<?php

namespace Koneko\SatCatalogs\Services;

use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Reader\Xls as XlsReader;
use PhpOffice\PhpSpreadsheet\Shared\Date as ExcelDate;
use Carbon\Carbon;

class CsvGeneratorService
{
    private static array $dateColumnsMap = [
        'c_formapago'     => [12, 13],
        'c_moneda'        => [4, 5],
        'c_codigopostal'  => [5, 6],
        'c_regimenfiscal' => [4, 5],
        'c_usocfdi'       => [4, 5],
        'c_claveprodserv' => [5, 6],
        'c_claveunidad'   => [4, 5],
        'c_aduana'        => [2, 3],
        'c_estado'        => [3],
        'c_localidad'     => [3],
        'c_municipio'     => [3],
    ];

    /**
     * Convierte hojas de un XLSX o XLS a un CSV optimizado.
     */
    public static function convertToCsv(string $filePath, $sheetNames, string $csvName, int $skipRows = 7)
    {
        $extension = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
        $reader = ($extension === 'xls') ? new XlsReader() : new XlsxReader();

        try {
            $reader->setReadDataOnly(true);
            $reader->setLoadSheetsOnly($sheetNames);
            $spreadsheet = $reader->load($filePath);
        } catch (\PhpOffice\PhpSpreadsheet\Reader\Exception $e) {
            die("❌ Error al cargar hojas: " . implode(", ", (array) $sheetNames) . "\n");
        }

        $csvPath = database_path("seeders/sat_cache/{$csvName}.csv");
        $handle = fopen($csvPath, 'w');

        if (!$handle) {
            return ["error" => "No se pudo crear el archivo CSV."];
        }

        foreach ((array) $sheetNames as $sheetName) {
            if (!$spreadsheet->sheetNameExists($sheetName)) {
                echo "⚠️ Hoja no encontrada: {$sheetName}, saltando...\n";
                continue;
            }

            $sheet = $spreadsheet->getSheetByName($sheetName);
            if (!$sheet) continue;

            $dateColumns = self::$dateColumnsMap[$csvName] ?? []; // Índices de columnas de fechas

            foreach ($sheet->getRowIterator($skipRows + 1) as $row) {
                $cells = [];
                $colIndex = 0;

                foreach ($row->getCellIterator() as $cell) {
                    $value = trim((string) $cell->getValue());

                    // 🛑 Omitir filas con "Continúa en..."
                    if (str_starts_with($value, 'Continúa en ')) {
                        echo "⚠️ Fila omitida: {$value}\n";
                        continue 2; // Salta toda la fila
                    }

                    // 🔥 Convertir "?" y valores vacíos a NULL
                    if ($value === '?' || $value === '') {
                        $value = '';
                    }

                    // 📅 Si es fecha de Excel, convertir a YYYY-MM-DD
                    if (in_array($colIndex, $dateColumns) && self::isExcelDate($value)) {
                        $value = self::convertExcelDate($value);
                    }

                    // 🔹 Escapar valores que contienen punto y coma, saltos de línea o comillas
                    $value = self::escapeCsvValue($value);

                    $cells[] = $value;
                    $colIndex++;
                }

                if (self::isEmptyRow($cells)) {
                    echo "⚠️ Fila vacía detectada y omitida\n";
                    continue;
                }

                fputcsv($handle, $cells, ';'); // 💡 Asegura que los valores se escapen correctamente
            }
        }

        fclose($handle);
        $spreadsheet->disconnectWorksheets();
        unset($spreadsheet);

        return $csvPath;
    }

    /**
     * **Detecta si el valor es un número de fecha de Excel**
     */
    private static function isExcelDate($value): bool
    {
        return is_numeric($value) && $value > 10000;
    }

    /**
     * **Convierte un número de fecha de Excel a formato YYYY-MM-DD**
     */
    private static function convertExcelDate($value): string
    {
        try {
            return Carbon::instance(ExcelDate::excelToDateTimeObject($value))->format('Y-m-d');
        } catch (\Exception $e) {
            return $value;
        }
    }

    /**
     * **Escapa valores con punto y coma, comillas o saltos de línea en CSV**
     */
    private static function escapeCsvValue($value): string
    {
        // Si el valor contiene punto y coma, salto de línea o comillas dobles, se escapa
        if (strpbrk($value, ";\"\n")) {
            $value = '"' . str_replace('"', '""', $value) . '"'; // Duplicar comillas internas
        }
        return $value;
    }

    /**
     * **Verifica si una fila está vacía o contiene valores inválidos.**
     */
    private static function isEmptyRow(array $cells): bool
    {
        $empty = empty(array_filter($cells, fn($cell) => $cell !== ''));

        if ($empty) {
            echo "⚠️ Fila detectada como vacía y omitida\n";
        }

        return $empty;
    }

    /**
     * **Cuenta las filas de un archivo CSV.**
     */
    public static function countCsvRows(string $csvPath): int
    {
        if (!file_exists($csvPath)) {
            return 0;
        }

        $file = fopen($csvPath, 'r');
        $count = 0;

        while (fgetcsv($file, 0, ';') !== false) {
            $count++;
        }

        fclose($file);
        return $count;
    }
}
