<?php

namespace App\Services;

use App\Enums\DestinationType;
use App\Exceptions\InsuranceCalculationException;

class JfRateService
{
    private array $rateTables = [
        'non_usa' => [
            '0-65' => [
                '60-64' => 3.80,
                '65-69' => 4.58,
                '70-74' => 7.22,
                '75-79' => 11.42,
                '80-84' => 18.52,
                '85-89' => 23.56,
                '90+' => 28.27,
            ],
            '66-120' => [
                '60-64' => 4.82,
                '65-69' => 5.69,
                '70-74' => 8.71,
                '75-79' => 12.29,
                '80-84' => 19.36,
                '85-89' => 27.75,
                '90+' => 33.31,
            ],
        ],
        'usa' => [
            '0-65' => [
                '60-64' => 4.82,
                '65-69' => 5.81,
                '70-74' => 8.52,
                '75-79' => 13.28,
                '80-84' => 21.60,
                '85-89' => 28.10,
                '90+' => 33.72,
            ],
            '66-120' => [
                '60-64' => 5.04,
                '65-69' => 6.05,
                '70-74' => 8.95,
                '75-79' => 13.61,
                '80-84' => 21.88,
                '85-89' => 29.15,
                '90+' => 34.98,
            ],
        ],
    ];

    public function calculatePremium(int $age, int $days, DestinationType $destination): array
    {
        $this->validateInputs($age, $days, $destination);
        
        $includeUSA = $destination === DestinationType::WORLDWIDE_INCLUDING_USA;
        $tableKey = $includeUSA ? 'usa' : 'non_usa';
        $durationBracket = $days <= 65 ? '0-65' : '66-120';
        
        $dailyRate = $this->findDailyRate($age, $tableKey, $durationBracket);
        $basePremium = $dailyRate * $days;
        
        return [
            'daily_rate' => round($dailyRate, 2),
            'base_premium' => round($basePremium, 2),
            'total_premium' => round($basePremium, 2),
            'destination' => $destination->value,
            'includes_usa' => $includeUSA,
            'plan_type' => 'jf_top',
        ];
    }

    private function findDailyRate(int $age, string $tableKey, string $durationBracket): float
    {
        $ageBrackets = $this->rateTables[$tableKey][$durationBracket] ?? [];
        
        foreach ($ageBrackets as $ageRange => $rate) {
            if ($this->isAgeInRange($age, $ageRange)) {
                return $rate;
            }
        }
        
        throw InsuranceCalculationException::ageNotSupported($age);
    }

    private function isAgeInRange(int $age, string $ageRange): bool
    {
        if ($ageRange === '90+') {
            return $age >= 90;
        }
        
        [$min, $max] = explode('-', $ageRange);
        return $age >= (int)$min && $age <= (int)$max;
    }

    private function validateInputs(int $age, int $days, DestinationType $destination): void
    {
        if ($age < 0 || $age > 120) {
            throw InsuranceCalculationException::ageNotSupported($age);
        }
        
        if ($days < 1 || $days > 365) {
            throw InsuranceCalculationException::durationNotSupported($days);
        }
        
        if ($destination === DestinationType::CANADA) {
            throw InsuranceCalculationException::destinationNotSupported($destination->value);
        }
    }
}