<?php

namespace App\Domain\Support\Models;

use App\Domain\Applicants\Models\Applicant;
use App\Domain\Communication\Enums\TicketCategory;
use App\Domain\Communication\Enums\TicketStatus;
use App\Domain\Identity\Models\User;
use App\Support\Concerns\HasUuid;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;

/** A complaint or query raised by an applicant (§59). */
class SupportTicket extends Model
{
    use HasUuid;

    protected $guarded = ['id', 'uuid'];

    protected function casts(): array
    {
        return [
            'category' => TicketCategory::class,
            'status' => TicketStatus::class,
            'due_at' => 'datetime',
            'first_responded_at' => 'datetime',
            'resolved_at' => 'datetime',
            'opened_at' => 'datetime',
        ];
    }

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

    public function assignee(): BelongsTo
    {
        return $this->belongsTo(User::class, 'assigned_to');
    }

    public function messages(): HasMany
    {
        return $this->hasMany(SupportTicketMessage::class)->orderBy('created_at');
    }

    /** What the applicant is allowed to read: never the internal notes. */
    public function visibleMessages(): HasMany
    {
        return $this->messages()->where('is_internal', false);
    }

    /**
     * Overdue means the agency has not answered in time. A ticket waiting on
     * the applicant is not the agency's delay, so it does not read as late.
     */
    public function isOverdue(): bool
    {
        return $this->due_at !== null
            && $this->first_responded_at === null
            && $this->due_at->isPast()
            && $this->status->countsTowardsSla();
    }

    public function scopeOpen(Builder $query): Builder
    {
        return $query->whereNotIn('status', [
            TicketStatus::Resolved->value,
            TicketStatus::Closed->value,
        ]);
    }

    public function scopeOverdue(Builder $query): Builder
    {
        return $query->whereNull('first_responded_at')
            ->whereNotNull('due_at')
            ->where('due_at', '<', now())
            ->whereIn('status', [
                TicketStatus::Open->value,
                TicketStatus::InProgress->value,
                TicketStatus::Escalated->value,
            ]);
    }
}
