<?php

namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromArray;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\WithTitle;
use Maatwebsite\Excel\Events\AfterSheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Style\Fill;

/**
 * Punto 3 — Export Excel del reporte "Ingresos Efectuados a Empleados".
 *
 * Columnas: Código | Nombre del Empleado | Valor del Ingreso
 * Por cada concepto (ALIMENTACION, VIATICOS, etc.) se emite subhead, filas
 * y fila TOTAL del concepto. Al final, una fila TOTAL INGRESOS general.
 */
class IncomesReportExport implements FromArray, WithTitle, WithEvents
{
    protected array $groups;
    protected float $grandTotal;
    protected $company;
    protected array $dateRange;

    /** Filas calculadas para emitir el sheet. */
    protected array $sheetRows = [];

    /** Mapas auxiliares para estilos en AfterSheet. */
    protected array $titleRows = [];     // filas con título (empresa, fecha)
    protected array $subheadRows = [];   // filas con nombre de concepto
    protected array $headerRows = [];    // filas de cabecera (Código | Nombre | Valor)
    protected array $totalRows = [];     // filas con subtotal por concepto
    protected int $grandTotalRow = 0;
    protected int $generatedRow = 0;

    public function __construct(array $groups, float $grandTotal, $company, array $dateRange)
    {
        $this->groups     = $groups;
        $this->grandTotal = $grandTotal;
        $this->company    = $company;
        $this->dateRange  = $dateRange;

        $this->buildRows();
    }

    public function title(): string
    {
        return 'Ingresos';
    }

    public function array(): array
    {
        return $this->sheetRows;
    }

    /**
     * Construye filas y guarda índices (1-based) para aplicar estilos luego.
     */
    private function buildRows(): void
    {
        $companyName = $this->resolveCompanyName();

        // Fila 1: Empresa.
        $this->sheetRows[] = [$companyName, '', ''];
        $this->titleRows[] = 1;

        // Fila 2: subtítulo de ingresos.
        $this->sheetRows[] = ['Ingresos Efectuados a Empleados', '', ''];
        $this->titleRows[] = 2;

        // Fila 3: rango de fechas.
        $this->sheetRows[] = [$this->dateRange['label'] ?? '', '', ''];
        $this->titleRows[] = 3;

        // Fila 4: vacía.
        $this->sheetRows[] = ['', '', ''];

        foreach ($this->groups as $group) {
            // Subhead concepto.
            $this->sheetRows[] = [$group['name'], '', ''];
            $this->subheadRows[] = count($this->sheetRows);

            // Cabecera tabla.
            $this->sheetRows[] = ['Código', 'Nombre del Empleado', 'Valor del Ingreso'];
            $this->headerRows[] = count($this->sheetRows);

            // Filas de empleados.
            foreach ($group['rows'] as $r) {
                $this->sheetRows[] = [
                    (string) ($r['code'] ?? ''),
                    (string) ($r['employee'] ?? ''),
                    (float) ($r['amount'] ?? 0),
                ];
            }

            // Total del concepto.
            $this->sheetRows[] = [
                'TOTAL ' . $group['name'],
                '',
                (float) ($group['subtotal'] ?? 0),
            ];
            $this->totalRows[] = count($this->sheetRows);

            // Vacía separador.
            $this->sheetRows[] = ['', '', ''];
        }

        // Total general.
        $this->sheetRows[] = ['TOTAL INGRESOS', '', $this->grandTotal];
        $this->grandTotalRow = count($this->sheetRows);

        // Vacía + fecha de generación.
        $this->sheetRows[] = ['', '', ''];
        $this->sheetRows[] = ['Generado: ' . now()->format('d/m/Y H:i:s'), '', ''];
        $this->generatedRow = count($this->sheetRows);
    }

    private function resolveCompanyName(): string
    {
        if (is_object($this->company) && isset($this->company->name)) {
            return mb_strtoupper((string) $this->company->name);
        }
        return 'EMPRESA';
    }

