<?php

namespace App\Controllers;

use App\Models\FuncionModel;
use App\Models\AsientoModel;
use App\Models\ReservaModel;
use App\Models\PagoModel;
use App\Models\UsuarioModel;
use App\Models\ClienteMembresiaModel;
use App\Models\ProductoModel;
use App\Models\PromocionModel;
use App\Entities\Reserva as ReservaEntity;
use App\Entities\Pago as PagoEntity;
use App\Libraries\BoletoGenerator;
use App\Libraries\PromoHelper;

class Reserva extends BaseController
{
    /**
     * Muestra el mapa de asientos para una función específica.
     */
    public function asientos($id_funcion)
    {
        // 1. Verificar si el usuario está logueado
        if (!session()->get('isLoggedIn')) {
            return redirect()->to(base_url('login'))->with('error', 'Por favor, inicia sesión para poder comprar tus entradas.');
        }

        $funcionModel = new FuncionModel();
        
        // Obtener detalles de la función (incluyendo película, sala, local)
        $db = \db_connect();
        $funcion = $db->query("SELECT f.*, p.titulo AS pelicula_titulo, p.poster_url, s.nombre AS sala_nombre, s.tipo AS sala_tipo, l.nombre AS local_nombre
            FROM funcion f
            JOIN pelicula p ON p.id_pelicula = f.id_pelicula
            JOIN sala s ON s.id_sala = f.id_sala
            JOIN local l ON l.id_local = s.id_local
            WHERE f.id_funcion = ? AND f.estado = 'programada'", [$id_funcion])->getRow();

        if (!$funcion) {
            return redirect()->to(base_url('/'))->with('error', 'La función solicitada no está disponible o no existe.');
        }

        // Obtener asientos con su estado de ocupación
        $asientoModel = new AsientoModel();
        $asientos = $asientoModel->getAsientosConOcupacion((int)$id_funcion, (int)$funcion->id_sala);

        // Agrupar los asientos por fila para renderizarlos en la cuadrícula
        $asientosAgrupados = [];
        foreach ($asientos as $asiento) {
            $asientosAgrupados[$asiento->fila][] = $asiento;
        }

        // Si el cliente tiene una membresía vigente, mostramos los precios ya con descuento.
        $cmModel = new ClienteMembresiaModel();
        $membresiaActiva = $cmModel->getMembresiaActiva(session()->get('user_id'));
        $descuentoPct = $membresiaActiva ? (float) $membresiaActiva->descuento_pct : 0.0;

        // Info de la promoción de tipo ENTRADA guardada en sesión (si la hay), ya
        // validada contra ESTA función específica (vigencia + tipo de sala).
        $promoTicket = session()->get('promo_ticket');
        $promoInfo = null;

        if (!empty($promoTicket)) {
            $promocionModel = new PromocionModel();
            $promocionEntity = $promocionModel->find($promoTicket['id_promocion']);

            $promoInfo = [
                'nombre' => $promoTicket['nombre'],
                'aplicable' => false,
                'motivo' => 'La promoción ya no está disponible.',
                'tipo_descuento' => $promoTicket['tipo_descuento'] ?? 'PORCENTAJE',
                'valor_descuento' => (float) ($promoTicket['valor_descuento'] ?? 0),
                'cantidad_minima' => (int) ($promoTicket['cantidad_minima'] ?? 1),
            ];

            if ($promocionEntity) {
                $dias = PromoHelper::diasValidos($promocionEntity->id_promocion);
                $vigencia = PromoHelper::verificarVigencia($promocionEntity, $dias);
                $tipoSala = PromoHelper::verificarTipoSala($promocionEntity, $funcion->sala_tipo);

                if (!$vigencia['vigente']) {
                    $promoInfo['motivo'] = $vigencia['motivo'];
                } elseif (!$tipoSala['vigente']) {
                    $promoInfo['motivo'] = $tipoSala['motivo'];
                } else {
                    $promoInfo['aplicable'] = true;
                    $promoInfo['motivo'] = null;
                }
            }
        }

        return view('home/reserva/asientos', [
            'funcion' => $funcion,
            'asientosAgrupados' => $asientosAgrupados,
            'descuentoPct' => $descuentoPct,
            'promoTicket' => $promoTicket,
            'promoInfo' => $promoInfo,
        ]);
    }

    /**
     * Procesa la selección de asientos y la guarda temporalmente en la sesión.
     */
    public function seleccionarAsientos($id_funcion)
    {
        if (!session()->get('isLoggedIn')) {
            return redirect()->to(base_url('login'));
        }

        $asientosSeleccionados = $this->request->getPost('asientos'); // Array de IDs de asientos

        if (empty($asientosSeleccionados)) {
            return redirect()->back()->with('error', 'Debes seleccionar al menos un asiento para continuar.');
        }

        $funcionModel = new FuncionModel();
        $funcion = $funcionModel->find($id_funcion);

        if (!$funcion) {
            return redirect()->to(base_url('/'))->with('error', 'La función seleccionada no es válida.');
        }

        // Se necesita el tipo de sala de la función para validar promociones
        // restringidas (ej. "Domingo 3D" solo aplica a salas 3D).
        $db = \db_connect();
        $salaTipo = $db->table('sala')->select('tipo')->where('id_sala', $funcion->id_sala)->get()->getRow();
        $tipoSalaFuncion = $salaTipo->tipo ?? null;

        // Obtener los detalles de los asientos seleccionados para calcular precios
        $asientoModel = new AsientoModel();
        $asientosDetalles = $asientoModel->whereIn('id_asiento', $asientosSeleccionados)->findAll();

        // Si el cliente tiene una membresía vigente, su descuento se aplica sobre
        // cada entrada automáticamente.
        $cmModel = new ClienteMembresiaModel();
        $membresiaActiva = $cmModel->getMembresiaActiva(session()->get('user_id'));
        $promoTicket = session()->get('promo_ticket');
        $descuentoPct = 0.0;
        $promoTicketAplicada = null;
        $promoTicketMotivoNoAplicada = null;

        $cantidadAsientos = count($asientosDetalles);

        if (!empty($promoTicket)) {
            $promocionModel = new PromocionModel();
            $promocionEntity = $promocionModel->find($promoTicket['id_promocion']);

            if (!$promocionEntity) {
                $promoTicketMotivoNoAplicada = 'La promoción ya no está disponible.';
            } else {
                $dias = PromoHelper::diasValidos($promocionEntity->id_promocion);
                $vigencia = PromoHelper::verificarVigencia($promocionEntity, $dias);
                $tipoSala = PromoHelper::verificarTipoSala($promocionEntity, $tipoSalaFuncion);
                $cantidadMinima = $promocionEntity->getCantidadMinima();

                if (!$vigencia['vigente']) {
                    $promoTicketMotivoNoAplicada = $vigencia['motivo'];
                } elseif (!$tipoSala['vigente']) {
                    $promoTicketMotivoNoAplicada = $tipoSala['motivo'];
                } elseif ($cantidadAsientos < $cantidadMinima) {
                    $promoTicketMotivoNoAplicada = "Esta promoción requiere al menos {$cantidadMinima} entrada(s) de la misma función.";
                } else {
                    // Promoción vigente, tipo de sala correcto y cantidad mínima cumplida: se aplica.
                    $promoTicketAplicada = $promocionEntity;
                    if ($promocionEntity->tipo_descuento === 'PORCENTAJE') {
                        $descuentoPct = max(0, min(100, (float) $promocionEntity->valor_descuento));
                    }
                }
            }

            if ($promoTicketMotivoNoAplicada) {
                session()->setFlashdata('info', 'Promoción "' . esc($promoTicket['nombre']) . '" no aplicada: ' . $promoTicketMotivoNoAplicada);
            }
        }

        if ($descuentoPct <= 0.0 && !$promoTicketAplicada) {
            $descuentoPct = $membresiaActiva ? (float) $membresiaActiva->descuento_pct : 0.0;
        }

        $subtotal = 0;
        $total = 0;
        $asientosNombres = [];

        foreach ($asientosDetalles as $asiento) {
            $precioAsiento = $funcion->precio_base;
            // Si el asiento es preferencial o discapacitado, tiene 25% de descuento (precio = base * 0.75)
            if ($asiento->tipo === 'preferencial' || $asiento->tipo === 'discapacitado') {
                $precioAsiento = $funcion->precio_base * 0.75;
            }

            if ($promoTicketAplicada && $promoTicketAplicada->tipo_descuento === 'PRECIO_FIJO') {
                $precioConDescuento = round((float) $promoTicketAplicada->valor_descuento, 2);
            } else {
                $precioConDescuento = $descuentoPct > 0
                    ? round($precioAsiento * (1 - ($descuentoPct / 100)), 2)
                    : $precioAsiento;
            }

            $subtotal += $precioAsiento;
            $total += $precioConDescuento;

            $asientosNombres[] = [
                'id_asiento' => $asiento->id_asiento,
                'codigo' => $asiento->fila . $asiento->numero,
                'tipo' => $asiento->tipo,
                'precio_base' => $precioAsiento,
                'precio' => $precioConDescuento
            ];
        }

        // Guardar en sesión
        session()->set('compra_temp', [
            'id_funcion' => $id_funcion,
            'asientos' => $asientosNombres,
            'subtotal' => $subtotal,
            'descuento_pct' => $descuentoPct,
            'descuento_monto' => round($subtotal - $total, 2),
            'total' => $total
        ]);
        session()->remove('carrito_reserva_temp');

        return redirect()->to(base_url('reserva/productos/' . $id_funcion));
    }

    /**
     * Muestra los productos que pueden agregarse al total de la compra.
     */
    public function productos($id_funcion)
    {
        if (!session()->get('isLoggedIn')) {
            return redirect()->to(base_url('login'));
        }

        $compra = session()->get('compra_temp');
        if (!$compra) {
            return redirect()->to(base_url('/'))->with('error', 'No tienes ninguna selección activa.');
        }

        $db = \db_connect();
        $funcion = $db->query("SELECT f.*, p.titulo AS pelicula_titulo, s.nombre AS sala_nombre, l.nombre AS local_nombre
            FROM funcion f
            JOIN pelicula p ON p.id_pelicula = f.id_pelicula
            JOIN sala s ON s.id_sala = f.id_sala
            JOIN local l ON l.id_local = s.id_local
            WHERE f.id_funcion = ?", [$id_funcion])->getRow();

        $productoModel = new ProductoModel();
        $productos = $productoModel->where('disponible', 1)->findAll();
        $carritoReserva = $this->getCarritoReserva();

        return view('home/reserva/productos', [
            'compra' => $compra,
            'funcion' => $funcion,
            'productos' => $productos,
            'carrito_reserva' => $carritoReserva,
        ]);
    }

    /**
     * Agrega un producto al total de la compra de entradas.
     */
    public function agregarProducto($id_funcion)
    {
        if (!session()->get('isLoggedIn')) {
            return redirect()->to(base_url('login'));
        }

        $compra = session()->get('compra_temp');
        if (!$compra) {
            return redirect()->to(base_url('/'))->with('error', 'No tienes ninguna selección activa.');
        }

        $idProducto = (int)$this->request->getPost('id_producto');
        $cantidad = max(1, (int)$this->request->getPost('cantidad'));

        $productoModel = new ProductoModel();
        $producto = $productoModel->find($idProducto);

        if (!$producto || !$producto->estaDisponible()) {
            return redirect()->back()->with('error', 'El producto seleccionado no está disponible.');
        }

        $carrito = $this->getCarritoReserva();

        if (isset($carrito['items'][$idProducto])) {
            $carrito['items'][$idProducto]['cantidad'] += $cantidad;
        } else {
            $carrito['items'][$idProducto] = [
                'id_producto' => $producto->id_producto,
                'nombre' => $producto->nombre,
                'descripcion' => $producto->descripcion,
                'categoria' => $producto->categoria,
                'imagen_url' => $producto->getImagenUrl(),
                'precio_unitario' => (float)$producto->precio,
                'cantidad' => $cantidad,
            ];
        }

        $carrito = $this->normalizeCarritoReserva($carrito['items']);
        session()->set('carrito_reserva_temp', $carrito);

        return redirect()->to(base_url('reserva/productos/' . $id_funcion))->with('success', 'Producto agregado a tu compra.');
    }

    public function actualizarProducto($id_funcion)
    {
        if (!session()->get('isLoggedIn')) {
            return redirect()->to(base_url('login'));
        }

        $compra = session()->get('compra_temp');
        if (!$compra) {
            return redirect()->to(base_url('/'))->with('error', 'No tienes ninguna selección activa.');
        }

        $idProducto = (int)$this->request->getPost('id_producto');
        $cantidad = max(1, (int)$this->request->getPost('cantidad'));

        $carrito = $this->getCarritoReserva();

        if (!isset($carrito['items'][$idProducto])) {
            return redirect()->back()->with('error', 'No se encontró el producto en tu carrito.');
        }

        $carrito['items'][$idProducto]['cantidad'] = $cantidad;
        $carrito = $this->normalizeCarritoReserva($carrito['items']);
        session()->set('carrito_reserva_temp', $carrito);

        return redirect()->to(base_url('reserva/productos/' . $id_funcion))->with('success', 'Cantidad actualizada correctamente.');
    }

    public function eliminarProducto($id_funcion)
    {
        if (!session()->get('isLoggedIn')) {
            return redirect()->to(base_url('login'));
        }

        $compra = session()->get('compra_temp');
        if (!$compra) {
            return redirect()->to(base_url('/'))->with('error', 'No tienes ninguna selección activa.');
        }

        $idProducto = (int)$this->request->getPost('id_producto');
        $carrito = $this->getCarritoReserva();

        if (isset($carrito['items'][$idProducto])) {
            unset($carrito['items'][$idProducto]);
        }

        $carrito = $this->normalizeCarritoReserva($carrito['items']);
        session()->set('carrito_reserva_temp', $carrito);

        return redirect()->to(base_url('reserva/productos/' . $id_funcion))->with('success', 'Producto eliminado del carrito.');
    }

    /**
     * Muestra el formulario de pago simulado.
     */
    public function pago()
    {
        if (!session()->get('isLoggedIn')) {
            return redirect()->to(base_url('login'));
        }

        $compra = session()->get('compra_temp');
        if (!$compra) {
            return redirect()->to(base_url('/'))->with('error', 'No tienes ninguna selección activa.');
        }

        $db = \db_connect();
        $funcion = $db->query("SELECT f.*, p.titulo AS pelicula_titulo, s.nombre AS sala_nombre, l.nombre AS local_nombre
            FROM funcion f
            JOIN pelicula p ON p.id_pelicula = f.id_pelicula
            JOIN sala s ON s.id_sala = f.id_sala
            JOIN local l ON l.id_local = s.id_local
            WHERE f.id_funcion = ?", [$compra['id_funcion']])->getRow();

        $carritoReserva = $this->getCarritoReserva();
        $montoProductos = $carritoReserva['total'];
        $compra['productos_total'] = $montoProductos;
        $compra['total_final'] = round((float)$compra['total'] + $montoProductos, 2);
        $compra['productos'] = $carritoReserva['items'];

        return view('home/reserva/pago', [
            'compra' => $compra,
            'funcion' => $funcion,
            'carrito_reserva' => $carritoReserva,
        ]);
    }

    /**
     * Valida el pago simulado, guarda la reserva, cambia asientos a ocupados y genera el PDF.
     */
    public function confirmar()
    {
        if (!session()->get('isLoggedIn')) {
            return redirect()->to(base_url('login'));
        }

        $compra = session()->get('compra_temp');
        if (!$compra) {
            return redirect()->to(base_url('/'))->with('error', 'Tu sesión de compra ha expirado.');
        }

        // Validaciones del formulario de pago
        $rules = [
            'numero_tarjeta' => 'required',
            'nombre_titular' => 'required|min_length[3]|max_length[100]',
            'fecha_vencimiento' => 'required',
            'cvv' => 'required|numeric|min_length[3]|max_length[4]'
        ];

        if (!$this->validate($rules)) {
            return redirect()->back()->withInput()->with('error', 'Por favor, verifique los datos de su tarjeta.');
        }

        // Verificar que el usuario de la sesión todavía exista en la base de datos.
        // (Puede haber sido eliminado por un admin mientras la sesión seguía activa,
        // lo que antes provocaba un error de FK silencioso y "reserva no encontrada").
        $userModelCheck = new UsuarioModel();
        $usuarioActual = $userModelCheck->find(session()->get('user_id'));
        if (!$usuarioActual) {
            session()->destroy();
            return redirect()->to(base_url('login'))
                             ->with('error', 'Tu sesión ya no es válida. Por favor, inicia sesión nuevamente para continuar con tu compra.');
        }

        // IMPORTANTE: Guardar datos necesarios y limpiar la sesión ANTES de procesar
        // para evitar doble submit que duplicaría la reserva.
        $carritoReserva = $this->getCarritoReserva();
        $montoProductos = $carritoReserva['total'];
        $compraGuardada = $compra;
        $compraGuardada['productos_total'] = $montoProductos;
        $compraGuardada['total_final'] = round((float)$compraGuardada['total'] + $montoProductos, 2);
        $compraGuardada['productos'] = $carritoReserva['items'];

        session()->remove('compra_temp');
        session()->remove('carrito_reserva_temp');

        $db = \db_connect();
        // Hacemos que cualquier error de BD dentro de la transacción lance una excepción
        // en lugar de fallar en silencio (comportamiento por defecto de CodeIgniter dentro
        // de una transacción manual), para poder detectarlo y revertir correctamente.
        $db->transException(true);

        $id_reserva = null;
        $referenciaGenerada = null;

        try {
            $db->transStart();

            // 1. Guardar la reserva
            $reservaModel = new ReservaModel();
            $reserva = new ReservaEntity();
            $reserva->id_usuario = session()->get('user_id');
            $reserva->total = $compraGuardada['total_final'];
            $reserva->estado = 'pagada';

            if (!$reservaModel->save($reserva)) {
                throw new \RuntimeException('No se pudo guardar la reserva: ' . implode(' ', $reservaModel->errors()));
            }
            $id_reserva = $reservaModel->getInsertID();

            // 2. Guardar el detalle de la reserva (asientos vendidos para la función)
            foreach ($compraGuardada['asientos'] as $asiento) {
                // Verificar si el asiento ya se ocupó (concurrencia)
                $ocupado = $db->table('detalle_reserva')
                              ->where('id_funcion', $compraGuardada['id_funcion'])
                              ->where('id_asiento', $asiento['id_asiento'])
                              ->countAllResults();

                if ($ocupado > 0) {
                    throw new \RuntimeException('ASIENTO_OCUPADO');
                }

                $db->table('detalle_reserva')->insert([
                    'id_reserva'      => $id_reserva,
                    'id_funcion'      => $compraGuardada['id_funcion'],
                    'id_asiento'      => $asiento['id_asiento'],
                    'precio_unitario' => $asiento['precio']
                ]);
            }

            if (!empty($compraGuardada['productos'])) {
                foreach ($compraGuardada['productos'] as $item) {
                    $db->table('reserva_producto')->insert([
                        'id_reserva'      => $id_reserva,
                        'id_producto'     => $item['id_producto'],
                        'id_promocion'    => $item['id_promocion'] ?? null,
                        'cantidad'        => $item['cantidad'],
                        'precio_unitario' => $item['precio_unitario'],
                    ]);
                }
            }

            // 3. Registrar el Pago
            $pagoModel = new PagoModel();
            $pago = new PagoEntity();
            $pago->id_reserva = $id_reserva;
            $pago->monto      = $compraGuardada['total_final'];
            $pago->metodo     = 'tarjeta';
            $pago->estado     = 'aprobado';
            $referencia       = 'CIN-' . date('Y') . '-' . sprintf('%06d', $id_reserva);
            $pago->referencia = $referencia;
            $referenciaGenerada = $referencia;

            if (!$pagoModel->save($pago)) {
                throw new \RuntimeException('No se pudo guardar el pago: ' . implode(' ', $pagoModel->errors()));
            }

            $db->transComplete();

            if ($db->transStatus() === false) {
                throw new \RuntimeException('La transacción no pudo completarse.');
            }
        } catch (\Throwable $e) {
            $db->transRollback();

            // Devolvemos los asientos seleccionados a la sesión para que el cliente
            // no pierda su selección y pueda intentarlo de nuevo.
            session()->set('compra_temp', $compraGuardada);

            if ($e->getMessage() === 'ASIENTO_OCUPADO') {
                return redirect()->to(base_url('reserva/asientos/' . $compraGuardada['id_funcion']))
                                 ->with('error', 'Lo sentimos, uno de los asientos seleccionados acaba de ser ocupado. Por favor, selecciona otros.');
            }

            log_message('error', 'Error al confirmar reserva: ' . $e->getMessage());

            return redirect()->to(base_url('reserva/pago'))
                             ->with('error', 'Ocurrió un problema al procesar tu pago y la reserva no se guardó. Por favor, intenta nuevamente.');
        }

        // 4. Generar PDF con QR — siempre dentro de try-catch para no interrumpir el flujo
        $correoEnviado = false;
        try {
            $generator = new BoletoGenerator();
            $pdfPath   = $generator->generarBoleto($id_reserva);

            // 5. Intentar enviar por correo
            $userModel = new UsuarioModel();
            $usuario   = $userModel->find(session()->get('user_id'));
            if ($usuario && !empty($usuario->email)) {
                $correoEnviado = $generator->enviarPorCorreo(
                    $usuario->email,
                    $usuario->nombres,
                    $referenciaGenerada,
                    $pdfPath
                );
            }
        } catch (\Throwable $e) {
            log_message('error', 'Error generando PDF o enviando correo: ' . $e->getMessage());
        }

        if ($correoEnviado) {
            session()->setFlashdata('success_email', 'Se ha enviado una copia del boleto digital a tu correo electrónico.');
        } else {
            session()->setFlashdata('warning_email', 'El boleto PDF se generó correctamente. No se pudo enviar por correo (revisar configuración SMTP).');
        }

        // Siempre redirigir a la página de confirmación
        return redirect()->to(base_url('reserva/confirmacion/' . $id_reserva));
    }

    /**
     * Muestra la página de confirmación con éxito.
     */
    public function confirmacion($id_reserva)
    {
        if (!session()->get('isLoggedIn')) {
            return redirect()->to(base_url('login'));
        }

        $db = \db_connect();
        
        // Obtener detalles de la reserva
        $reserva = $db->query("SELECT r.*, p.referencia, p.metodo, p.fecha_pago
            FROM reserva r
            JOIN pago p ON p.id_reserva = r.id_reserva
            WHERE r.id_reserva = ? AND r.id_usuario = ?", [$id_reserva, session()->get('user_id')])->getRow();

        if (!$reserva) {
            return redirect()->to(base_url('/'))->with('error', 'La reserva no fue encontrada.');
        }

        // Obtener detalles de la película, sala, fecha, asientos comprados
        $detalles = $db->query("SELECT dr.*, a.fila, a.numero, f.fecha, f.hora_inicio, pel.titulo AS pelicula_titulo, s.nombre AS sala_nombre, l.nombre AS local_nombre
            FROM detalle_reserva dr
            JOIN asiento a ON a.id_asiento = dr.id_asiento
            JOIN funcion f ON f.id_funcion = dr.id_funcion
            JOIN pelicula pel ON pel.id_pelicula = f.id_pelicula
            JOIN sala s ON s.id_sala = f.id_sala
            JOIN local l ON l.id_local = s.id_local
            WHERE dr.id_reserva = ?", [$id_reserva])->getResult();

        return view('home/reserva/confirmacion', [
            'reserva' => $reserva,
            'detalles' => $detalles
        ]);
    }

    private function getCarritoReserva(): array
    {
        $carrito = session()->get('carrito_reserva_temp');
        if (!is_array($carrito)) {
            return [
                'items' => [],
                'subtotal' => 0.0,
                'descuento_pct' => 0.0,
                'descuento_monto' => 0.0,
                'total' => 0.0,
            ];
        }

        return $this->normalizeCarritoReserva($carrito['items'] ?? []);
    }

    private function normalizeCarritoReserva(array $items): array
    {
        $subtotal = 0.0;
        $itemsNormalizados = [];

        foreach ($items as $idProducto => $item) {
            $cantidad = max(1, (int)($item['cantidad'] ?? 1));
            $precioUnitario = (float)($item['precio_unitario'] ?? 0.0);
            $subtotalItem = round($precioUnitario * $cantidad, 2);
            $subtotal += $subtotalItem;

            $itemsNormalizados[$idProducto] = [
                'id_producto' => $item['id_producto'] ?? $idProducto,
                'nombre' => $item['nombre'] ?? '',
                'descripcion' => $item['descripcion'] ?? '',
                'categoria' => $item['categoria'] ?? '',
                'imagen_url' => $item['imagen_url'] ?? '',
                'precio_unitario' => $precioUnitario,
                'cantidad' => $cantidad,
                'subtotal' => $subtotalItem,
            ];
        }

        return [
            'items' => $itemsNormalizados,
            'subtotal' => round($subtotal, 2),
            'descuento_pct' => 0.0,
            'descuento_monto' => 0.0,
            'total' => round($subtotal, 2),
        ];
    }

    /**
     * Permite al cliente descargar su boleto PDF generado.
     */
    public function descargarBoleto($id_reserva)
    {
        if (!session()->get('isLoggedIn')) {
            return redirect()->to(base_url('login'));
        }

        // Validar que la reserva pertenece al usuario
        $reservaModel = new ReservaModel();
        $reserva = $reservaModel->where('id_reserva', $id_reserva)
                               ->where('id_usuario', session()->get('user_id'))
                               ->first();

        if (!$reserva) {
            return redirect()->back()->with('error', 'Acceso no autorizado a este boleto.');
        }

        // Generar o recuperar el PDF
        $generator = new BoletoGenerator();
        $pdfPath = $generator->generarBoleto($id_reserva);

        if (file_exists($pdfPath)) {
            return $this->response->download($pdfPath, null)->setFileName('Boleto-CIN-' . $id_reserva . '.pdf');
        } else {
            return redirect()->back()->with('error', 'El archivo del boleto no está disponible en este momento.');
        }
    }
    /**
     * Historial de compras del usuario autenticado.
     */
    public function misCompras()
    {
        if (!session()->get('isLoggedIn')) {
            return redirect()->to(base_url('login'))->with('error', 'Por favor, inicia sesión para ver tus compras.');
        }

        $db = \db_connect();
        $id_usuario = session()->get('user_id');

        // Obtener todas las reservas del usuario con info del primer detalle (película, fecha, etc.)
        $reservas = $db->query("
            SELECT
                r.id_reserva,
                r.total,
                r.estado,
                r.fecha_reserva,
                p.referencia,
                p.metodo,
                p.estado AS pago_estado,
                p.fecha_pago,
                pel.titulo  AS pelicula_titulo,
                pel.poster_url,
                l.nombre    AS local_nombre,
                s.nombre    AS sala_nombre,
                f.fecha     AS funcion_fecha,
                f.hora_inicio,
                COUNT(dr.id_detalle) AS total_asientos
            FROM reserva r
            JOIN pago p          ON p.id_reserva  = r.id_reserva
            JOIN detalle_reserva dr ON dr.id_reserva = r.id_reserva
            JOIN funcion f       ON f.id_funcion   = dr.id_funcion
            JOIN pelicula pel    ON pel.id_pelicula = f.id_pelicula
            JOIN sala s          ON s.id_sala       = f.id_sala
            JOIN local l         ON l.id_local      = s.id_local
            WHERE r.id_usuario = ?
            GROUP BY r.id_reserva, p.id_pago
            ORDER BY r.fecha_reserva DESC
        ", [$id_usuario])->getResult();

        return view('home/reserva/mis_compras', [
            'reservas' => $reservas
        ]);
    }
}
