<?php

declare(strict_types=1);

namespace App\Controller;

use Dompdf\Dompdf;
use Dompdf\Options;

/**
 * Presupuestos Controller
 *
 * @property \App\Model\Table\PresupuestosTable $Presupuestos
 */
class PresupuestosController extends AppController
{
    /**
     * Verificación centralizada de permisos
     * Se ejecuta antes de cualquier acción
     */
    public function beforeFilter(\Cake\Event\EventInterface $event)
    {
        parent::beforeFilter($event);

        $currentAction = $this->request->getParam('action');

        $this->verificarPermisoORedireccionar('Presupuestos', $currentAction);
    }

    public function exportPresupuestoPdf($id = null)
    {
        $logoPath = WWW_ROOT . 'img' . DS . 'logoQP.png';
        $logoUrl = file_exists($logoPath)
            ? 'data:image/png;base64,' . base64_encode(file_get_contents($logoPath))
            : '';
        // Obtener el cliente por ID y cargar las relaciones necesarias
        $presupuesto = $this->Presupuestos->get($id, contain: [
            'ClientesFacturacion',
            'PresupuestosServicios.Servicios',
        ]);

        // Renderizar la vista HTML como contenido para el PDF
        $this->viewBuilder()->enableAutoLayout(false);
        $this->set(compact('presupuesto', 'logoUrl'));
        $html = $this->render('presupuesto_detalle');

        // Configurar DomPDF para el PDF
        $options = new Options();
        $options->set('isRemoteEnabled', true);
        $dompdf = new Dompdf($options);
        $dompdf->loadHtml($html);

        // Configurar tamaño de papel
        $dompdf->setPaper('A4', 'portrait');

        // Renderizar el PDF
        $dompdf->render();

        // Descargar el archivo PDF
        $dompdf->stream("presupuesto_detalle_{$id}.pdf", ['Attachment' => 1]);
    }
    /**
     * Index method
     *
     * @return \Cake\Http\Response|null|void Renders view
     */
    public function index()
    {
        // Obtener el término de búsqueda de la solicitud (GET)
        $searchTerm = $this->request->getQuery('search', '');

        // Construir la consulta inicial
        $query = $this->Presupuestos->find()
            ->contain(['ClientesFacturacion', 'PresupuestosInvoices'])
            ->order(['Presupuestos.id' => 'DESC']);

        // Agregar condiciones de búsqueda si hay un término
        if (!empty($searchTerm)) {

            $query
                ->leftJoinWith('ClientesFacturacion')
                ->where([
                    'OR' => [
                        'LOWER(ClientesFacturacion.nombre_razon_social) LIKE' => '%' . strtolower($searchTerm) . '%',
                        'LOWER(Presupuestos.nombre_apellido) LIKE' => '%' . strtolower($searchTerm) . '%',
                    ]
                ]);
        }

        // Paginar los resultados
        $presupuestos = $this->paginate($query);

        // Pasar datos a la vista
        $this->set(compact('presupuestos', 'searchTerm'));
    }

    /**
     * View method
     *
     * @param string|null $id Presupuesto id.
     * @return \Cake\Http\Response|null|void Renders view
     * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
     */
    public function view($id = null)
    {
        $presupuesto = $this->Presupuestos->get($id, contain: [
            'ClientesFacturacion',
            'PresupuestosServicios.Servicios',
            'PresupuestosInvoices.Invoices',
        ]);

        // Calcular monto ya facturado por cada servicio del presupuesto,
        // cruzando los invoice_items de las facturas generadas desde este presupuesto.
        // Se compara por MONTO y no por cantidad de unidades, porque la facturación
        // puede ser parcial en soles sin completar una unidad entera.
        $invoiceIds = array_map(
            fn($pi) => $pi->invoice_id,
            array_filter($presupuesto->presupuestos_invoices, fn($pi) => ($pi->invoice->estado ?? '') !== 'ANULADO')
        );
        $montoFacturadoPorServicio = [];

        if (!empty($invoiceIds)) {
            $items = $this->Presupuestos->PresupuestosInvoices->Invoices->InvoiceItems->find()
                ->where(['invoice_id IN' => $invoiceIds])
                ->all();

            foreach ($items as $item) {
                $sid = $item->servicio_id;
                if ($sid === null) {
                    continue;
                }
                $montoFacturadoPorServicio[$sid] = ($montoFacturadoPorServicio[$sid] ?? 0) + (float) $item->total;
            }
        }

        $this->set(compact('presupuesto', 'montoFacturadoPorServicio'));
        // Usar un layout diferenciado para solicitudes normales o AJAX
        if ($this->request->is('ajax')) {
            $this->viewBuilder()->setLayout('ajax');
        } else {
            $this->viewBuilder()->setLayout('default');
        }
    }