    public function registerEvents(): array
    {
        return [
            AfterSheet::class => function (AfterSheet $event) {
                $sheet = $event->sheet->getDelegate();

                // Anchos de columna.
                $sheet->getColumnDimension('A')->setWidth(15);
                $sheet->getColumnDimension('B')->setWidth(40);
                $sheet->getColumnDimension('C')->setWidth(18);

                // Títulos (3 filas).
                foreach ($this->titleRows as $i => $row) {
                    $sheet->mergeCells("A{$row}:C{$row}");
                    $sheet->getStyle("A{$row}")->applyFromArray([
                        'font'      => ['bold' => true, 'size' => $i === 0 ? 14 : 11],
                        'alignment' => [
                            'horizontal' => Alignment::HORIZONTAL_CENTER,
                            'vertical'   => Alignment::VERTICAL_CENTER,
                        ],
                    ]);
                    $sheet->getRowDimension($row)->setRowHeight($i === 0 ? 26 : 18);
                }

                // Subheads (concepto).
                foreach ($this->subheadRows as $row) {
                    $sheet->mergeCells("A{$row}:C{$row}");
                    $sheet->getStyle("A{$row}")->applyFromArray([
                        'font'      => ['bold' => true, 'size' => 11],
                        'fill'      => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => 'D9E1F2']],
                        'alignment' => ['horizontal' => Alignment::HORIZONTAL_LEFT, 'vertical' => Alignment::VERTICAL_CENTER],
                    ]);
                    $sheet->getRowDimension($row)->setRowHeight(20);
                }

                // Cabeceras tabla.
                foreach ($this->headerRows as $row) {
                    $sheet->getStyle("A{$row}:C{$row}")->applyFromArray([
                        'font'      => ['bold' => true, 'size' => 10, 'color' => ['rgb' => 'FFFFFF']],
                        'fill'      => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => '2E3A59']],
                        'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER],
                        'borders'   => ['allBorders' => ['borderStyle' => Border::BORDER_THIN]],
                    ]);
                }

                // Totales por concepto.
                foreach ($this->totalRows as $row) {
                    $sheet->mergeCells("A{$row}:B{$row}");
                    $sheet->getStyle("A{$row}:C{$row}")->applyFromArray([
                        'font'      => ['bold' => true, 'size' => 10],
                        'fill'      => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => 'FCE4D6']],
                        'borders'   => ['allBorders' => ['borderStyle' => Border::BORDER_THIN]],
                    ]);
                    $sheet->getStyle("A{$row}")->getAlignment()->setHorizontal(Alignment::HORIZONTAL_RIGHT);
                    $sheet->getStyle("C{$row}")->getAlignment()->setHorizontal(Alignment::HORIZONTAL_RIGHT);
                    $sheet->getStyle("C{$row}")->getNumberFormat()->setFormatCode('#,##0.00');
                }

                // Gran total.
                if ($this->grandTotalRow) {
                    $row = $this->grandTotalRow;
                    $sheet->mergeCells("A{$row}:B{$row}");
                    $sheet->getStyle("A{$row}:C{$row}")->applyFromArray([
                        'font'      => ['bold' => true, 'size' => 11],
                        'fill'      => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => 'DAEEF3']],
                        'borders'   => ['allBorders' => ['borderStyle' => Border::BORDER_MEDIUM]],
                    ]);
                    $sheet->getStyle("A{$row}")->getAlignment()->setHorizontal(Alignment::HORIZONTAL_RIGHT);
                    $sheet->getStyle("C{$row}")->getAlignment()->setHorizontal(Alignment::HORIZONTAL_RIGHT);
                    $sheet->getStyle("C{$row}")->getNumberFormat()->setFormatCode('#,##0.00');
                }

                // Fila "Generado".
                if ($this->generatedRow) {
                    $row = $this->generatedRow;
                    $sheet->getStyle("A{$row}")->applyFromArray([
                        'font' => ['italic' => true, 'size' => 8, 'color' => ['rgb' => '808080']],
                    ]);
                }

                // Formato dinero en filas de datos (todas las filas de C que no son header/subhead/title)
                $this->applyDataMoneyFormat($sheet);

                // Bordes en filas de datos.
                $this->applyDataBorders($sheet);

                // Configuración de impresión.
                $sheet->getPageSetup()->setOrientation(\PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::ORIENTATION_PORTRAIT);
                $sheet->getPageSetup()->setPaperSize(\PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::PAPERSIZE_LETTER);
                $sheet->getPageSetup()->setFitToWidth(1);
                $sheet->getPageSetup()->setFitToHeight(0);
                $sheet->getPageMargins()->setTop(0.5);
                $sheet->getPageMargins()->setBottom(0.5);
                $sheet->getPageMargins()->setLeft(0.5);
                $sheet->getPageMargins()->setRight(0.5);
            },
        ];
    }

    /**
     * Aplica formato dinero a celdas C en filas de datos.
     */
    protected function applyDataMoneyFormat($sheet): void
    {
        $skip = array_merge(
            $this->titleRows,
            $this->subheadRows,
            $this->headerRows,
            $this->totalRows,
            [$this->grandTotalRow, $this->generatedRow]
        );

        $totalRows = count($this->sheetRows);
        for ($r = 1; $r <= $totalRows; $r++) {
            if (in_array($r, $skip, true)) {
                continue;
            }
            // Solo aplicar si C tiene un número.
            $val = $sheet->getCell("C{$r}")->getValue();
            if (is_numeric($val)) {
                $sheet->getStyle("C{$r}")->getNumberFormat()->setFormatCode('#,##0.00');
                $sheet->getStyle("C{$r}")->getAlignment()->setHorizontal(Alignment::HORIZONTAL_RIGHT);
            }
        }
    }

    /**
     * Aplica bordes finos a celdas en filas de datos.
     */
    protected function applyDataBorders($sheet): void
    {
        $skip = array_merge(
            $this->titleRows,
            $this->subheadRows,
            $this->totalRows,
            [$this->grandTotalRow, $this->generatedRow]
        );

        $totalRows = count($this->sheetRows);
        for ($r = 1; $r <= $totalRows; $r++) {
            if (in_array($r, $skip, true)) {
                continue;
            }
            if (in_array($r, $this->headerRows, true)) {
                continue; // ya tienen bordes
            }
            $val = $sheet->getCell("A{$r}")->getValue();
            if ($val === null || $val === '') {
                continue; // separador
            }
            $sheet->getStyle("A{$r}:C{$r}")->applyFromArray([
                'borders' => ['allBorders' => ['borderStyle' => Border::BORDER_THIN, 'color' => ['rgb' => 'CCCCCC']]],
            ]);
        }
    }
}
