<?php
session_start();
$host = 'localhost';
$database = 'C:\Program Files (x86)\Common Files\Aspel\Sistemas Aspel\SAE7.00\Ejemplos\Ejemplos.fdb';
$username = 'SYSDBA';
$password = 'masterkey';
setlocale(LC_MONETARY, 'es_MX');

if ($_SERVER["REQUEST_METHOD"] == "POST") {

    try {
        $dbh = new PDO("firebird:host=$host;dbname=$database;charset=UTF8", $username, $password);
        $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        error_log(print_r($_POST, true));

        //campos que ocupo en variable
        $comision = $_POST['comision'] ?? '';
        $costo_unidad = $_POST['costo_unidad'];

        $descuentofinal = $_POST['descuentofinal'] ?? '0';

        // Obtener el valor de cveDoc (número con serie)
        $folioCompleto = $_POST['cveDoc'];
        $serie = preg_replace('/\d+/', '', $folioCompleto);
        $numero = (int)filter_var($folioCompleto, FILTER_SANITIZE_NUMBER_INT);
        $cveDoc = $_POST['cveDoc'];

        $sql_update = "UPDATE FOLIOSF01 SET ULT_DOC = :new_number WHERE TIP_DOC = 'C' AND SERIE = :serie";
        $stmt_update = $dbh->prepare($sql_update);
        $stmt_update->execute([':new_number' => $numero, ':serie' => $serie]);

        // Ver la cantidad total de los productos General
        $canTot = 0;
        foreach ($_POST['productos'] as $producto) {
            $canTot += $producto['subtotal_partida'];
        }

        // Obtiene el esquema de el formulario
        $esquema2 = $_POST['esquema2'] ?? '';
        // Fecha de elaboracion COMPC01
        $fechaElaboracion = DateTime::createFromFormat('U.u', microtime(true))->format('Y-m-d H:i:s.v');

        // Obtener folios siguiente
        $stmtFol = $dbh->query("SELECT FOLIO FROM FACTC01");
        $folios = $stmtFol->fetchAll(PDO::FETCH_COLUMN);
        $numeric_folios = [];
        foreach ($folios as $folio) {
            $folio_limpia = preg_replace('/[^0-9]/', '', $folio);
            if (is_numeric($folio_limpia)) {
                $numeric_folios[] = intval($folio_limpia);
            }
        }
        $last_folio = !empty($numeric_folios) ? max($numeric_folios) : 0;
        $new_folio = $last_folio + 1;

        // tipo de moneda en FACTC01
        $sqlMoneda = "SELECT NUM_MONED FROM FACTC01 WHERE CVE_DOC = :cveDoc";
        $stmtMoneda = $dbh->prepare($sqlMoneda);
        $stmtMoneda->bindParam(':cveDoc', $cveDoc);
        $stmtMoneda->execute();
        $moneda = $stmtMoneda->fetch(PDO::FETCH_ASSOC)['NUM_MONED'] ?? null;

        // Tipo de Almacen en FACTC01
        $sqlInv = "SELECT NUM_ALMA FROM FACTC01 WHERE CVE_DOC = :cveDoc";
        $stmtInv = $dbh->prepare($sqlInv);
        $stmtInv->bindParam(':cveDoc', $cveDoc);
        $stmtInv->execute();
        $Inv = $stmtInv->fetch(PDO::FETCH_ASSOC)['NUM_ALMA'] ?? null;

        // OBS_DOC01 En general
        $observacion = $_POST['observaciones_hidden'];
        // Obtener la observación general y las observaciones de los productos
        $stmtObs = $dbh->query("SELECT MAX(CVE_OBS) AS LAST_OBS FROM OBS_DOCF01");
        $lastObs = $stmtObs->fetch(PDO::FETCH_ASSOC)['LAST_OBS'] ?? 0;
        $newObs = $lastObs + 1;
        $sqlObs = "INSERT INTO OBS_DOCF01 (CVE_OBS, STR_OBS) VALUES (:cve_obs, :str_obs)";
        $stmtObsInsert = $dbh->prepare($sqlObs);
        $cveObs = $cveObs ?? 0;
        // Insertar las observaciones generales (si existen)
        if (!empty($_POST['observaciones_hidden'])) {
            $stmtObsInsert->execute([
                ':cve_obs' => $newObs,
                ':str_obs' => $_POST['observaciones_hidden']
            ]);
            $cveObsGEN = $newObs;
            $newObs++; // Incrementar para la siguiente observación
        }

        if (strpos($cveDoc, 'STAND') !== false) {
            $autoriza = 1;
        } else {
            $autoriza = 0;
        }

        $seriedefolio = preg_replace('/[^A-Za-z]/', '', $cveDoc);
        $soloNumeros = preg_replace('/\D/', '', $cveDoc); // Elimina todo lo que no sea dígito
        $serieserie = ltrim($soloNumeros, '0');

        $sql = "INSERT INTO FACTC01 (
            TIP_DOC, CVE_DOC, CVE_CLPV, STATUS, CVE_PEDI,
            FECHA_DOC, FECHA_ENT, FECHA_VEN, COM_TOT, NUM_MONED,
            TIPCAMB, RFC, FOLIO, NUM_ALMA, CONDICION,
            FECHAELAB, NUM_PAGOS, CONTADO, PRIMERPAGO, AUTOANIO,
            ESCFD, IMP_TOT1, IMP_TOT2, IMP_TOT3, IMP_TOT4,
            SERIE, AUTORIZA, CVE_VEND, BLOQ, CTLPOL,
            CVE_OBS, COM_TOT_PORC, TIP_DOC_ANT, DOC_ANT, DAT_MOSTR,
            DES_FIN, DES_FIN_PORC, CAN_TOT, DES_TOT, IMPORTE,
            DES_TOT_PORC
        ) VALUES (
            'C', :cveDoc, :cveClpv, 'E', '',
            :fechaDoc, :fechaEnt, :fechaVen, :comTot, :numMoned,
            :tipCamb, :rfc, :folio, :numAlma, :condicion,
            :fechaElab, '1', 'N', '0', '',
            'N', '0', '0', '0', :impTot4,
            :serie, :autoriza, :cveVend, 'N', '0',
            :cveObs, :comTotPorc, '', '', '0',
            :descuentofinal , '0', :canTot, :desTot, :importe,
            :desTotPorc
        )";

        $stmt = $dbh->prepare($sql);
        $stmt->bindParam(':cveDoc',  $cveDoc);
        $stmt->bindParam(':cveClpv', $_POST['cliente']);
        $stmt->bindParam(':fechaDoc', $_POST['fechaDoc']);
        $stmt->bindParam(':fechaEnt', $_POST['fechaRec']);
        $stmt->bindParam(':fechaVen', $_POST['fechaVenc']);
        $stmt->bindParam(':comTot', $_POST['comision']);
        $stmt->bindParam(':numMoned', $_POST['moneda']);
        $stmt->bindParam(':tipCamb', $_POST['tcambio']);
        $stmt->bindParam(':rfc', $_POST['rfc']);
        
        $stmt->bindParam(':folio', $serieserie);
        $stmt->bindParam(':numAlma', $_POST['almacen']);
        $stmt->bindParam(':condicion', $_POST['condicion']);    
        $stmt->bindParam(':fechaElab', date('Y-m-d H:i:s'));
        $stmt->bindParam(':impTot4', $_POST['imp_tot4']);
        $stmt->bindParam(':serie', $seriedefolio);
        $stmt->bindParam(':autoriza', $autoriza);
        $stmt->bindParam(':cveVend', $_POST['vendedor']) ?? '';
        $stmt->bindParam(':cveObs', $cveObsGEN);
        $stmt->bindParam(':comTotPorc', $comision);
        $stmt->bindParam(':canTot', $canTot);
        $stmt->bindParam(':desTot', $descuentototal);
        $stmt->bindParam(':importe', $importe);
        $stmt->bindParam(':desTotPorc', $_POST['descuento']);
        $stmt->bindParam(':descuentofinal', $descuentofinal);
        $stmt->execute();

        // Inserción separada de los campos libres del documento
        if (isset($_POST['campos_libres']) && is_array($_POST['campos_libres'])) {
            $campos_libres = $_POST['campos_libres'];

            // Filtrar campos vacíos si deseas evitar que se inserten como NULL
            // $campos_libres = array_filter($campos_libres, fn($v) => trim($v) !== '');

            if (!empty($campos_libres)) {
                $campos_nombres = implode(", ", array_keys($campos_libres));
                $campos_placeholders = implode(", ", array_map(fn($c) => ":$c", array_keys($campos_libres)));

                $sql_clib = "INSERT INTO FACTC_CLIB01 (CLAVE_DOC, $campos_nombres) VALUES (:cveDoc, $campos_placeholders)";
                $stmt_clib = $dbh->prepare($sql_clib);
                $stmt_clib->bindValue(':cveDoc', $cveDoc);

                foreach ($campos_libres as $campo => $valor) {
                    $valor = trim($valor);
                    if ($valor === "") {
                        $stmt_clib->bindValue(":$campo", null, PDO::PARAM_NULL);
                    } else {
                        $stmt_clib->bindValue(":$campo", $valor);
                    }
                }

                $stmt_clib->execute();
            } else {
                // Si no hay valores, solo insertamos el CLAVE_DOC
                $sql_clib = "INSERT INTO FACTC_CLIB01 (CLAVE_DOC) VALUES (:cveDoc)";
                $stmt_clib = $dbh->prepare($sql_clib);
                $stmt_clib->bindValue(':cveDoc', $cveDoc);
                $stmt_clib->execute();
            }

            // OBS_DOC01 Por cada partida 
        $stmtObs = $dbh->query("SELECT MAX(CVE_OBS) AS LAST_OBS FROM OBS_DOCF01");
        $lastObs = $stmtObs->fetch(PDO::FETCH_ASSOC)['LAST_OBS'] ?? 0;
        $newObs = $lastObs + 1;
        $sqlObs = "INSERT INTO OBS_DOCF01 (CVE_OBS, STR_OBS) VALUES (:cve_obs, :str_obs)";
        $stmtObsInsert = $dbh->prepare($sqlObs);
        $observacionesPorProducto = [];

foreach ($_POST['productos'] as $index => $producto) {
    if (!empty(trim($producto['observaciones']))) {
        // Insertar la observación en OBS_DOCF01
        $stmtObsInsert->execute([
            ':cve_obs' => $newObs,
            ':str_obs' => $producto['observaciones'],
        ]);

        // Guardar la clave generada para ese producto
        $observacionesPorProducto[$index] = $newObs;

        // Incrementar para el siguiente
        $newObs++;
    }
}

        }

        // Obtener TIPO_ELE y COSTO_PROM del producto
        $sqlDatosProducto = "SELECT TIPO_ELE, COSTO_PROM FROM INVE01 WHERE CVE_ART = :cveArt";
        $stmtDatosProducto = $dbh->prepare($sqlDatosProducto);
        $stmtDatosProducto->bindParam(':cveArt', $producto['producto']);
        $stmtDatosProducto->execute();
        $datosProducto = $stmtDatosProducto->fetch(PDO::FETCH_ASSOC);

        // Asignar a variables
        $tipoElem = $datosProducto['TIPO_ELE'] ?? null;
        $cost = $datosProducto['COSTO_PROM'] ?? 0;

        // Impuestos a plazos segun el Esquema de Impuestos (PAR_FACTC01)
        $sqlimpu = "SELECT IMP1APLICA, IMP2APLICA, IMP3APLICA, IMP4APLICA FROM IMPU01 WHERE CVE_ESQIMPU = ?";
        $stmtimpu = $dbh->prepare($sqlimpu);
        $stmtimpu->execute([$esquema2]);
        $resultado = $stmtimpu->fetch(PDO::FETCH_ASSOC);

        if ($resultado) {
            $imp1Apla = $resultado['IMP1APLICA'];
            $imp2Apla = $resultado['IMP2APLICA'];
            $imp3Apla = $resultado['IMP3APLICA'];
            $imp4Apla = $resultado['IMP4APLICA'];
        } else {
            $imp1Apla = 0;
            $imp2Apla = 0;
            $imp3Apla = 0;
            $imp4Apla = 0;
        }

        // Total de Impuestos en las Partidas si no hay datos
        $totalImpuesto1 = 0;
        $totalImpuesto2 = 0;
        $totalImpuesto3 = 0;
        $totalImpuesto4 = 0;
        $totalDescuento = 0;
        $totalimporte = 0;
        

        // Inicio de Insertacion de datos en PAR_FACTC01
        $sqlPartida = "INSERT INTO PAR_FACTC01 (
            CVE_DOC, NUM_PAR, CANT, PXS, CVE_ART, PREC, 
            COMI, NUM_ALM, TIP_CAM, UNI_VENTA, TIPO_PROD, CVE_OBS, 
            IMPU1, IMPU2, IMPU3, IMPU4, IMP1APLA, IMP2APLA, IMP3APLA, IMP4APLA, 
            TOTIMP1, TOTIMP2, TOTIMP3, TOTIMP4, 
            DESC1, DESC2, DESC3, 
            APAR, ACT_INV, POLIT_APLI, REG_SERIE, E_LTPD, TIPO_ELEM, NUM_MOV, 
            IMPRIMIR, MAN_IEPS, APL_MAN_IMP, CUOTA_IEPS, APL_MAN_IEPS, 
            MTO_PORC, MTO_CUOTA, CVE_ESQ, DESCR_ART, 
            TOT_PARTIDA, COST
        ) VALUES (
            :cveDoc, :numPar, :cant, :pxs, :cveArt, :prec, 
            :comision, :numAlm, :tipCam, :uniVenta, :tipoProd, :cveObs, 
            :ieps, :ret_isr, :ret_iva, :iva, :imp1Apla, :imp2Apla, :imp3Apla, :imp4Apla,
            :totImp1, :totImp2, :totImp3, :totImp4,
            :descuento, '0', '0', 
            '0', 'N', '', '0', '0', 'N', '0', 
            'S', 'N', '1', '0', 'C', 
            '0', '0', :cveEsq, :descrArt, 
            :totPartida, :cost
        )";

        $stmtPartida = $dbh->prepare($sqlPartida);
        foreach ($_POST['productos'] as $index => $producto) {
            $numPar = $index + 1;

             // Tomar la observación asociada si existe, si no, usar 0
    $cveObs = isset($observacionesPorProducto[$index]) ? $observacionesPorProducto[$index] : 0;


            $porcentajeIeps = $producto['ieps'] / 100;
            $porcentajeRetIsr = $producto['ret_isr'] / 100;
            $porcentajeRetIva = $producto['ret_iva'] / 100;
            $porcentajeIva = $producto['iva'] / 100;
            $porcentajeDescuento = $producto['descuento'] / 100;
            $porcentajeDescuentoFin = $descuentofinal / 100;

            // 1. Subtotal sin descuentos
            $subtotalSinDescuentos = $producto['subtotal_partida'];

            // 2. Descuento normal
            $descuentoCalculado = $subtotalSinDescuentos * $porcentajeDescuento;
            $subtotalConDescuento = $subtotalSinDescuentos - $descuentoCalculado;

            // 3. Descuento financiero sobre subtotal con descuento
            $descuentoFinancieroCalculado = $subtotalConDescuento * $porcentajeDescuentoFin;
            $subtotalFinalAntesImpuestos = $subtotalConDescuento - $descuentoFinancieroCalculado;

            // COST_DEV = subtotal con descuento normal
            $cost_dev = $subtotalConDescuento;

            // 4. Impuestos aplicados al final
            $totImp1 = $subtotalFinalAntesImpuestos * $porcentajeIeps;
            $totImp2 = $subtotalFinalAntesImpuestos * $porcentajeRetIsr;
            $totImp3 = $subtotalFinalAntesImpuestos * $porcentajeRetIva;
            $totImp4 = $subtotalFinalAntesImpuestos * $porcentajeIva;

            // 5. Total final de la partida
            $totalPartidaFinal = $subtotalFinalAntesImpuestos + $totImp1 + $totImp2 + $totImp3 + $totImp4;

            // 6. Acumuladores
            $totalImpuesto1 += $totImp1;
            $totalImpuesto2 += $totImp2;
            $totalImpuesto3 += $totImp3;
            $totalImpuesto4 += $totImp4;
            $totalDescuento += $descuentoCalculado;
            $totalDescuentoFinanciero += $descuentoFinancieroCalculado;
            $totalimporte += $totalPartidaFinal;

            $stmtPartida->bindParam(':cveDoc',  $cveDoc);
            $stmtPartida->bindParam(':numPar', $numPar);
            $stmtPartida->bindParam(':cant', $producto['cantidad']);
            $stmtPartida->bindParam(':pxs', $producto['cantidad']);
            $stmtPartida->bindParam(':cveArt', $producto['producto']);
            $stmtPartida->bindParam(':prec', $producto['costo_unidad']);
            $stmtPartida->bindParam(':comision', $comision);
            $stmtPartida->bindParam(':uniVenta', $producto['unidad']);
            $stmtPartida->bindParam(':tipoProd', $tipoElem);
            $stmtPartida->bindParam(':cveObs', $cveObs);

            $stmtPartida->bindParam(':ieps', $producto['ieps']);
            $stmtPartida->bindParam(':ret_isr', $producto['ret_isr']);
            $stmtPartida->bindParam(':ret_iva', $producto['ret_iva']);
            $stmtPartida->bindParam(':iva', $producto['iva']);
            $stmtPartida->bindParam(':imp1Apla', $imp1Apla);
            $stmtPartida->bindParam(':imp2Apla', $imp2Apla);
            $stmtPartida->bindParam(':imp3Apla', $imp3Apla);
            $stmtPartida->bindParam(':imp4Apla', $imp4Apla);
            $stmtPartida->bindParam(':totImp1', $totImp1);
            $stmtPartida->bindParam(':totImp2', $totImp2);
            $stmtPartida->bindParam(':totImp3', $totImp3);
            $stmtPartida->bindParam(':totImp4', $totImp4);
            $stmtPartida->bindParam(':tipCam', $_POST['tcambio']);
            $stmtPartida->bindParam(':numAlm', $_POST['almacen']);
            $stmtPartida->bindParam(':descuento', $producto['descuento']);
            
            $stmtPartida->bindParam(':cveEsq', $_POST['esquema2']);
            $stmtPartida->bindParam(':descrArt', $producto['descripcion']);
            $stmtPartida->bindParam(':totPartida', $producto['subtotal_partida']);
            $stmtPartida->bindParam(':cost', $cost);
            $stmtPartida->execute();


            if (isset($producto['campos_libres']) && is_array($producto['campos_libres'])) {
                $campos = $producto['campos_libres'];
                $campos_nombres = implode(", ", array_keys($campos));
                $campos_placeholders = implode(", ", array_map(fn($c) => ":$c", array_keys($campos)));

                $sql_clib = "INSERT INTO PAR_FACTC_CLIB01 (CLAVE_DOC, NUM_PART, $campos_nombres)
                         VALUES (:cveDoc, :numPar, $campos_placeholders)";

                $stmt_clib = $dbh->prepare($sql_clib);
                $stmt_clib->bindValue(':cveDoc', $cveDoc);
                $stmt_clib->bindValue(':numPar', $index + 1);

                foreach ($campos as $campo => $valor) {
                    $valor = trim($valor);
                    $stmt_clib->bindValue(":$campo", $valor === "" ? null : $valor);
                }

                $stmt_clib->execute();
            }
        }

        /*  Actualizar la columna IMPORTE en FACTC01 */
        $sqlUpdate = "UPDATE FACTC01 SET 
        IMP_TOT1 = :totalImpuesto1,
        IMP_TOT2 = :totalImpuesto2,
        IMP_TOT3 = :totalImpuesto3,
        IMP_TOT4 = :totalImpuesto4,
        DES_TOT = :totalDescuento,
        DES_FIN = :descuentofinal,
        IMPORTE = :totalimporte
        WHERE CVE_DOC = :cveDoc";
        $stmtUpdate = $dbh->prepare($sqlUpdate);
        $stmtUpdate->bindParam(':totalImpuesto1', $totalImpuesto1);
        $stmtUpdate->bindParam(':totalImpuesto2', $totalImpuesto2);
        $stmtUpdate->bindParam(':totalImpuesto3', $totalImpuesto3);
        $stmtUpdate->bindParam(':totalImpuesto4', $totalImpuesto4);
        $stmtUpdate->bindParam(':totalDescuento', $descuentoCalculado);
        $stmtUpdate->bindParam(':descuentofinal', $descuentoFinancieroCalculado ?? '0');
        $stmtUpdate->bindParam(':totalimporte', $totalimporte);
        $stmtUpdate->bindParam(':cveDoc', $cveDoc);
        $stmtUpdate->execute();

        echo json_encode([
            'success' => true,
            'message' => 'Los datos se guardaron correctamente.'
        ]);
    } catch (PDOException $e) {
        http_response_code(500);
        echo json_encode([
            'success' => false,
            'message' => 'Error de base de datos: ' . $e->getMessage()
        ]);
    } catch (Exception $e) {
        http_response_code(500);
        echo json_encode([
            'success' => false,
            'message' => 'Error general: ' . $e->getMessage()
        ]);
    }
}
