<?php

namespace App\Models;

use App\Http\Controllers\Api\AirlineApiController;
use App\Observers\FlightObserver;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Storage;

#[ObservedBy(FlightObserver::class)]
class UserFlight extends Model
{
    protected $table = 'user_flights';

    protected $fillable = [
        'user_id',
        'departure_date',
        'arrival_date',
        'flight_number',
        'departure_airport_id',
        'arrival_airport_id',
        'airline_id',
        'aircraft_id',
        'aircraft_registration',
        'seat_number',
        'seat_type_id',
        'flight_class_id',
        'flight_reason_id',
        'crew_type_id',
        'note',
        'auto_update',
        'departure_processed_at',
        'arrival_processed_at'
    ];

    protected $casts = [
        'departure_date' => 'immutable_datetime',
        'arrival_date'   => 'immutable_datetime',
        'auto_update' => 'boolean',
        'departure_processed_at' => 'datetime',
        'arrival_processed_at' => 'datetime',
    ];

    protected $appends = [
        'departure_date_display',
        'departure_time_display',
        'arrival_date_display',
        'arrival_time_display',
        'arrival_day_difference',
        'duration',
        'duration_display',
        'distance',
        'livery',
        'scope',
        'range',
        'region_range',
        'class_seat_combined',
        'other_users_on_flight'
    ];

    protected static function booted(): void
    {
        static::creating(function (UserFlight $flight) {
            $flight->departure_processed_at = now();
            $flight->arrival_processed_at = now();
        });
    }


    public function calculateGreatCircleDistance(): float{
        $earthRadiusKm = 6371;
        [$depLat, $depLong] = [$this->departureAirport->latitude_deg, $this->departureAirport->longitude_deg];
        [$arrLat, $arrLong] = [$this->arrivalAirport->latitude_deg, $this->arrivalAirport->longitude_deg];


        $latDelta  = deg2rad($arrLat - $depLat);
        $longDelta = deg2rad($arrLong - $depLong);

        $a = sin($latDelta / 2) * sin($latDelta / 2)
            + cos(deg2rad($depLat)) * cos(deg2rad($arrLat))
            * sin($longDelta / 2) * sin($longDelta / 2);

        $c = 2 * atan2(sqrt($a), sqrt(1 - $a));

        return $earthRadiusKm * $c;
    }

    protected function departureDateDisplay(): Attribute
    {
        return Attribute::make(
            get: fn() => $this->departure_date
                ->toMutable()
                ->setTimezone($this->departureAirport->timezone)
                ->format('j M Y')
        );
    }

    protected function classSeatCombined(): Attribute
    {
        return Attribute::make(
            get: fn() => $this->flightClass?->name
        );
    }

    protected function departureTimeDisplay(): Attribute
    {
        return Attribute::make(
            get: fn() => $this->departure_date
                ->toMutable()
                ->setTimezone($this->departureAirport->timezone)
                ->format('g:iA')
        );
    }

    protected function arrivalDateDisplay(): Attribute
    {
        return Attribute::make(
            get: fn() => $this->arrival_date
                ?->copy()
                ->setTimezone($this->arrivalAirport->timezone)
                ->format('j M Y')
        );
    }

    protected function arrivalTimeDisplay(): Attribute
    {
        return Attribute::make(
            get: fn() => $this->arrival_date
                ?->copy()
                ->setTimezone($this->arrivalAirport->timezone)
                ->format('g:iA')
        );
    }

    protected function scope(): Attribute
    {
        return Attribute::make(
            get: fn() => $this->departureAirport->region->country_id == $this->arrivalAirport->region->country_id ? 'domestic' : 'international'
        );
    }
    protected function range(): Attribute
    {
        return Attribute::make(
            get: fn() => $this->departureAirport->region->continent_id == $this->arrivalAirport->region->continent_id ? 'intracontinental' : 'intercontinental'
        );
    }

    protected function regionRange(): Attribute
    {
        return Attribute::make(
            get: fn() => $this->departureAirport->region_id == $this->arrivalAirport->region_id ? 'intraregional' : 'interregional'
        );
    }

    protected function arrivalDayDifference(): Attribute
    {
        return Attribute::make(
            get: function () {
                if (!$this->arrival_date) return 0;

                $departureLocal = $this->departure_date->copy()->setTimezone($this->departureAirport->timezone);
                $arrivalLocal   = $this->arrival_date->copy()->setTimezone($this->arrivalAirport->timezone);

                return (int) abs(
                    Carbon::parse($arrivalLocal->toDateString())
                        ->diffInDays(Carbon::parse($departureLocal->toDateString()))
                );
            }
        );
    }

