<?php

namespace App\Models;

use App\Contracts\Model;
use App\Enums\ExpenseType;
use App\Enums\FlightType;
use Illuminate\Database\Eloquent\Attributes\Scope;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\AsEnumCollection;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;

/**
 * @property int                              $id
 * @property int|null                         $airline_id
 * @property string                           $name
 * @property int                              $amount
 * @property ExpenseType                      $type
 * @property Collection<int, FlightType>|null $flight_type
 * @property int|null                         $charge_to_user
 * @property int|null                         $multiplier
 * @property int|null                         $active
 * @property string|null                      $ref_model_type
 * @property string|null                      $ref_model_id
 * @property Carbon|null                      $created_at
 * @property Carbon|null                      $updated_at
 * @property-read Airline|null $airline
 * @property-read \Illuminate\Database\Eloquent\Model|\Eloquent|null $ref_model
 *
 * @method static Builder<static>|Expense            active()
 * @method static \Database\Factories\ExpenseFactory factory($count = null, $state = [])
 * @method static Builder<static>|Expense            forAirline(int $airlineId)
 * @method static Builder<static>|Expense            forGlobalAirline()
 * @method static Builder<static>|Expense            forRefModel(string $type, ?mixed $id = null)
 * @method static Builder<static>|Expense            newModelQuery()
 * @method static Builder<static>|Expense            newQuery()
 * @method static Builder<static>|Expense            ofType(\App\Enums\ExpenseType $type)
 * @method static Builder<static>|Expense            query()
 * @method static Builder<static>|Expense            whereActive($value)
 * @method static Builder<static>|Expense            whereAirlineId($value)
 * @method static Builder<static>|Expense            whereAmount($value)
 * @method static Builder<static>|Expense            whereChargeToUser($value)
 * @method static Builder<static>|Expense            whereCreatedAt($value)
 * @method static Builder<static>|Expense            whereFlightType($value)
 * @method static Builder<static>|Expense            whereId($value)
 * @method static Builder<static>|Expense            whereMultiplier($value)
 * @method static Builder<static>|Expense            whereName($value)
 * @method static Builder<static>|Expense            whereRefModelId($value)
 * @method static Builder<static>|Expense            whereRefModelType($value)
 * @method static Builder<static>|Expense            whereType($value)
 * @method static Builder<static>|Expense            whereUpdatedAt($value)
 *
 * @mixin \Eloquent
 */
class Expense extends Model
{
    use HasFactory;

    public $table = 'expenses';

    protected $fillable = [
        'airline_id',
        'name',
        'amount',
        'type',
        'flight_type',
        'multiplier',
        'charge_to_user',
        'ref_model_type',
        'ref_model_id',
        'active',
    ];

    /**
     * Relationships
     */
    public function airline(): BelongsTo
    {
        return $this->belongsTo(Airline::class, 'airline_id');
    }

    public function ref_model(): MorphTo
    {
        return $this->morphTo('ref_model', 'ref_model_type', 'ref_model_id');
    }

    #[\Override]
    protected function casts(): array
    {
        return [
            'flight_type' => AsEnumCollection::of(FlightType::class),
            'type'        => ExpenseType::class,
        ];
    }

    /**
     * Filter to active expenses (active = true).
     */
    #[Scope]
    protected function active(Builder $q): Builder
    {
        return $q->where('active', true);
    }

    /**
     * Filter by expense type (FLIGHT / DAILY / MONTHLY).
     */
    #[Scope]
    protected function ofType(Builder $q, ExpenseType $type): Builder
    {
        return $q->where('type', $type);
    }

    /**
     * Filter to expenses belonging to a specific airline.
     */
    #[Scope]
    protected function forAirline(Builder $q, int $airlineId): Builder
    {
        return $q->where('airline_id', $airlineId);
    }

    /**
     * Filter to "global" expenses with no airline (airline_id IS NULL).
     */
    #[Scope]
    protected function forGlobalAirline(Builder $q): Builder
    {
        return $q->whereNull('airline_id');
    }

    /**
     * Filter by ref_model_type, optionally narrowing by ref_model_id.
     */
    #[Scope]
    protected function forRefModel(Builder $q, string $type, mixed $id = null): Builder
    {
        $q->where('ref_model_type', $type);
        if ($id !== null) {
            $q->where('ref_model_id', $id);
        }

        return $q;
    }
}