    /**
     * Add method
     *
     * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise.
     */
    public function add()
    {
        $presupuesto = $this->Presupuestos->newEmptyEntity();
        $pacienteSeleccionado = null; // Variable para el cliente seleccionado

        // Obtener cliente_facturacion_id del query string (?cliente_facturacion_id=123)
        $clienteFacturacionId = $this->request->getQuery('cliente_facturacion_id');

        // Prellenar datos si el cliente_facturacion_id fue pasado como parámetro en la URL
        if ($clienteFacturacionId) {
            $presupuesto->cliente_facturacion_id = $clienteFacturacionId;

            try {
                $pacienteSeleccionado = $this->Presupuestos->ClientesFacturacion->get($clienteFacturacionId);
            } catch (\Cake\Datasource\Exception\RecordNotFoundException $e) {
                $this->Flash->error(__('Cliente no encontrado'));
            }
        }

        if ($this->request->is('post')) {
            $data = $this->request->getData();

            // Combina la fecha ingresada por el usuario con la hora actual
            $fechaUsuario = new \DateTime($data['modified']);
            $horaActual = new \DateTime();
            $fechaUsuario->setTime((int)$horaActual->format('H'), (int)$horaActual->format('i'), (int)$horaActual->format('s'));

            // Asigna la fecha combinada al campo modified
            $data['modified'] = $fechaUsuario->format('Y-m-d H:i:s');
            $serviciosData = $data['servicios'] ?? [];
            $totalConIgv = $data['total'] ?? 0;

            // Remover datos de servicios antes de guardar el presupuesto
            unset($data['servicios']);
            $presupuesto = $this->Presupuestos->patchEntity($presupuesto, $data);

            $presupuesto->total = $totalConIgv;

            if ($this->Presupuestos->save($presupuesto)) {
                $presupuestoId = $presupuesto->id;

                // Procesar los servicios y guardarlos en PresupuestosServicios
                foreach ($serviciosData as $servicio) {
                    $presupuestoServicio = $this->Presupuestos->PresupuestosServicios->newEmptyEntity();
                    $presupuestoServicio = $this->Presupuestos->PresupuestosServicios->patchEntity($presupuestoServicio, [
                        'presupuesto_id' => $presupuestoId,
                        'servicio_id' => $servicio['servicio_id'],
                        'precio_unitario' => $servicio['precio_unitario'],
                        'cantidad' => $servicio['cantidad'],
                        'pz_dental' => $servicio['pz_dental'] ?? null,
                        'descuento' => $servicio['descuento'] ?? null,
                        'descuento_tipo' => $servicio['descuento_tipo'] ?? 'porcentaje',
                        'total' => $servicio['total'],
                        'observaciones' => $servicio['observaciones'] ?? null,
                    ]);

                    if (!$this->Presupuestos->PresupuestosServicios->save($presupuestoServicio)) {
                        $this->Flash->error(__('No se pudo guardar el servicio: {0}', $servicio['servicio_id']));
                    }
                }

                $this->Flash->success(__('El presupuesto ha sido guardado.'));

                // Redirigir a la vista del cliente asociado
                if ($presupuesto->cliente_facturacion_id) {
                    return $this->redirect([
                        'controller' => 'ClientesFacturacion',
                        'action' => 'view',
                        $presupuesto->cliente_facturacion_id,
                        '#' => 'presupuestos'
                    ]);
                }

                return $this->redirect(['action' => 'index']);
            }
            $this->Flash->error(__('El presupuesto no pudo ser guardado. Por favor, inténtelo de nuevo.'));
        }

        $pacientesData = $this->Presupuestos->ClientesFacturacion->find('all')
            ->where(['estado' => 'A'])
            ->select(['id', 'nombre_razon_social', 'numero_doc', 'direccion'])
            ->toArray();

        // Mapear los datos para que JavaScript pueda encontrar por cliente_facturacion_id
        $pacientesData2 = [];
        foreach ($pacientesData as $cliente) {
            $pacientesData2[] = [
                'cliente_facturacion_id' => $cliente->id,
                'dni' => $cliente->numero_doc,
                'direccion' => $cliente->direccion
            ];
        }

        $serviciosData = $this->Presupuestos->PresupuestosServicios->Servicios->find('all')
            ->select(['id', 'nombre', 'costo'])
            ->toArray();

        // Pasar el cliente_facturacion_id si viene desde la URL
        $clienteFacturacionIdPreseleccionado = $clienteFacturacionId ?? null;

        $this->set(compact('presupuesto', 'pacientesData', 'serviciosData', 'pacienteSeleccionado', 'pacientesData2', 'clienteFacturacionIdPreseleccionado'));
        // Usar un layout diferenciado para solicitudes normales o AJAX
        if ($this->request->is('ajax')) {
            $this->viewBuilder()->setLayout('ajax');
        } else {
            $this->viewBuilder()->setLayout('default');
        }
    }

