<?php

namespace App\Services\Achievements\Checkers;

use App\Models\Continent;
use App\Models\User;
use App\Models\UserFlight;
use Illuminate\Support\Collection;

class CountriesAndContinentsChecker extends BaseChecker
{
    private const INHABITED_CONTINENTS = [
        'africa', 'asia', 'europe', 'north_america', 'oceania', 'south_america',
    ];

    public function check(): void
    {
        $flights = $this->flights();
        // Resolve internal_name → id once, used throughout
        $continents = Continent::pluck('id', 'internal_name');

        $arrivalContinentIds = $flights->pluck('arrivalAirport.region.continent_id')->unique();

        $has = fn(string $name) => $arrivalContinentIds->contains($continents[$name]);

        // --- Simple "fly to X continent" achievements ---

        $this->awardIf(
            $flights->contains(fn(UserFlight $f) =>
                $f->departureAirport->region->continent_id !== $f->arrivalAirport->region->continent_id
            ),
            'countries_continents.intercontinental'
        );

        $this->awardIf($has('africa'),        'countries_continents.fly_to_africa');
        $this->awardIf($has('asia'),          'countries_continents.fly_to_asia');
        $this->awardIf($has('oceania'),       'countries_continents.fly_to_oceania');
        $this->awardIf($has('antarctica'),    'countries_continents.fly_to_antarctica');
        $this->awardIf($has('europe'),        'countries_continents.fly_to_europe');
        $this->awardIf($has('south_america'), 'countries_continents.fly_to_south_america');
        $this->awardIf($has('north_america'), 'countries_continents.fly_to_north_america');

        // --- All inhabited continents ---

        $inhabitedIds = collect(self::INHABITED_CONTINENTS)->map(fn($name) => $continents[$name]);

        $visitedInhabited = $arrivalContinentIds
            ->intersect($inhabitedIds)
            ->unique()
            ->count();

        $this->awardProgress($visitedInhabited, 'countries_continents.all_inhabited_continents');

        // --- All continents including Antarctica ---

        $this->awardProgress(
            $arrivalContinentIds->unique()->count(),
            'countries_continents.all_continents'
        );

        // --- Continent route pairs ---

        $this->checkContinentPairs($flights);
    }

    /**
     * @param Collection<int, UserFlight> $flights
     * @return void
     */
    private function checkContinentPairs(Collection $flights): void
    {
        $oneWayRoutes   = collect();
        $directedRoutes = collect();

        foreach ($flights as $flight) {
            $dep = $flight->departureAirport->region->continent->internal_name;
            $arr = $flight->arrivalAirport->region->continent->internal_name;

            if (!in_array($dep, self::INHABITED_CONTINENTS) || !in_array($arr, self::INHABITED_CONTINENTS)) continue;
            if ($dep === $arr) {
                $depCountry = $flight->departureAirport->region->country_id;
                $arrCountry = $flight->arrivalAirport->region->country_id;
                if ($depCountry === $arrCountry) continue;
            }

            // Directed route key e.g. "europe→asia"
            $directedRoutes->push("{$dep}→{$arr}");

            // Undirected — sort alphabetically so "europe→asia" and "asia→europe" are the same
            $undirected = implode('→', collect([$dep, $arr])->sort()->values()->all());
            $oneWayRoutes->push($undirected);
        }

        $this->awardProgress(
            $oneWayRoutes->unique()->count(),
            'countries_continents.all_continent_pairs_one_way'
        );

        $this->awardProgress(
            $directedRoutes->unique()->count(),
            'countries_continents.all_continent_pairs_both_ways'
        );
    }
}