    protected function duration(): Attribute
    {
        return Attribute::make(
            get: fn() => $this->departure_date->diffInMinutes($this->arrival_date)
        );
    }

    protected function durationDisplay(): Attribute
    {
        return Attribute::make(
            get: function () {
                $hours   = intdiv($this->duration, 60);
                $minutes = $this->duration % 60;

                return $hours . 'h ' . str_pad($minutes, 2, '0', STR_PAD_LEFT) . 'm';
            }
        );
    }

    protected function distance(): Attribute
    {
        return Attribute::make(
            get: fn() => round($this->calculateGreatCircleDistance())
        );
    }

    public function isDomestic() : bool{
        return $this->departureAirport->region->country_id == $this->arrivalAirport->region->country_id;
    }

    public function isInternational() : bool{
        return !$this->isDomestic();
    }

    protected function otherUsersOnFlight(): Attribute
    {
        return Attribute::make(
            get: function () {
                return once(fn() => UserFlight::where('user_id', '!=', $this->user_id)
                    ->where('departure_airport_id', $this->departure_airport_id)
                    ->where('arrival_airport_id', $this->arrival_airport_id)
                    ->where('flight_number', $this->flight_number)
                    ->where('airline_id', $this->airline_id)
                    ->whereRaw('DATE(departure_date AT TIME ZONE \'UTC\') = ?', [
                        Carbon::parse($this->departure_date)->utc()->toDateString()
                    ])
                    ->with('user')
                    ->get()
                    ->pluck('user.name'));
            }
        );
    }

    public static function snapshot($userFlightId): array
    {
            return UserFlight::with([
                'departureAirport',
                'departureAirport.region.country',
                'arrivalAirport',
                'arrivalAirport.region.country',
                'aircraft',
                'airline',
                'airline.country',
                'airline.alliance',
                'flightClass',
                'seatType',
                'flightReason',
                'crewType',
            ])->find($userFlightId)->toArray();
    }

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    public function departureAirport(): BelongsTo
    {
        return $this->belongsTo(Airport::class, 'departure_airport_id');
    }

    public function arrivalAirport(): BelongsTo
    {
        return $this->belongsTo(Airport::class, 'arrival_airport_id');
    }

    public function crewType(): BelongsTo
    {
        return $this->belongsTo(CrewType::class);
    }

    public function airline(): BelongsTo
    {
        return $this->belongsTo(Airline::class);
    }


    public function aircraft(): BelongsTo
    {
        return $this->belongsTo(Aircraft::class);
    }

    public function seatType(): BelongsTo
    {
        return $this->belongsTo(SeatType::class);
    }

    public function flightClass(): BelongsTo
    {
        return $this->belongsTo(FlightClass::class);
    }

    public function flightReason(): BelongsTo
    {
        return $this->belongsTo(FlightReason::class);
    }

    public function livery(): Attribute{
        return Attribute::make(
            get: function () {
                $user = auth()?->user();

                $useAi = !$user || $user->getSetting('ai_liveries');

                $apiUrl = config('app.logo_api_url');

                $attribution = '';
                $attributionUrl = '';
                $isAi = false;

                if (!$this->aircraft) {
                    return null;
                }


                if ($this->airline && $useAi){
                    $path = "images/liveries/{$this->airline->internal_name}_{$this->aircraft->designator}.png";
                    if (Storage::disk('local')->exists($path)) {
                        $finalPath = $apiUrl."/airline/{$this->airline->internal_name}/livery/{$this->aircraft->designator}";
                        $attribution = 'This image is AI generated and may not be an accurate representation of the aircraft.';
                        $isAi = true;
                    }
                }

                if(empty($finalPath)){
                    $path = "images/livery_templates/{$this->aircraft->designator}.png";
                    if (Storage::disk('local')->exists($path)) {
                        $finalPath = $apiUrl."/aircraft/{$this->aircraft->designator}/livery";
                        $attribution = '© NoRebbo Blank Aircraft Templates';
                        $attributionUrl = 'https://www.norebbo.com/category/aircraft-templates/';
                    }
                }

                if(empty($finalPath)){
                    return null;
                }

                return [
                    'image_url' => $finalPath,
                    'attribution' => $attribution,
                    'attribution_url' => $attributionUrl,
                    'is_ai' => $isAi,
                 ];
            }
        );
    }
}
