<?php
header('Content-Type: application/json; charset=utf-8');
require_once __DIR__ . '/db.php';

$action = isset($_GET['action']) ? $_GET['action'] : (isset($_POST['action']) ? $_POST['action'] : '');

try {
    $pdo = getConnection();

    if ($_SERVER['REQUEST_METHOD'] === 'GET' || $action === 'list') {
        // --- BUSCAR / LISTAR PRODUCTOS ---
        $query = isset($_GET['query']) ? trim($_GET['query']) : '';
        $page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
        $limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 50;
        $offset = ($page - 1) * $limit;

        $lugar_compra_id = isset($_GET['lugar_compra_id']) ? (int)$_GET['lugar_compra_id'] : 0;
        $laboratorio = isset($_GET['laboratorio']) ? trim($_GET['laboratorio']) : '';
        $sincronizado = isset($_GET['sincronizado']) ? trim($_GET['sincronizado']) : '';
        $sort_codigo = isset($_GET['sort_codigo']) ? trim($_GET['sort_codigo']) : '';

        $whereTerms = ["1=1"];
        $params = [];

        if ($query !== '') {
            // Dividir la búsqueda por palabras para coincidencias más inteligentes y potentes
            $words = array_filter(explode(' ', $query), function($w) {
                return strlen(trim($w)) >= 1;
            });

            if (!empty($words)) {
                $queryTerms = [];
                foreach ($words as $index => $word) {
                    $paramCommercial = ":word_" . $index . "_comm";
                    $paramGeneric = ":word_" . $index . "_gen";
                    $paramLab = ":word_" . $index . "_lab";
                    $paramIntCode = ":word_" . $index . "_int";
                    $paramBarCode = ":word_" . $index . "_bar";
                    $paramFunc = ":word_" . $index . "_func";
                    
                    $queryTerms[] = "(p.NombreComercial LIKE $paramCommercial 
                                     OR p.NombreGenerico LIKE $paramGeneric 
                                     OR p.laboratorio LIKE $paramLab 
                                     OR p.CodigoInterno LIKE $paramIntCode 
                                     OR p.CodigoBarra LIKE $paramBarCode 
                                     OR p.FuncionMedica LIKE $paramFunc)";
                                     
                    $val = '%' . $word . '%';
                    $params[$paramCommercial] = $val;
                    $params[$paramGeneric] = $val;
                    $params[$paramLab] = $val;
                    $params[$paramIntCode] = $val;
                    $params[$paramBarCode] = $val;
                    $params[$paramFunc] = $val;
                }
                $whereTerms[] = "(" . implode(' AND ', $queryTerms) . ")";
            }
        }

        if ($lugar_compra_id > 0) {
            $whereTerms[] = "p.id IN (SELECT DISTINCT producto_id FROM producto_lugares_compra WHERE lugar_compra_id = :lugar_compra_id AND activo = 1)";
            $params[':lugar_compra_id'] = $lugar_compra_id;
        }

        if ($laboratorio !== '') {
            $whereTerms[] = "p.laboratorio = :laboratorio";
            $params[':laboratorio'] = $laboratorio;
        }

        if ($sincronizado === 'sinc') {
            $whereTerms[] = "(SELECT COUNT(*) FROM fel_producto_mapping WHERE producto_id = p.id) > 0";
        } elseif ($sincronizado === 'nosinc') {
            $whereTerms[] = "(SELECT COUNT(*) FROM fel_producto_mapping WHERE producto_id = p.id) = 0";
        }

        $whereClause = implode(' AND ', $whereTerms);

        $orderByClause = "p.id DESC";
        if ($sort_codigo === 'asc') {
            $orderByClause = "p.CodigoInterno ASC";
        } elseif ($sort_codigo === 'desc') {
            $orderByClause = "p.CodigoInterno DESC";
        } elseif ($query !== '') {
            $exactMatchQuery = $pdo->quote($query);
            $startsWithQuery = $pdo->quote($query . '%');
            $orderByClause = "
                (p.NombreComercial = $exactMatchQuery) DESC,
                (p.NombreComercial LIKE $startsWithQuery) DESC,
                (p.CodigoInterno = $exactMatchQuery) DESC,
                (p.CodigoBarra = $exactMatchQuery) DESC,
                p.id DESC
            ";
        }

        // Obtener el total para paginación
        $countSql = "SELECT COUNT(*) FROM productos p WHERE $whereClause";
        $countStmt = $pdo->prepare($countSql);
        $countStmt->execute($params);
        $totalItems = (int)$countStmt->fetchColumn();

        // Obtener los productos con el costo promedio ponderado y mapeo fel
        $sql = "SELECT p.*, 
                       COALESCE(pcp.costo_promedio_unidad_base, 0) as costo_promedio,
                       (SELECT COUNT(*) FROM fel_producto_mapping WHERE producto_id = p.id) > 0 as tiene_mapeo
                FROM productos p
                LEFT JOIN productos_costo_promedio pcp ON p.id = pcp.producto_id
                WHERE $whereClause
                ORDER BY $orderByClause
                LIMIT :limit OFFSET :offset";

        $stmt = $pdo->prepare($sql);
        foreach ($params as $key => $val) {
            $stmt->bindValue($key, $val);
        }
        $stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
        $stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
        $stmt->execute();
        $productos = $stmt->fetchAll(PDO::FETCH_ASSOC);

        // Para cada producto, adjuntar presentaciones y lugares de compra
        foreach ($productos as &$p) {
            $pId = $p['id'];

            // 1. Obtener todas las presentaciones configuradas para este producto
            $presStmt = $pdo->prepare("SELECT pp.*, pr.nombre as presentacion_nombre 
                                       FROM producto_presentaciones pp
                                       JOIN presentaciones pr ON pp.presentacion_id = pr.id
                                       WHERE pp.producto_id = :pId
                                       ORDER BY pp.orden ASC, pp.presentacion_id ASC");
            $presStmt->execute([':pId' => $pId]);
            $p['presentaciones'] = $presStmt->fetchAll(PDO::FETCH_ASSOC);

            // 2. Obtener lugares de compra vinculados
            $lugarStmt = $pdo->prepare("SELECT plc.*, lc.nombre as lugar_nombre 
                                        FROM producto_lugares_compra plc
                                        JOIN lugarcompra lc ON plc.lugar_compra_id = lc.id
                                        WHERE plc.producto_id = :pId AND plc.activo = 1
                                        ORDER BY plc.fecha_ultima_compra DESC, plc.id DESC");
            $lugarStmt->execute([':pId' => $pId]);
            $p['lugares_compra'] = $lugarStmt->fetchAll(PDO::FETCH_ASSOC);

            // 3. Extraer última compra para columna 6
            if (!empty($p['lugares_compra'])) {
                $p['ultimo_lugar_compra'] = $p['lugares_compra'][0]['lugar_nombre'];
                $p['ultima_fecha_compra'] = $p['lugares_compra'][0]['fecha_ultima_compra'];
            } else {
                $p['ultimo_lugar_compra'] = null;
                $p['ultima_fecha_compra'] = null;
            }
        }

        echo json_encode([
            'success' => true,
            'productos' => $productos,
            'total' => $totalItems,
            'page' => $page,
            'limit' => $limit,
            'pages' => ceil($totalItems / $limit)
        ]);



    } elseif ($action === 'toggle_estado') {
        // --- HABILITAR / DESHABILITAR PRODUCTO ---
        $data = json_decode(file_get_contents('php://input'), true);
        $productoId = isset($data['producto_id']) ? (int)$data['producto_id'] : 0;
        $estado = isset($data['estado']) ? (int)$data['estado'] : 0;

        if (!$productoId) {
            throw new Exception("ID de producto no proporcionado");
        }

        $stmt = $pdo->prepare("UPDATE productos SET estado = :estado WHERE id = :id");
        $stmt->execute([':estado' => $estado, ':id' => $productoId]);

        echo json_encode([
            'success' => true,
            'message' => 'Estado del producto actualizado correctamente',
            'estado' => $estado
        ]);

    } elseif ($action === 'save_product_details') {
        // --- GUARDAR DETALLES COMPLETOS DE PRODUCTO ---
        $data = json_decode(file_get_contents('php://input'), true);
        $productoId = isset($data['producto_id']) ? (int)$data['producto_id'] : 0;
        $exentoIva = isset($data['exento_iva']) ? (int)$data['exento_iva'] : 0;
        $costoPromedio = isset($data['costo_promedio']) ? (float)$data['costo_promedio'] : 0.0;
        $presentaciones = isset($data['presentaciones']) ? $data['presentaciones'] : [];

        if (!$productoId) {
            throw new Exception("ID de producto no proporcionado");
        }

        $pdo->beginTransaction();

        // 1. Actualizar exención de IVA en la tabla productos
        $updProduct = $pdo->prepare("UPDATE productos SET exento_iva = :exento WHERE id = :id");
        $updProduct->execute([':exento' => $exentoIva, ':id' => $productoId]);

        // 2. Guardar/Actualizar Costo Promedio Ponderado
        $checkCpp = $pdo->prepare("SELECT id FROM productos_costo_promedio WHERE producto_id = :pId");
        $checkCpp->execute([':pId' => $productoId]);
        if ($checkCpp->rowCount() > 0) {
            $updCpp = $pdo->prepare("UPDATE productos_costo_promedio 
                                     SET costo_promedio_unidad_base = :costo, fecha_ultimo_calculo = NOW() 
                                     WHERE producto_id = :pId");
            $updCpp->execute([':costo' => $costoPromedio, ':pId' => $productoId]);
        } else {
            $insCpp = $pdo->prepare("INSERT INTO productos_costo_promedio 
                                     (producto_id, costo_promedio_unidad_base, cantidad_total_unidades, valor_total_inventario, fecha_ultimo_calculo) 
                                     VALUES (:pId, :costo, 0, 0.0, NOW())");
            $insCpp->execute([':pId' => $productoId, ':costo' => $costoPromedio]);
        }

        // 3. Procesar las presentaciones (Máximo 4 slots)
        // El primer elemento (índice 0) del array de presentaciones es siempre la base
        $basePres = $presentaciones[0] ?? [
            'presentacion_id' => 1,
            'factor_conversion' => 1,
            'activo' => 1,
            'precio_venta' => 0.0,
            'margen_ganancia_porcentaje' => 30.0
        ];

        $basePresId = intval($basePres['presentacion_id']);
        $baseActivo = intval($basePres['activo']);
        $basePrecio = floatval($basePres['precio_venta']);
        $baseMargen = floatval($basePres['margen_ganancia_porcentaje']);

        // Reset base unit flags first
        $clearBaseFlag = $pdo->prepare("UPDATE producto_presentaciones SET es_unidad_base = 0 WHERE producto_id = :pId");
        $clearBaseFlag->execute([':pId' => $productoId]);

        // Desactivar primero todas las presentaciones que no sean la base seleccionada
        $deactivate = $pdo->prepare("UPDATE producto_presentaciones SET activo = 0 WHERE producto_id = :pId AND presentacion_id != :basePresId");
        $deactivate->execute([':pId' => $productoId, ':basePresId' => $basePresId]);

        // Asegurar que la presentación base exista y tenga el estado enviado
        $checkBase = $pdo->prepare("SELECT id FROM producto_presentaciones WHERE producto_id = :pId AND presentacion_id = :basePresId");
        $checkBase->execute([':pId' => $productoId, ':basePresId' => $basePresId]);

        if ($checkBase->rowCount() > 0) {
            $updBase = $pdo->prepare("UPDATE producto_presentaciones 
                                      SET factor_conversion = 1, activo = :activo, es_unidad_base = 1, 
                                          precio_venta = :precio, margen_ganancia_porcentaje = :margen, 
                                          fecha_actualizacion = NOW() 
                                      WHERE producto_id = :pId AND presentacion_id = :basePresId");
            $updBase->execute([
                ':activo' => $baseActivo,
                ':precio' => $basePrecio,
                ':margen' => $baseMargen,
                ':pId' => $productoId,
                ':basePresId' => $basePresId
            ]);
        } else {
            $insBase = $pdo->prepare("INSERT INTO producto_presentaciones 
                                      (producto_id, presentacion_id, factor_conversion, activo, es_unidad_base, orden, precio_venta, margen_ganancia_porcentaje, es_facturable, es_comprable, es_vendible, fecha_creacion) 
                                      VALUES (:pId, :basePresId, 1, :activo, 1, 1, :precio, :margen, 1, 1, 1, NOW())");
            $insBase->execute([
                ':pId' => $productoId,
                ':basePresId' => $basePresId,
                ':activo' => $baseActivo,
                ':precio' => $basePrecio,
                ':margen' => $baseMargen
            ]);
        }

        // Insertar o actualizar las otras presentaciones
        $orden = 2;
        foreach ($presentaciones as $idx => $pres) {
            if ($idx === 0) continue; // Ya procesada la base

            $presId = (int)$pres['presentacion_id'];
            if ($presId === $basePresId) continue;

            $factor = (int)$pres['factor_conversion'];
            $activo = (int)$pres['activo'];
            $precio = (float)$pres['precio_venta'];
            $margen = (float)$pres['margen_ganancia_porcentaje'];

            if ($factor <= 0) $factor = 1;

            $checkEx = $pdo->prepare("SELECT id FROM producto_presentaciones WHERE producto_id = :pId AND presentacion_id = :presId");
            $checkEx->execute([':pId' => $productoId, ':presId' => $presId]);

            if ($checkEx->rowCount() > 0) {
                $updPres = $pdo->prepare("UPDATE producto_presentaciones 
                                          SET factor_conversion = :factor, activo = :activo, 
                                              precio_venta = :precio, margen_ganancia_porcentaje = :margen, 
                                              orden = :orden, fecha_actualizacion = NOW() 
                                          WHERE producto_id = :pId AND presentacion_id = :presId");
                $updPres->execute([
                    ':factor' => $factor,
                    ':activo' => $activo,
                    ':precio' => $precio,
                    ':margen' => $margen,
                    ':orden' => $orden,
                    ':pId' => $productoId,
                    ':presId' => $presId
                ]);
            } else {
                $insPres = $pdo->prepare("INSERT INTO producto_presentaciones 
                                          (producto_id, presentacion_id, factor_conversion, activo, es_unidad_base, orden, precio_venta, margen_ganancia_porcentaje, es_facturable, es_comprable, es_vendible, fecha_creacion) 
                                          VALUES (:pId, :presId, :factor, :activo, 0, :orden, :precio, :margen, 1, 1, 1, NOW())");
                $insPres->execute([
                    ':pId' => $productoId,
                    ':presId' => $presId,
                    ':factor' => $factor,
                    ':activo' => $activo,
                    ':precio' => $precio,
                    ':margen' => $margen,
                    ':orden' => $orden
                ]);
            }
            $orden++;
        }

        $pdo->commit();
        echo json_encode([
            'success' => true,
            'message' => 'Detalles del producto y presentaciones actualizados correctamente'
        ]);

    } elseif ($action === 'delete_product') {
        // --- ELIMINAR PRODUCTO ATÓMICAMENTE ---
        $data = json_decode(file_get_contents('php://input'), true);
        $productoId = isset($data['producto_id']) ? (int)$data['producto_id'] : 0;

        if (!$productoId) {
            throw new Exception("ID de producto no proporcionado");
        }

        $pdo->beginTransaction();

        // 1. Eliminar relaciones secundarias
        $tablesToDelete = [
            'producto_presentaciones' => 'producto_id',
            'producto_lugares_compra' => 'producto_id',
            'productos_costo_promedio' => 'producto_id',
            'fel_producto_mapping' => 'producto_id',
            'inventario_sucursal' => 'producto_id',
            'compras_detalle' => 'producto_id'
        ];

        foreach ($tablesToDelete as $table => $fk) {
            try {
                $delStmt = $pdo->prepare("DELETE FROM `$table` WHERE `$fk` = :pId");
                $delStmt->execute([':pId' => $productoId]);
            } catch (Exception $e) {
                // Si alguna tabla no existe o falla, continuar
            }
        }

        // 2. Eliminar de la tabla productos principal
        $stmt = $pdo->prepare("DELETE FROM productos WHERE id = :id");
        $stmt->execute([':id' => $productoId]);

        $pdo->commit();

        echo json_encode([
            'success' => true,
            'message' => 'El producto y todos sus registros vinculados han sido eliminados de forma atómica y segura.'
        ]);

    } elseif ($action === 'delete_provider_assignment') {
        // --- ELIMINAR ASIGNACIÓN DE PROVEEDOR ---
        $data = json_decode(file_get_contents('php://input'), true);
        $productoId = isset($data['producto_id']) ? (int)$data['producto_id'] : 0;
        $lugarId = isset($data['lugar_compra_id']) ? (int)$data['lugar_compra_id'] : 0;

        if (!$productoId || !$lugarId) {
            throw new Exception("ID de producto y de proveedor requeridos");
        }

        $pdo->beginTransaction();
        
        $stmt = $pdo->prepare("DELETE FROM producto_lugares_compra 
                               WHERE producto_id = :pId AND lugar_compra_id = :lugarId");
        $stmt->execute([
            ':pId' => $productoId,
            ':lugarId' => $lugarId
        ]);

        // Recalcular CPP basado en proveedores restantes
        $stmtRestantes = $pdo->prepare("SELECT costo_compra FROM producto_lugares_compra 
                                       WHERE producto_id = :pId AND activo = 1");
        $stmtRestantes->execute([':pId' => $productoId]);
        $costosRestantes = $stmtRestantes->fetchAll(PDO::FETCH_COLUMN);

        if (count($costosRestantes) > 0) {
            $nuevoCostoPromedio = array_sum($costosRestantes) / count($costosRestantes);
        } else {
            $nuevoCostoPromedio = 0.0000;
        }

        // Actualizar en productos_costo_promedio
        $stmtCheckCpp = $pdo->prepare("SELECT id, cantidad_total_unidades FROM productos_costo_promedio WHERE producto_id = :pId LIMIT 1");
        $stmtCheckCpp->execute([':pId' => $productoId]);
        $cppRow = $stmtCheckCpp->fetch();

        if ($cppRow) {
            $cantidadTotal = (int)$cppRow['cantidad_total_unidades'];
            $valorTotal = $cantidadTotal * $nuevoCostoPromedio;
            
            $stmtUpdCpp = $pdo->prepare("UPDATE productos_costo_promedio 
                                         SET costo_promedio_unidad_base = :costo, 
                                             valor_total_inventario = :valor,
                                             fecha_ultimo_calculo = NOW() 
                                         WHERE producto_id = :pId");
            $stmtUpdCpp->execute([
                ':costo' => $nuevoCostoPromedio,
                ':valor' => $valorTotal,
                ':pId' => $productoId
            ]);
        } else {
            $stmtInsCpp = $pdo->prepare("INSERT INTO productos_costo_promedio 
                                         (producto_id, costo_promedio_unidad_base, cantidad_total_unidades, valor_total_inventario, fecha_ultimo_calculo) 
                                         VALUES (:pId, :costo, 0, 0.0, NOW())");
            $stmtInsCpp->execute([
                ':pId' => $productoId,
                ':costo' => $nuevoCostoPromedio
            ]);
        }

        // Actualizar en inventario_sucursal
        $stmtUpdStock = $pdo->prepare("UPDATE inventario_sucursal 
                                       SET costo_promedio_local = :costo,
                                           last_updated = NOW() 
                                       WHERE producto_id = :pId AND sucursal_id = 1");
        $stmtUpdStock->execute([
            ':costo' => $nuevoCostoPromedio,
            ':pId' => $productoId
        ]);

        $pdo->commit();

        echo json_encode([
            'success' => true,
            'message' => 'Asignación de proveedor eliminada y CPP recalculado con éxito.'
        ]);

    } elseif ($action === 'update_field') {
        // --- ACTUALIZAR CAMPO DE PRODUCTO ---
        $data = json_decode(file_get_contents('php://input'), true);
        $productoId = isset($data['producto_id']) ? (int)$data['producto_id'] : 0;
        $field = isset($data['field']) ? trim($data['field']) : '';
        $value = isset($data['value']) ? trim($data['value']) : '';

        if (!$productoId) {
            throw new Exception("ID de producto no proporcionado");
        }

        $allowedFields = ['CodigoInterno', 'CodigoBarra', 'NombreComercial', 'NombreGenerico', 'laboratorio'];
        if (!in_array($field, $allowedFields)) {
            throw new Exception("Campo no permitido para edición");
        }

        if ($field === 'NombreComercial' && empty($value)) {
            throw new Exception("El nombre comercial no puede estar vacío");
        }

        if ($field === 'CodigoInterno') {
            if (empty($value)) {
                throw new Exception("El código interno no puede estar vacío");
            }
            $stmtCheck = $pdo->prepare("SELECT COUNT(*) FROM productos WHERE CodigoInterno = :value AND id != :id");
            $stmtCheck->execute([':value' => $value, ':id' => $productoId]);
            if ((int)$stmtCheck->fetchColumn() > 0) {
                throw new Exception("El código interno '$value' ya está asignado a otro producto");
            }
        }

        $stmt = $pdo->prepare("UPDATE productos SET `$field` = :value WHERE id = :id");
        $stmt->execute([':value' => $value === '' ? null : $value, ':id' => $productoId]);

        echo json_encode([
            'success' => true,
            'message' => "Campo $field actualizado correctamente"
        ]);

    } else {
        throw new Exception("Acción no válida o no especificada");
    }


} catch (Exception $e) {
    if (isset($pdo) && $pdo->inTransaction()) {
        $pdo->rollBack();
    }
    http_response_code(500);
    echo json_encode([
        'success' => false,
        'error' => $e->getMessage()
    ]);
}
