<?php

namespace App\Controllers;

use App\Models\Procedure;
use App\Models\Setting;
use App\Models\State;
use App\Services\ProcessService;
use App\Services\SearchValidator;
use App\Services\UserService;
use DateTime;
use Dompdf\Dompdf;
use Exception;
use IntlDateFormatter;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Style\Alignment;

class ReportController extends BaseController
{

    protected ProcessService $processService;

    public function __construct() {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }

        $this->processService = new ProcessService();
    }

    public function generate()
    {
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            header("Location: " . BASE_HEADER . "search");
            exit;
        }

        $export_type = $_POST['export_type'] ?? 'pdf';
        $filters = [];
        $processes = null;
        $derivation_results = null;
        $state_results_grouped = null;

        if (!empty($_POST['search_type'])) {
            $search_type = $_POST['search_type'];

            switch ($search_type) {
                case 'name':
                    $filters = SearchValidator::validateNameSearch($_POST);
                    $processes = $this->processService->searchByName($filters);
                    break;

                case 'dni':
                    $filters = SearchValidator::validateDniSearch($_POST);
                    $processes = $this->processService->searchByDni($filters);
                    break;

                case 'dates':
                    $filters = SearchValidator::validateDateRangeSearch($_POST);
                    $processes = $this->processService->searchByDateRange($filters);
                    break;

                case 'priority':
                    $filters = SearchValidator::validatePrioritySearch($_POST);
                    $processes = $this->processService->searchByPriority($filters);
                    break;

                case 'procedure':
                    $filters = SearchValidator::validateProcedureSearch($_POST);
                    $processes = $this->processService->searchByProcedure($filters);
                    break;

                case 'derivados':
                    $filters = SearchValidator::validateDerivationSearch($_POST);
                    $derivation_results = $this->processService->searchByDerivationDate($filters);
                    break;
                
                case 'state':
                    $role = $_SESSION['role'];
                    $isAdmin = $role === 'ADMIN';

                    if (!$isAdmin) {
                        $_POST['group_id'] = UserService::getUser()->group_id;
                        $_POST['subgroup_id'] = UserService::getUser()->subgroup_id;
                    }

                    $filters = SearchValidator::validateStateSearch($_POST, $isAdmin);
                    $state_results = $this->processService->searchByState($filters);
                    $state_results_grouped = $this->processService->groupStateResultsByHierarchy($state_results);
                    break;

                case 'process_number':
                    $filters = SearchValidator::validateProcessNumberSearch($_POST);
                    $processes = $this->processService->searchByProcessNumber($filters);
                    break;

                default:
                    $this->setErrorAndRedirect("Error: Tipo de búsqueda no válido.");
            }
        }

        $report_title = $this->buildReportTitle($search_type, $filters);

        if ($export_type === 'excel') {
            $this->generateExcel($processes, $derivation_results, $state_results_grouped, $filters, $search_type, $report_title);
        } else {
            $this->generatePdf($processes, $derivation_results, $state_results_grouped, $filters, $search_type, $report_title);
        }
    }

    private function generatePdf($processes, $derivation_results, $state_results, $filters, $search_type, $report_title)
    {
        $nombreAnio = Setting::getYearName();
        
        ob_start();
        include __DIR__ . '/../Views/reports/pdf-report.php';
        $html = ob_get_clean();

        $dompdf = new Dompdf();
        $dompdf->loadHtml($html);
        $dompdf->setPaper('A4', 'landscape'); 
        $dompdf->render();
        $dompdf->stream("reporte.pdf", ["Attachment" => false]); 
        exit;
    }


    private function generateExcel($processes, $derivation_results, $state_results, $filters, $search_type, $report_title)
    {
        $spreadsheet = new Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();
        
        $sheet->setCellValue('A1', $report_title);
        $sheet->mergeCells('A1:I1');
        $sheet->getStyle('A1')->getFont()->setBold(true)->setSize(14);

        $row = 3;
        
        $headerFillColor = 'BDD7EE'; 
        $headerStyle = [
            'font' => ['bold' => true],
            'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER],
            'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => $headerFillColor]],
            'borders' => ['allBorders' => ['borderStyle' => Border::BORDER_THIN]],
        ];

        $cellStyle = [
            'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER],
            'borders' => ['allBorders' => ['borderStyle' => Border::BORDER_THIN]],
        ];

        if (!empty($processes)) {
            $headers = ['#', 'Expediente', 'Administrado', 'DNI', 'Procedimiento', 'Asunto', 'Folios', 'Estado', 'Fecha'];
            $colLetters = range('A', 'I');
        } elseif (!empty($derivation_results)) {
            $headers = ['#', 'Expediente', 'Administrado', 'DNI', 'Procedimiento', 'Asunto', 'Fecha de derivación', 'Derivado a'];
            $colLetters = range('A', 'H');
        }

        if (!empty($headers)) {
            foreach ($headers as $i => $title) {
                $col = $colLetters[$i];
                $sheet->setCellValue($col . $row, $title);
            }
            $sheet->getStyle("{$colLetters[0]}{$row}:" . end($colLetters) . $row)->applyFromArray($headerStyle);
            $row++;
        }

        if (!empty($processes)) {
            foreach ($processes as $index => $p) {
                $sheet->setCellValue("A{$row}", $index + 1);
                $sheet->setCellValue("B{$row}", $p->num_exped);
                $sheet->setCellValue("C{$row}", $p->user()->name . ' ' . $p->user()->paternal_surname . ' ' . $p->user()->maternal_surname);
                $sheet->setCellValue("D{$row}", $p->user()->dni);
                $sheet->setCellValue("E{$row}", $p->procedure()->description ?? 'Sin procedimiento');
                $sheet->setCellValue("F{$row}", $p->subject);
                $sheet->setCellValue("G{$row}", $p->folios);
                $sheet->setCellValue("H{$row}", $p->general_state);
                $sheet->setCellValue("I{$row}", date('d/m/Y', strtotime($p->entry_date)));
                $sheet->getStyle("A{$row}:I{$row}")->applyFromArray($cellStyle);
                $row++;
            }
        } elseif (!empty($derivation_results)) {
            foreach ($derivation_results as $index => $d) {
                $sheet->setCellValue("A{$row}", $index + 1);
                $sheet->setCellValue("B{$row}", $d['num_exped']);
                $sheet->setCellValue("C{$row}", $d['user_name']);
                $sheet->setCellValue("D{$row}", $d['user_dni']);
                $sheet->setCellValue("E{$row}", $d['procedure_description'] ?? 'Sin procedimiento');
                $sheet->setCellValue("F{$row}", $d['subject']);
                $sheet->setCellValue("G{$row}", date('d/m/Y', strtotime($d['derived_date'])));
                $sheet->setCellValue("H{$row}", $d['subgroup_name'] ?? $d['group_name'] ?? 'N/A');
                $sheet->getStyle("A{$row}:H{$row}")->applyFromArray($cellStyle);
                $row++;
            }
        } 

        elseif (!empty($state_results)) {
            foreach ($state_results as $area => $grupos) {
                $sheet->setCellValue("A{$row}", "Área: $area");
                $sheet->getStyle("A{$row}")->getFont()->setBold(true)->setSize(12);
                $row++;
        
                foreach ($grupos as $grupo => $subgrupos) {
                    $sheet->setCellValue("A{$row}", "Grupo: $grupo");
                    $sheet->getStyle("A{$row}")->getFont()->setBold(true);
                    $row++;
        
                    foreach ($subgrupos as $subgrupo => $items) {
                        $tituloSubgrupo = $subgrupo !== 'default' ? "Subgrupo: $subgrupo" : "Sin subgrupo";
                        $sheet->setCellValue("A{$row}", $tituloSubgrupo);
                        $sheet->getStyle("A{$row}")->getFont()->setBold(true)->setItalic(true);
                        $row++;
        
                        // Encabezados
                        $headers = ['#', 'Expediente', 'Asunto', 'Fecha de entrada', 'Días transcurridos', 'Estado'];
                        $colLetters = range('A', 'F');
                        foreach ($headers as $i => $title) {
                            $col = $colLetters[$i];
                            $sheet->setCellValue($col . $row, $title);
                        }
                        $sheet->getStyle("{$colLetters[0]}{$row}:" . end($colLetters) . $row)->applyFromArray($headerStyle);
                        $row++;
        
                        foreach ($items as $index => $item) {
                            $sheet->setCellValue("A{$row}", $index + 1);
                            $sheet->setCellValue("B{$row}", $item['expediente']);
                            $sheet->setCellValue("C{$row}", $item['asunto']);
                            $sheet->setCellValue("D{$row}", date('d/m/Y', strtotime($item['fecha_ingreso'])));
                            $sheet->setCellValue("E{$row}", $item['dias_transcurridos']);
                            $sheet->setCellValue("F{$row}", $item['estado']);
                            $sheet->getStyle("A{$row}:F{$row}")->applyFromArray($cellStyle);
                            $row++;
                        }
        
                        $row++; // espacio entre subgrupos
                    }
        
                    $row++; // espacio entre grupos
                }
        
                $row++; // espacio entre áreas
            }
        }        
        
        else {
            $sheet->setCellValue("A{$row}", 'No se encontraron resultados.');
        }

        foreach ($colLetters as $col) {
            $sheet->getColumnDimension($col)->setAutoSize(true);
        }

        $writer = new Xlsx($spreadsheet);

        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        header('Content-Disposition: attachment; filename="reporte.xlsx"');
        header('Cache-Control: max-age=0');

        $writer->save('php://output');
        exit;
    }



    private function setErrorAndRedirect(string $message): void
    {
        $_SESSION['message'] = $message;
        $_SESSION['message_type'] = 'danger';
        header("Location: " . BASE_HEADER . "search");
        exit;
    }

    private function buildReportTitle(string $searchType, array $filters): string
    {
        switch ($searchType) {
            case 'name':
                return 'Trámites del usuario: ' . 
                    $filters['paternal_surname'] . ' ' . 
                    $filters['maternal_surname'] . ', ' . 
                    $filters['name'];

            case 'dni':
                return 'Trámites con DNI: ' . $filters['dni'];

            case 'dates':
                $from = date('d/m/Y', strtotime($filters['start_date']));
                $to = date('d/m/Y', strtotime($filters['end_date']));
                return "Trámites registrados entre $from y $to";

            case 'priority':
                $state = State::find($filters['priority']);
                return 'Trámites con prioridad: ' . ($state ? $state->description : 'Desconocida');

            case 'procedure':
                $procedure = Procedure::find($filters['procedure_id']);
                return 'Trámites del procedimiento: ' . ($procedure ? $procedure->description : 'Desconocido');

            case 'derivados':
                switch ($filters['grouping_type']) {
                    case 'day':
                        $day = date('d/m/Y', strtotime($filters['day_date']));
                        return "Derivaciones del día: $day";
                    case 'month':
                        $monthDate = DateTime::createFromFormat('!m', $filters['month']);
                        $formatter = new IntlDateFormatter(
                            'es_ES', 
                            IntlDateFormatter::LONG, 
                            IntlDateFormatter::NONE, 
                            null,
                            null,
                            'LLLL'
                        );

                        $monthName = $formatter->format($monthDate);
                        return "Derivaciones de: $monthName del {$filters['month_year']}";
                    case 'year':
                        return "Derivaciones del año: {$filters['year']}";
                    case 'period':
                        return "Derivaciones del período: {$filters['period']}";
                    default:
                        return 'Reporte de Trámites Derivados';
                }
            
            case 'state':
                $state = $filters['state'] ?? '';
                if ($state === '') {
                    return 'Trámites por estado';
                } else {
                    return 'Trámites por estado: ' . strtoupper($state);
                }

            case 'process_number':
                return 'Detalle del trámite N°: ' . $filters['num_exped'];
                
            default:
                return 'Reporte de Trámites';
        }
    }
}