<?php

namespace Daniv04\HaciendaPackage\Services;

use Carbon\Carbon;

class KeyGeneratorService
{
    public function generateSecurityCode(?string $seed = null): string
    {
        if ($seed === null) {
            $seed = uniqid('', true) . microtime(true) . bin2hex(random_bytes(16));
        }

        $hash = hash('sha256', $seed);
        $digits = preg_replace('/[^0-9]/', '', $hash);

        if (strlen($digits) >= 8) {
            return substr($digits, 0, 8);
        }

        // Pad with random digits if not enough
        while (strlen($digits) < 8) {
            $digits .= random_int(0, 9);
        }

        return substr($digits, 0, 8);
    }

    public function generateConsecutiveKey(
        string $typeCode,
        string $consecutive,
        string $establishment,
        string $terminal
    ): string {
        $establishment = (int) $establishment;
        $terminal = (int) $terminal;
        $consecutive = (int) $consecutive;

        if ($establishment < 1 || $establishment > 999) {
            throw new \InvalidArgumentException('Establishment must be between 1 and 999');
        }
        if ($terminal < 1 || $terminal > 99999) {
            throw new \InvalidArgumentException('Terminal must be between 1 and 99999');
        }
        if ($consecutive < 1 || $consecutive > 9999999999) {
            throw new \InvalidArgumentException('Consecutive must be between 1 and 9999999999');
        }

        return str_pad($establishment, 3, '0', STR_PAD_LEFT) .
               str_pad($terminal, 5, '0', STR_PAD_LEFT) .
               $typeCode .
               str_pad($consecutive, 10, '0', STR_PAD_LEFT);
    }

    public function formatIdentificationNumber(string $identificationNumber, string $type): string
    {
        $cleanNumber = preg_replace('/[^0-9]/', '', $identificationNumber);

        return match ($type) {
            '01' => str_pad($cleanNumber, 12, '0', STR_PAD_LEFT),     // Física
            '02' => str_pad($cleanNumber, 12, '0', STR_PAD_LEFT),     // Jurídica
            '03' => strlen($cleanNumber) === 11                       // DIMEX
                ? '0' . $cleanNumber
                : $cleanNumber,
            '04' => str_pad($cleanNumber, 12, '0', STR_PAD_LEFT),     // NITE
            default => str_pad($cleanNumber, 12, '0', STR_PAD_LEFT),
        };
    }

    public function generateUniqueKey(
        array $dateParsed,
        string $emisorID,
        string $idType,
        string $consecutive,
        string $situation,
        string $securityCode
    ): string {
        $day = str_pad($dateParsed['day'], 2, '0', STR_PAD_LEFT);
        $month = str_pad($dateParsed['month'], 2, '0', STR_PAD_LEFT);
        $year = str_pad($dateParsed['year'], 2, '0', STR_PAD_LEFT);

        $formattedID = $this->formatIdentificationNumber($emisorID, $idType);

        return '506' .
               $day .
               $month .
               $year .
               $formattedID .
               $consecutive .
               $situation .
               $securityCode;
    }

    public function parseDateToArray(string $dateTime): array
    {
        $date = Carbon::createFromFormat('Y-m-d', substr($dateTime, 0, 10));

        if (!$date) {
            throw new \InvalidArgumentException("Invalid date format: {$dateTime}");
        }

        return [
            'day' => $date->format('d'),
            'month' => $date->format('m'),
            'year' => $date->format('y'),
        ];
    }
}
