<?php

declare(strict_types=1);

/**
 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 * @link      https://cakephp.org CakePHP(tm) Project
 * @since     0.2.9
 * @license   https://opensource.org/licenses/mit-license.php MIT License
 */

namespace App\Controller;

use Cake\Core\Configure;
use Cake\Http\Exception\ForbiddenException;
use Cake\Http\Exception\NotFoundException;
use Cake\Http\Response;
use Cake\View\Exception\MissingTemplateException;

class PagesController extends AppController
{
    public function display(string ...$path): ?Response
    {
        if (!$path) {
            return $this->redirect('/');
        }

        if (in_array('..', $path, true) || in_array('.', $path, true)) {
            throw new ForbiddenException();
        }

        $page = $subpage = null;

        if (!empty($path[0])) {
            $page = $path[0];
        }
        if (!empty($path[1])) {
            $subpage = $path[1];
        }

        if ($page === 'home') {
            $citasTable = $this->fetchTable('Citas');

            $today = date('Y-m-d');

            // Mes seleccionado para "Servicios Más Facturados" (?mes=YYYY-MM), por defecto el mes actual
            $mesSeleccionado = $this->request->getQuery('mes');
            if (!$mesSeleccionado || !preg_match('/^\d{4}-\d{2}$/', $mesSeleccionado)) {
                $mesSeleccionado = date('Y-m');
            }
            $inicioMesSeleccionado = $mesSeleccionado . '-01 00:00:00';
            $finMesSeleccionado = date('Y-m-t 23:59:59', strtotime($inicioMesSeleccionado));

            $inicioMes = date('Y-m-01 00:00:00');
            $finMes = date('Y-m-t 23:59:59');

            // Citas creadas hoy por usuario (usando created_at en zona horaria Lima)
            $tzLima = new \DateTimeZone('America/Lima');
            $hoyInicio = new \DateTime('today', $tzLima);
            $hoyFin = (clone $hoyInicio)->modify('+1 day -1 second');

            // Convertir a UTC (porque los timestamps están en UTC en la base de datos)
            $hoyInicioUTC = (clone $hoyInicio)->setTimezone(new \DateTimeZone('UTC'))->format('Y-m-d H:i:s');
            $hoyFinUTC = (clone $hoyFin)->setTimezone(new \DateTimeZone('UTC'))->format('Y-m-d H:i:s');

            // Consulta actualizada
            $citasPorUsuarioHoy = $citasTable->find()
                ->select([
                    'user_id',
                    'total' => 'COUNT(*)'
                ])
                ->where([
                    'created_at >=' => $hoyInicioUTC,
                    'created_at <=' => $hoyFinUTC,
                    'campana_id IS NOT' => null
                ])
                ->group('user_id')
                ->contain([
                    'Users' => function ($q) {
                        return $q->select(['id', 'username']);
                    }
                ])
                ->toArray();

            // Citas por estado hoy (solo sin campaña)
            $citasPorEstadoHoy = $citasTable->find()
                ->select([
                    'estado',
                    'total' => 'COUNT(*)'
                ])
                ->where(function ($exp) use ($hoyInicioUTC, $hoyFinUTC) {
                    return $exp
                        ->between('created_at', $hoyInicioUTC, $hoyFinUTC)
                        ->isNotNull('campana_id');
                })
                ->group('estado')
                ->toArray();



            // Citas finalizadas por usuario en el mes actual (solo SIN campaña)
            $citasFinalizadasMensual = $citasTable->find()
                ->select([
                    'user_id',
                    'total' => 'COUNT(*)'
                ])
                ->where([
                    'estado' => 'finalizado',
                    'fecha_hora >=' => $inicioMes,
                    'fecha_hora <=' => $finMes,
                    'campana_id IS NOT' => null
                ])
                ->group('user_id')
                ->contain([
                    'Users' => function ($q) {
                        return $q->select(['id', 'username']);
                    }
                ])
                ->toArray();


            // Clientes nuevos vs frecuentes en el mes
            // Clientes del mes (cliente_facturacion_id únicos)
            $clientesDelMes = $citasTable->find()
                ->select(['cliente_facturacion_id'])
                ->distinct()
                ->where([
                    'fecha_hora >=' => $inicioMes,
                    'fecha_hora <=' => $finMes,
                    'estado' => 'finalizado', // solo los atendidos
                    'cliente_facturacion_id IS NOT' => null,
                ])
                ->enableHydration(false)
                ->toArray();

            $clienteIdsDelMes = array_column($clientesDelMes, 'cliente_facturacion_id');

            // Inicializa en vacío
            $clienteIdsFrecuentes = [];

            if (!empty($clienteIdsDelMes)) {
                // Clientes frecuentes (con citas antes del mes actual y con estado finalizado)
                $clientesFrecuentes = $citasTable->find()
                    ->select(['cliente_facturacion_id'])
                    ->distinct()
                    ->where([
                        'cliente_facturacion_id IN' => $clienteIdsDelMes,
                        'fecha_hora <' => $inicioMes,
                        'estado' => 'finalizado'
                    ])
                    ->enableHydration(false)
                    ->toArray();

                $clienteIdsFrecuentes = array_column($clientesFrecuentes, 'cliente_facturacion_id');
            }

            // Conteos protegidos contra negativos
            $pacientesFrecuentesCount = count($clienteIdsFrecuentes);
            $pacientesNuevos = max(0, count($clienteIdsDelMes) - $pacientesFrecuentesCount);

            // Tiempo promedio entre llegada e inicio de consulta en el mes actual
            $tiempoPromedioLlegadaInicio = $citasTable->find()
                ->select([
                    'avg_diff' => 'AVG(TIMESTAMPDIFF(MINUTE, hora_llegada, hora_inicio_consulta))'
                ])
                ->where([
                    'hora_llegada IS NOT' => null,
                    'hora_inicio_consulta IS NOT' => null,
                    'fecha_hora >=' => $inicioMes,
                    'fecha_hora <=' => $finMes,
                ])
                ->first();

            $promedioMinutos = $tiempoPromedioLlegadaInicio?->avg_diff ?? 0;
            // Total de citas finalizadas por personal en el mes actual
            $citasFinalizadasPorDoctor = $citasTable->find()
                ->select([
                    'personal_id',
                    'doctor_nombre' => 'Personal.nombre',
                    'total' => 'COUNT(*)'
                ])
                ->where([
                    'estado' => 'finalizado',
                    'fecha_hora >=' => $inicioMes,
                    'fecha_hora <=' => $finMes,
                ])
                ->group('personal_id')
                ->leftJoinWith('Personal')
                ->toArray();

            // Citas del día (todas las citas programadas para hoy)
            $citasDelDia = $citasTable->find()
                ->contain([
                    'Personal',
                    'Users'
                ])
                ->where([
                    'DATE(Citas.fecha_hora)' => $today
                ])
                ->order(['Citas.fecha_hora' => 'ASC'])
                ->toArray();

            // Servicios más facturados en el mes seleccionado (cantidad de veces y monto cobrado),
            // basado en las líneas de comprobantes (invoice_items) ya emitidos.
            $invoiceItemsTable = $this->fetchTable('InvoiceItems');
            $serviciosMasFacturados = $invoiceItemsTable->find()
                ->select([
                    'nombre' => 'InvoiceItems.descripcion',
                    'total' => 'COUNT(*)',
                    'monto' => 'SUM(InvoiceItems.total)',
                ])
                ->innerJoinWith('Invoices')
                ->where([
                    'Invoices.created >=' => $inicioMesSeleccionado,
                    'Invoices.created <=' => $finMesSeleccionado,
                    'Invoices.estado !=' => 'ANULADO',
                ])
                ->group('InvoiceItems.descripcion')
                ->orderDesc('total')
                ->enableHydration(false)
                ->toArray();

            // Próximos hitos de proyectos pendientes para los próximos 5 días
            $avancesProyectosTable = $this->fetchTable('AvancesProyectos');
            $fechaHitoEn5Dias = (new \DateTime($today))->modify('+5 days')->format('Y-m-d');
            $avancesProximos5Dias = $avancesProyectosTable->find()
                ->select([
                    'id' => 'AvancesProyectos.id',
                    'fecha_avance' => 'AvancesProyectos.fecha_avance',
                    'proximo_hito' => 'AvancesProyectos.proximo_hito',
                    'seguimiento_titulo' => 'SeguimientosProyectos.titulo',
                    'cliente_facturacion_id' => 'ClientesFacturacion.id',
                    'cliente_nombre' => 'ClientesFacturacion.nombre_razon_social',
                    'cliente_telefono' => 'ClientesFacturacion.telefono',
                ])
                ->leftJoinWith('SeguimientosProyectos.ClientesFacturacion')
                ->where([
                    'AvancesProyectos.estado_control' => 'A',
                    'AvancesProyectos.proximo_hito >=' => $today,
                    'AvancesProyectos.proximo_hito <=' => $fechaHitoEn5Dias,
                ])
                ->order([
                    'SeguimientosProyectos.titulo' => 'ASC',
                ])
                ->enableHydration(false)
                ->toArray();

            // Citas en estado "programar"
            try {
                $citasTable = $this->fetchTable('Citas');
                $citasPorProgramarQuery = $citasTable->find('all')
                    ->contain(['ClientesFacturacion'])
                    ->where(['Citas.estado' => 'programar'])
                    ->order(['Citas.id' => 'DESC'])
                    ->limit(15);

                $citasPorProgramar = $citasPorProgramarQuery->toArray();
            } catch (\Exception $e) {
                $citasPorProgramar = [];
            }

            try {

                $paquetesPagosTable = $this->fetchTable('PaquetesPagos');
                $cuotasTable = $this->fetchTable('PaquetesPagosCuotas');

                $proximos7Dias = (new \DateTime())
                    ->modify('+7 days')
                    ->format('Y-m-d');

                // ==========================
                // PRÓXIMOS 7 DÍAS
                // ==========================

                $containCuotasPago = [
                    'PaquetesPagos' => [
                        'ClientesFacturacion',
                    ]
                ];

                $pagosProximosContado = $paquetesPagosTable->find()
                    ->contain(['ClientesFacturacion'])
                    ->where([
                        'PaquetesPagos.estado' => 'pendiente',
                        'PaquetesPagos.estado_paquete' => 'A',
                        'PaquetesPagos.tipo_pago' => 'contado',
                        'PaquetesPagos.fecha_recordatorio <=' => $proximos7Dias
                    ])
                    ->order(['PaquetesPagos.fecha_recordatorio' => 'ASC'])
                    ->toArray();

                $pagosProximosCuotas = $cuotasTable->find()
                    ->contain($containCuotasPago)
                    ->where([
                        'PaquetesPagosCuotas.estado' => 'pendiente',
                        'PaquetesPagosCuotas.estado_cuota' => 'A',
                        'PaquetesPagos.tipo_pago' => 'partes',
                        'PaquetesPagosCuotas.fecha_recordatorio <=' => $proximos7Dias
                    ])
                    ->order(['PaquetesPagosCuotas.fecha_recordatorio' => 'ASC'])
                    ->toArray();

                $pagosProximosRecurrente = $cuotasTable->find()
                    ->contain($containCuotasPago)
                    ->where([
                        'PaquetesPagosCuotas.estado' => 'pendiente',
                        'PaquetesPagosCuotas.estado_cuota' => 'A',
                        'PaquetesPagos.tipo_pago' => 'recurrente',
                        'PaquetesPagosCuotas.fecha_recordatorio <=' => $proximos7Dias
                    ])
                    ->order(['PaquetesPagosCuotas.fecha_recordatorio' => 'ASC'])
                    ->toArray();

                // ==========================
                // TODOS LOS PENDIENTES
                // ==========================

                $pagosTodosContado = $paquetesPagosTable->find()
                    ->contain(['ClientesFacturacion'])
                    ->where([
                        'PaquetesPagos.estado' => 'pendiente',
                        'PaquetesPagos.estado_paquete' => 'A',
                        'PaquetesPagos.tipo_pago' => 'contado'
                    ])
                    ->order(['PaquetesPagos.fecha_recordatorio' => 'ASC'])
                    ->toArray();

                $pagosTodosCuotas = $cuotasTable->find()
                    ->contain($containCuotasPago)
                    ->where([
                        'PaquetesPagosCuotas.estado' => 'pendiente',
                        'PaquetesPagosCuotas.estado_cuota' => 'A',
                        'PaquetesPagos.tipo_pago' => 'partes'
                    ])
                    ->order(['PaquetesPagosCuotas.fecha_recordatorio' => 'ASC'])
                    ->toArray();

                $pagosTodosRecurrente = $cuotasTable->find()
                    ->contain($containCuotasPago)
                    ->where([
                        'PaquetesPagosCuotas.estado' => 'pendiente',
                        'PaquetesPagosCuotas.estado_cuota' => 'A',
                        'PaquetesPagos.tipo_pago' => 'recurrente'
                    ])
                    ->order(['PaquetesPagosCuotas.fecha_recordatorio' => 'ASC'])
                    ->toArray();
            } catch (\Exception $e) {

                $pagosProximosContado = [];
                $pagosProximosCuotas = [];
                $pagosProximosRecurrente = [];

                $pagosTodosContado = [];
                $pagosTodosCuotas = [];
                $pagosTodosRecurrente = [];
            }

            // Agrupar para la vista
            $recordatoriosPagoProximos = [
                'contado' => $pagosProximosContado,
                'partes' => $pagosProximosCuotas,
                'recurrente' => $pagosProximosRecurrente
            ];

            $recordatoriosPagoTodos = [
                'contado' => $pagosTodosContado,
                'partes' => $pagosTodosCuotas,
                'recurrente' => $pagosTodosRecurrente
            ];

            $this->set(compact(
                'citasPorUsuarioHoy',
                'citasPorEstadoHoy',
                'citasFinalizadasMensual',
                'pacientesNuevos',
                'pacientesFrecuentesCount',
                'promedioMinutos',
                'citasFinalizadasPorDoctor',
                'citasDelDia',
                'serviciosMasFacturados',
                'mesSeleccionado',
                'avancesProximos5Dias',
                'citasPorProgramar',
                'recordatoriosPagoProximos',
                'recordatoriosPagoTodos'
            ));
        }

        $this->set(compact('page', 'subpage'));

        try {
            return $this->render(implode('/', $path));
        } catch (MissingTemplateException $exception) {
            if (Configure::read('debug')) {
                throw $exception;
            }
            throw new NotFoundException();
        }
    }
}