    /**
     * Edit method
     *
     * @param string|null $id Presupuesto id.
     * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise.
     * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
     */
    public function edit($id)
    {
        $presupuesto = $this->Presupuestos->get($id, contain: [
            'PresupuestosServicios' => [
                'Servicios',
            ],
            'ClientesFacturacion',
        ]);


        if ($this->request->is(['post', 'put'])) {
            $data = $this->request->getData();
            // Combina la fecha ingresada por el usuario con la hora actual
            $fechaUsuario = new \DateTime($data['modified']);
            $horaActual = new \DateTime();
            $fechaUsuario->setTime((int)$horaActual->format('H'), (int)$horaActual->format('i'), (int)$horaActual->format('s'));

            // Asigna la fecha combinada al campo modified
            $data['modified'] = $fechaUsuario->format('Y-m-d H:i:s');
            $serviciosData = $data['servicios'] ?? [];
            $totalConIgv = $data['total'] ?? 0;

            unset($data['servicios']);
            $presupuesto = $this->Presupuestos->patchEntity($presupuesto, $data);
            $presupuesto->total = $totalConIgv;

            if ($this->Presupuestos->save($presupuesto)) {
                foreach ($serviciosData as $servicio) {
                    // Si el ID está vacío, asumimos que es un nuevo servicio
                    if (empty($servicio['id'])) {
                        $presupuestoServicio = $this->Presupuestos->PresupuestosServicios->newEntity([
                            'presupuesto_id' => $presupuesto->id,
                            'servicio_id' => $servicio['servicio_id'],
                            'precio_unitario' => $servicio['precio_unitario'],
                            'pz_dental' => $servicio['pz_dental'] ?? null,
                            'descuento' => $servicio['descuento'] ?? null,
                            'descuento_tipo' => $servicio['descuento_tipo'] ?? 'porcentaje',
                            'cantidad' => $servicio['cantidad'],
                            'total' => $servicio['total'],
                            'observaciones' => $servicio['observaciones'] ?? null,
                        ]);

                        if (!$this->Presupuestos->PresupuestosServicios->save($presupuestoServicio)) {
                            $this->Flash->error(__('No se pudo guardar el nuevo servicio: {0}. Errores: {1}', $servicio['servicio_id'], json_encode($presupuestoServicio->getErrors())));
                        }
                    } else {
                        // Si el ID existe, editamos el servicio existente
                        if ($this->Presupuestos->PresupuestosServicios->exists(['id' => $servicio['id']])) {
                            $presupuestoServicio = $this->Presupuestos->PresupuestosServicios->get($servicio['id']);
                            $presupuestoServicio = $this->Presupuestos->PresupuestosServicios->patchEntity($presupuestoServicio, [
                                'servicio_id' => $servicio['servicio_id'],
                                'precio_unitario' => $servicio['precio_unitario'],
                                'pz_dental' => $servicio['pz_dental'] ?? null,
                                'descuento' => $servicio['descuento'] ?? null,
                                'descuento_tipo' => $servicio['descuento_tipo'] ?? 'porcentaje',
                                'cantidad' => $servicio['cantidad'],
                                'total' => $servicio['total'],
                                'observaciones' => $servicio['observaciones'] ?? null,
                            ]);

                            if (!$this->Presupuestos->PresupuestosServicios->save($presupuestoServicio)) {
                                $this->Flash->error(__('No se pudo guardar el servicio existente: {0}. Errores: {1}', $servicio['servicio_id'], json_encode($presupuestoServicio->getErrors())));
                            }
                        } else {
                            $this->Flash->error(__('No se encontró el servicio asociado con el ID: {0}', $servicio['id']));
                            continue; // Salta este servicio
                        }
                    }
                }
                $this->Flash->success(__('El presupuesto ha sido guardado.'));

                if (!empty($presupuesto->cliente_facturacion_id)) {
                    return $this->redirect([
                        'controller' => 'ClientesFacturacion',
                        'action' => 'view',
                        $presupuesto->cliente_facturacion_id,
                        '#' => 'presupuestos'
                    ]);
                }

                // Si es proforma
                return $this->redirect(['action' => 'index']);
            }
            $this->Flash->error(__('El presupuesto no pudo ser guardado. Por favor, inténtelo de nuevo.'));
        }

        $pacientesData = $this->Presupuestos->ClientesFacturacion->find('all')
            ->where(['estado' => 'A'])
            ->select(['id', 'nombre_razon_social', 'numero_doc', 'direccion'])
            ->toArray();

        // Mapear los datos para que JavaScript pueda encontrar por cliente_facturacion_id
        $pacientesData2 = [];
        foreach ($pacientesData as $cliente) {
            $pacientesData2[] = [
                'cliente_facturacion_id' => $cliente->id,
                'dni' => $cliente->numero_doc,
                'direccion' => $cliente->direccion
            ];
        }

        $serviciosData = $this->Presupuestos->PresupuestosServicios->Servicios->find('all')
            ->select(['id', 'nombre', 'costo'])
            ->toArray();

        $this->set(compact('presupuesto', 'pacientesData', 'serviciosData', 'pacientesData2'));
        // Usar un layout diferenciado para solicitudes normales o AJAX
        if ($this->request->is('ajax')) {
            $this->viewBuilder()->setLayout('ajax');
        } else {
            $this->viewBuilder()->setLayout('default');
        }
    }

    /**
     * Delete method
     *
     * @param string|null $id Presupuesto id.
     * @return \Cake\Http\Response|null Redirects to index.
     * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
     */
    public function delete($id = null)
    {
        $this->request->allowMethod(['post', 'delete']);
        $presupuesto = $this->Presupuestos->get($id);
        if ($this->Presupuestos->delete($presupuesto)) {
            $this->Flash->success(__('The presupuesto has been deleted.'));
        } else {
            $this->Flash->error(__('The presupuesto could not be deleted. Please, try again.'));
        }

        return $this->redirect(['action' => 'index']);
    }
}
