<?php
    // Requiere: phpoffice/phpspreadsheet
    // composer require phpoffice/phpspreadsheet
    use PhpOffice\PhpSpreadsheet\IOFactory;

    require_once __DIR__ . '/../clases/InformeCierreCaja.php';
    require_once __DIR__ . '/../../vendor/autoload.php'; // ajusta la ruta según tu árbol

    class InformeCierreCajaDAO
    {
        private $conn;

        // Excel fijo según tu requerimiento
        private string $excelPath = 'E:\\Archivo_LG_Cierre_Caja.xlsx';
        private string $sheetName = 'IMPORTACION_ORACLE_LG';

        public function __construct($conn)
        {
            $this->conn = $conn;
            date_default_timezone_set('America/Lima');
        }

        public function setExcelSource(string $path, string $sheet = 'IMPORTACION_ORACLE_LG'): void
        {
            $this->excelPath = $path;
            $this->sheetName = $sheet;
        }

        // ========= Fuentes SQL =========

        /** Suma MON_POS del día */
        public function sumReportePOSHoy(?string $fechaISO = null): float
        {
            $fechaISO = $fechaISO ?: date('Y-m-d');
            $sql = "SELECT COALESCE(SUM(MON_POS),0) AS total
                    FROM REPORTE_POS
                    WHERE CAST(FECHA_REG_POS AS DATE) = ?";
            $st = sqlsrv_query($this->conn, $sql, [$fechaISO]);
            if (!$st) throw new RuntimeException('sumReportePOSHoy: '.print_r(sqlsrv_errors(), true));
            $r = sqlsrv_fetch_array($st, SQLSRV_FETCH_ASSOC);
            return (float)($r['total'] ?? 0);
        }

        /** Suma propinas del día (total y 0.95) */
        public function sumPropinaTarjetaHoy(?string $fechaISO = null): array
        {
            $fechaISO = $fechaISO ?: date('Y-m-d');
            $sql = "SELECT
                        COALESCE(SUM(MON_TARJETA),0)      AS total_prop,
                        COALESCE(SUM(DESC_MON_TARJETA),0) AS total_prop_095
                    FROM PROPINA_TARJETA
                    WHERE CAST(FECHA_REG_TARJETA AS DATE) = ?";
            $st = sqlsrv_query($this->conn, $sql, [$fechaISO]);
            if (!$st) throw new RuntimeException('sumPropinaTarjetaHoy: '.print_r(sqlsrv_errors(), true));
            $r = sqlsrv_fetch_array($st, SQLSRV_FETCH_ASSOC);
            return [
                'total_prop_tarjeta'  => (float)($r['total_prop'] ?? 0),
                'total_prop_tarj_095' => (float)($r['total_prop_095'] ?? 0),
            ];
        }

        /** ¿Existe un cierre para la fecha (global, sin importar usuario)? */
        public function existsCierrePorDia(string $fechaISO): bool
        {
            $sql = "SELECT 1 FROM INFORME_CIERRE_CAJA WHERE CAST(FECHA_REG_CAJA AS DATE) = ?";
            $st = sqlsrv_query($this->conn, $sql, [$fechaISO]);
            if (!$st) throw new RuntimeException('existsCierrePorDia: '.print_r(sqlsrv_errors(), true));
            return (bool)sqlsrv_fetch_array($st, SQLSRV_FETCH_NUMERIC);
        }

        // ========= Excel (estructura fija como tu imagen) =========

        /**
         * Lee la hoja IMPORTACION_ORACLE_LG:
         * Fila 1 = encabezados, Fila 2 = valores.
         * Encabezados esperados (case-insensitive):
         * Total Revenue | Tarjeta | Efectivo | Funcionario2 | Yape | Transferencia | Pago Cortesia | Cargos por servicio
         */
        public function leerMontosDesdeExcel(): array
        {
            if (!is_file($this->excelPath)) {
                throw new InvalidArgumentException("Excel no encontrado: {$this->excelPath}");
            }

            // IMPORTANTE: autoload ya debe estar cargado antes de llamar a este DAO
            $ss = \PhpOffice\PhpSpreadsheet\IOFactory::load($this->excelPath);
            $sh = $this->sheetName
                ? ($ss->getSheetByName($this->sheetName) ?: $ss->getSheet(0))
                : $ss->getSheet(0);

            // Si no hay hoja, error claro
            if (!$sh) {
                throw new RuntimeException("No se pudo abrir la hoja '{$this->sheetName}'");
            }

            $highestCol = $sh->getHighestColumn();
            $highestColIndex = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::columnIndexFromString($highestCol);

            $norm = function(string $s): string {
                $s = trim($s);
                $s = preg_replace('/\s+/u',' ', $s);
                $s = mb_strtoupper($s, 'UTF-8');
                $s = strtr($s, ['Á'=>'A','É'=>'E','Í'=>'I','Ó'=>'O','Ú'=>'U','Ü'=>'U','Ñ'=>'N']);
                return $s;
            };

            // Mapa encabezado -> clave de salida
            $map = [
                'TOTAL REVENUE'        => 'total_revenue',
                'TARJETA'              => 'tarjeta',
                'EFECTIVO'             => 'efectivo',
                'FUNCIONARIO2'         => 'funcionario',
                'YAPE'                 => 'yape',
                'TRANSFERENCIA'        => 'trasferencia',
                'TRASFERENCIA'         => 'trasferencia',
                'PAGO CORTESIA'        => 'pago_cortesia',
                'CARGOS POR SERVICIO'  => 'service_change',
            ];

            $out = [
                'total_revenue'  => 0.00,
                'pago_cortesia'  => 0.00,
                'service_change' => 0.00,
                'efectivo'       => 0.00,
                'funcionario'    => 0.00,
                'yape'           => 0.00,
                'trasferencia'   => 0.00,
                'tarjeta'        => 0.00,
            ];

            // Lee Fila 1 (encabezados) y Fila 2 (valores) usando letras de columna
            for ($c = 1; $c <= $highestColIndex; $c++) {
                $col = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($c);

                $hCell = $col . '1';
                $vCell = $col . '2';

                $h = (string) $sh->getCell($hCell)->getCalculatedValue();
                if ($h === '') continue;

                $hN = $norm($h);
                if (!isset($map[$hN])) continue;

                $v = $sh->getCell($vCell)->getCalculatedValue();
                if (is_numeric($v)) {
                    $out[$map[$hN]] = round((float)$v, 2);
                }
            }

            return $out;
        }


        // ========= Armar objeto y reglas =========

        /** Construye el cierre del día (sin guardar) fusionando SQL + Excel */
        public function buildCierreHoy(string $idUsuario, float $conteoFisicoCaja): InformeCierreCaja
        {
            $fechaISO = date('Y-m-d');

            $totalReportPos = $this->sumReportePOSHoy($fechaISO);
            $prop = $this->sumPropinaTarjetaHoy($fechaISO);
            $excel = $this->leerMontosDesdeExcel();

            $obj = new InformeCierreCaja(
                null, null,
                $totalReportPos,
                $prop['total_prop_tarjeta'],
                $prop['total_prop_tarj_095'],

                $excel['total_revenue'],
                $excel['pago_cortesia'],
                $excel['service_change'],
                $excel['efectivo'],
                $excel['funcionario'],
                $excel['yape'],
                $excel['trasferencia'], // coincide con col BD TRASFERENCIA (sin n)
                $excel['tarjeta'],

                $conteoFisicoCaja,
                null, null, null,
                null, null,
                null,
                $idUsuario
            );

            // Calcula métricas y validación en memoria
            $obj->recomputeReportTarjMenosPropTarj();
            $obj->recomputeEfectivo1();
            $obj->recomputeEfectivoSistemaFinal();
            $obj->aplicarValidacionCierre();

            return $obj;
        }

        // ========= Persistencia =========

        /** Inserta el cierre (bloquea duplicado global por día). Retorna ID_CIERRE_CAJA */
        public function insert(InformeCierreCaja $c): int
        {
            $fechaISO = date('Y-m-d');
            if ($this->existsCierrePorDia($fechaISO)) {
                throw new RuntimeException("Ya existe un cierre para {$fechaISO}. No se puede registrar otro.");
            }

            $sql = "INSERT INTO INFORME_CIERRE_CAJA
            (
                TOTAL_REPORT_POS, TOTAL_PROP_TARJETA, TOTAL_PROP_TARJ_095,
                TOTAL_REVENUE, PAGO_CORTESIA, SERVICE_CHANGE,
                EFECTIVO, FUNCIONARIO, YAPE, TRASFERENCIA, TARJETA,
                CONTEO_FISICO_CAJA, DINERO_SOBRANTE, DINERO_FALTANTE,
                OBSERVACIONES_CIERRE_CAJA, ID_USUARIO
            )
            OUTPUT INSERTED.ID_CIERRE_CAJA AS id
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";

            $params = [
                $c->getTotalReportPos(),
                $c->getTotalPropTarjeta(),
                $c->getTotalPropTarj095(),
                $c->getTotalRevenue(),
                $c->getPagoCortesia(),
                $c->getServiceChange(),
                $c->getEfectivo(),
                $c->getFuncionario(),
                $c->getYape(),
                $c->getTrasferencia(),   // en BD: TRASFERENCIA (sin n)
                $c->getTarjeta(),
                $c->getConteoFisicoCaja(),
                $c->getDineroSobrante(),
                $c->getDineroFaltante(),
                $c->getObservacionesCierreCaja(),
                $c->getIdUsuario(),
            ];

            $st = sqlsrv_query($this->conn, $sql, $params);
            if (!$st) {
                throw new RuntimeException('INSERT cierre falló: ' . print_r(sqlsrv_errors(), true));
            }

            $row = sqlsrv_fetch_array($st, SQLSRV_FETCH_ASSOC);
            if (!$row || !isset($row['id'])) {
                throw new RuntimeException('INSERT ok pero no devolvió ID (OUTPUT).');
            }
            return (int)$row['id'];
        }


        /** (Opcional) Listar por rango de fechas */
        public function listByDateRange(string $desdeISO, string $hastaISO): array
        {
            $sql = "SELECT * FROM INFORME_CIERRE_CAJA
                    WHERE CAST(FECHA_REG_CAJA AS DATE) BETWEEN ? AND ?
                    ORDER BY FECHA_REG_CAJA DESC, ID_CIERRE_CAJA DESC";
            $st = sqlsrv_query($this->conn, $sql, [$desdeISO, $hastaISO]);
            if (!$st) throw new RuntimeException('listByDateRange: '.print_r(sqlsrv_errors(), true));
            $out = [];
            while ($row = sqlsrv_fetch_array($st, SQLSRV_FETCH_ASSOC)) $out[] = $row;
            return $out;
        }
    }
?>