<?php

namespace App\Domains\Sale\Services;

use App\Domains\Logging\Models\ValueChange;
use App\Domains\Purchase\Models\Purchase;
use App\Domains\Tenant\Models\Tenant;
use Illuminate\Support\Collection;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use Symfony\Component\HttpFoundation\StreamedResponse;

class AdminAppSaleExcelService
{
    /** @param Collection<int, Purchase> $sales */
    public function downloadSales(Tenant $tenant, Collection $sales, string $timeZone): StreamedResponse
    {
        $generatedAt = now();
        $spreadsheet = $this->spreadsheet($tenant, 'Historial de ventas');
        $sheet = $spreadsheet->getActiveSheet();
        $sheet->setTitle('Ventas');
        $sheet->fromArray([
            'ID',
            'Fecha',
            'Cliente',
            'Cantidad',
            'Estado',
            'Importe',
            'Tickets',
        ], null, 'A1');

        foreach ($sales->values() as $index => $sale) {
            $row = $index + 2;
            $sheet->setCellValueExplicit("A{$row}", '#'.$sale->id, DataType::TYPE_STRING);
            if ($sale->created_at) {
                $sheet->setCellValue(
                    "B{$row}",
                    Date::dateTimeToExcel($sale->created_at->copy()->timezone($timeZone)),
                );
            }
            $sheet->setCellValueExplicit(
                "C{$row}",
                $sale->nombre_apellido ?: 'Sin nombre',
                DataType::TYPE_STRING,
            );
            $sheet->setCellValue("D{$row}", (int) ($sale->quantity ?? 0));
            $sheet->setCellValue("E{$row}", $this->saleStatus($sale->status));
            $sheet->setCellValue("F{$row}", (float) $sale->total);
            $sheet->setCellValue("G{$row}", (int) ($sale->tickets_count ?? 0));
        }

        $lastRow = max(2, $sales->count() + 1);
        $sheet->getStyle("B2:B{$lastRow}")->getNumberFormat()->setFormatCode('dd/mm/yyyy hh:mm');
        $sheet->getStyle("F2:F{$lastRow}")->getNumberFormat()->setFormatCode('$ #,##0.00');
        $this->formatSheet($spreadsheet, 'A1:G1', "A1:G{$lastRow}", [
            'A' => 13,
            'B' => 20,
            'C' => 32,
            'D' => 12,
            'E' => 22,
            'F' => 16,
            'G' => 12,
        ]);

        return $this->download(
            $spreadsheet,
            'ventas_'.$tenant->codigo.'_'
                .$generatedAt->copy()->timezone($timeZone)->format('Ymd_His').'.xlsx',
        );
    }

    /** @param Collection<int, ValueChange> $modifications */
    public function downloadModifications(
        Tenant $tenant,
        Collection $modifications,
        string $timeZone,
    ): StreamedResponse {
        $generatedAt = now();
        $spreadsheet = $this->spreadsheet($tenant, 'Historial de modificaciones de ventas');
        $sheet = $spreadsheet->getActiveSheet();
        $sheet->setTitle('Modificaciones');
        $sheet->fromArray([
            'Fecha',
            'Hora',
            'Venta',
            'Cliente',
            'Campo',
            'Valor anterior',
            'Valor nuevo',
            'Modificado por',
        ], null, 'A1');

        foreach ($modifications->values() as $index => $modification) {
            $row = $index + 2;
            $changedAt = $modification->changed_at->copy()->timezone($timeZone);
            $sale = $modification->trackable;
            $sheet->setCellValue("A{$row}", Date::dateTimeToExcel($changedAt));
            $sheet->setCellValue("B{$row}", Date::dateTimeToExcel($changedAt));
            $sheet->setCellValueExplicit(
                "C{$row}",
                '#'.$modification->trackable_id,
                DataType::TYPE_STRING,
            );
            $sheet->setCellValueExplicit(
                "D{$row}",
                $sale?->nombre_apellido ?: 'Sin nombre',
                DataType::TYPE_STRING,
            );
            $sheet->setCellValueExplicit(
                "E{$row}",
                $modification->attribute,
                DataType::TYPE_STRING,
            );
            $sheet->setCellValueExplicit(
                "F{$row}",
                $modification->old_value ?? '-',
                DataType::TYPE_STRING,
            );
            $sheet->setCellValueExplicit(
                "G{$row}",
                $modification->new_value ?? '-',
                DataType::TYPE_STRING,
            );
            $sheet->setCellValueExplicit(
                "H{$row}",
                $modification->user?->nombre_apellido ?? 'Sistema',
                DataType::TYPE_STRING,
            );
        }

        $lastRow = max(2, $modifications->count() + 1);
        $sheet->getStyle("A2:A{$lastRow}")->getNumberFormat()->setFormatCode('dd/mm/yyyy');
        $sheet->getStyle("B2:B{$lastRow}")->getNumberFormat()->setFormatCode('hh:mm:ss');
        $this->formatSheet($spreadsheet, 'A1:H1', "A1:H{$lastRow}", [
            'A' => 14,
            'B' => 12,
            'C' => 13,
            'D' => 32,
            'E' => 20,
            'F' => 24,
            'G' => 24,
            'H' => 28,
        ]);

        return $this->download(
            $spreadsheet,
            'historial_modificaciones_'.$tenant->codigo.'_'
                .$generatedAt->copy()->timezone($timeZone)->format('Ymd_His').'.xlsx',
        );
    }

    private function spreadsheet(Tenant $tenant, string $title): Spreadsheet
    {
        $spreadsheet = new Spreadsheet;
        $spreadsheet->getProperties()
            ->setCreator('Shopit')
            ->setTitle($title)
            ->setSubject($tenant->nombre);

        return $spreadsheet;
    }

    /** @param array<string, int> $widths */
    private function formatSheet(
        Spreadsheet $spreadsheet,
        string $headerRange,
        string $filterRange,
        array $widths,
    ): void {
        $sheet = $spreadsheet->getActiveSheet();
        $sheet->getStyle($headerRange)->applyFromArray([
            'font' => ['bold' => true, 'color' => ['rgb' => 'FFFFFF']],
            'fill' => [
                'fillType' => Fill::FILL_SOLID,
                'startColor' => ['rgb' => '26382E'],
            ],
            'alignment' => ['vertical' => Alignment::VERTICAL_CENTER],
        ]);
        $sheet->getRowDimension(1)->setRowHeight(24);
        $sheet->freezePane('A2');
        $sheet->setAutoFilter($filterRange);

        foreach ($widths as $column => $width) {
            $sheet->getColumnDimension($column)->setWidth($width);
        }
    }

    private function download(Spreadsheet $spreadsheet, string $filename): StreamedResponse
    {
        return response()->streamDownload(function () use ($spreadsheet): void {
            (new Xlsx($spreadsheet))->save('php://output');
            $spreadsheet->disconnectWorksheets();
        }, $filename, [
            'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        ]);
    }

    private function saleStatus(string $status): string
    {
        return match ($status) {
            Purchase::STATUS_PAID => 'Confirmado',
            Purchase::STATUS_CREATED => 'Por completar datos',
            Purchase::STATUS_PENDING_PAYMENT, Purchase::STATUS_IN_REVIEW => 'Esperando pago',
            default => 'Anulado',
        };
    }
}
