<?php

namespace App\Models;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Spatie\Activitylog\Traits\LogsActivity;
use Spatie\Activitylog\LogOptions;

class Territorio extends Model
{
    use SoftDeletes, LogsActivity;

    protected $table = 'territori';

    protected $fillable = [
        'numero',
        'zona_id',
        'tipologia_id',
        'note',
        'confini',
        'pdf_path',
        'thumbnail_path',
        'attivo',
        'prioritario',
    ];

    protected function casts(): array
    {
        return [
            'attivo' => 'boolean',
            'prioritario' => 'boolean',
        ];
    }

    public function getActivitylogOptions(): LogOptions
    {
        return LogOptions::defaults()
            ->logOnly(['numero', 'zona_id', 'tipologia_id', 'attivo', 'prioritario', 'pdf_path'])
            ->logOnlyDirty()
            ->dontSubmitEmptyLogs();
    }

    // ─── Relationships ─────────────────────────────────────────

    public function zona()
    {
        return $this->belongsTo(Zona::class, 'zona_id');
    }

    public function tipologia()
    {
        return $this->belongsTo(Tipologia::class, 'tipologia_id');
    }

    public function assegnazioni()
    {
        return $this->hasMany(Assegnazione::class, 'territorio_id');
    }

    public function assegnazioneCorrente()
    {
        return $this->hasOne(Assegnazione::class, 'territorio_id')
            ->whereNull('returned_at')
            ->latestOfMany('assigned_at');
    }

    public function ultimaAssegnazione()
    {
        return $this->hasOne(Assegnazione::class, 'territorio_id')
            ->latestOfMany('assigned_at');
    }

    // ─── Computed State ─────────────────────────────────────────

    public function getStatoAttribute(): string
    {
        if (!$this->attivo) {
            return 'inattivo';
        }

        $corrente = $this->assegnazioneCorrente;
        if ($corrente) {
            $giorniAssegnato = Carbon::parse($corrente->assigned_at)->diffInDays(now());
            $sogliaSmarrito = Setting::getValue('giorni_per_smarrito', 120);

            if ($giorniAssegnato > $sogliaSmarrito) {
                return 'da_rientrare';
            }
            return 'assegnato';
        }

        return 'in_reparto';
    }

    public function getAssegnatarioAttribute(): ?Proclamatore
    {
        return $this->assegnazioneCorrente?->proclamatore;
    }

    /**
     * Days since last return (or creation if never assigned).
     */
    public function getGiorniGiacenzaAttribute(): int
    {
        $ultima = $this->ultimaAssegnazione;

        if ($ultima && $ultima->returned_at) {
            return Carbon::parse($ultima->returned_at)->diffInDays(now());
        }

        if (!$ultima) {
            return $this->created_at->diffInDays(now());
        }

        // Currently assigned, no giacenza concept
        return 0;
    }

    /**
     * Is this territory "prioritario"?
     * Manual flag OR giacenza exceeds threshold (threshold always wins).
     */
    public function getIsPrioritarioAttribute(): bool
    {
        if (!$this->attivo) {
            return false;
        }

        if ($this->prioritario) {
            return true;
        }

        // Threshold-based priority (only when in reparto)
        if ($this->stato === 'in_reparto') {
            $soglia = Setting::getValue('giorni_giacenza_prioritari', 180);
            return $this->giorni_giacenza > $soglia;
        }

        return false;
    }

    // ─── Scopes ─────────────────────────────────────────────────

    public function scopeAttivi($query)
    {
        return $query->where('attivo', true);
    }

    public function scopeInReparto($query)
    {
        return $query->attivi()
            ->whereDoesntHave('assegnazioni', function ($q) {
                $q->whereNull('returned_at');
            });
    }

    public function scopeAssegnato($query)
    {
        return $query->attivi()
            ->whereHas('assegnazioni', function ($q) {
                $q->whereNull('returned_at');
            });
    }

    public function scopeDaRientrare($query)
    {
        $soglia = Setting::getValue('giorni_per_smarrito', 120);

        return $query->attivi()
            ->whereHas('assegnazioneCorrente', function ($q) use ($soglia) {
                $q->where('assigned_at', '<=', now()->subDays($soglia));
            });
    }

    public function scopeDaAssegnare($query)
    {
        $soglia = Setting::getValue('giorni_giacenza_da_assegnare', 120);

        return $query->inReparto()
            ->where(function ($q) use ($soglia) {
                // Territories whose last assignment returned > soglia days ago
                $q->whereHas('assegnazioni', function ($sub) use ($soglia) {
                    $sub->whereNotNull('returned_at')
                        ->where('returned_at', '<=', now()->subDays($soglia))
                        ->whereRaw('id = (SELECT MAX(a2.id) FROM assegnazioni a2 WHERE a2.territorio_id = assegnazioni.territorio_id)');
                })
                // Or territories never assigned, created > soglia days ago
                ->orWhere(function ($sub) use ($soglia) {
                    $sub->doesntHave('assegnazioni')
                        ->where('created_at', '<=', now()->subDays($soglia));
                });
            });
    }

    public function scopePrioritari($query)
    {
        $soglia = Setting::getValue('giorni_giacenza_prioritari', 180);

        return $query->inReparto()
            ->where(function ($q) use ($soglia) {
                // Manual priority flag
                $q->where('prioritario', true)
                // OR threshold-based
                ->orWhere(function ($sub) use ($soglia) {
                    $sub->whereHas('assegnazioni', function ($a) use ($soglia) {
                        $a->whereNotNull('returned_at')
                           ->where('returned_at', '<=', now()->subDays($soglia))
                           ->whereRaw('id = (SELECT MAX(a2.id) FROM assegnazioni a2 WHERE a2.territorio_id = assegnazioni.territorio_id)');
                    })
                    ->orWhere(function ($never) use ($soglia) {
                        $never->doesntHave('assegnazioni')
                            ->where('created_at', '<=', now()->subDays($soglia));
                    });
                });
            });
    }
}
