<?php

namespace App\Models\Dsar;

use App\Enum\Contact\MessageDirection;
use App\Enum\Dsar\DsarStatus;
use App\Interface\DocumentOwner;
use App\Interface\HistoryOwner;
use App\Interface\NoteOwner;
use App\Models\Claim\Claim;
use App\Models\Contact\Hub\ContactMessage;
use App\Models\Contact\Hub\ContactMessageAttachment;
use App\Models\Institution\Institution;
use App\Models\User\User;
use App\Trait\BelongsToSolicitor;
use App\Trait\HasDocuments;
use App\Trait\HasHistory;
use App\Trait\HasNotes;
use App\Trait\HasSlug;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Dsar extends Model implements HistoryOwner, NoteOwner, DocumentOwner {
    public $fillable = [
        'slug',
        'solicitor_id',
        'tranche_id',
        'user_id',
        'institution_id',
        'status',
        'is_flagged',
        'claim_id',
        'content',
        'email_content',
        'reference',
        'receiver_reference',
        'file_path',
        'posted_at',
        'received_at',
        'expected_at',
    ];

    protected $casts = [
        'is_flagged'  => 'boolean',
        'posted_at'   => 'datetime',
        'received_at' => 'datetime',
        'expected_at' => 'datetime',
    ];

    use BelongsToSolicitor, HasSlug, HasHistory, SoftDeletes, HasNotes, HasDocuments;

    /**
     * Stamp received_at the first time a DSAR reaches a terminal status, giving
     * the reports a real "when did the institution come back to us" timestamp
     * instead of leaning on updated_at.
     *
     * Query-builder updates bypass model events, so code that moves a DSAR to a
     * terminal status via ->update() on a builder rather than on a model
     * instance must stamp received_at itself — see FindRelatedDsarJob.
     */
    protected static function booted(): void {
        static::updating(function (Dsar $dsar) {
            if ($dsar->isDirty('status')
                && $dsar->received_at === null
                && in_array($dsar->status, DsarStatus::terminal(), true)) {
                $dsar->received_at = now();
            }
        });
    }

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

    public function institution() {
        return $this->belongsTo(Institution::class);
    }

    public function claim() {
        return $this->belongsTo(Claim::class);
    }
    public function tranche() {
        return $this->belongsTo(DsarTranche::class);
    }

    public function responses() {
        return $this->hasMany(DsarResponse::class);
    }

    public function latestResponse() {
        return $this->hasOne(DsarResponse::class)->latestOfMany();
    }

    public function chases() {
        return $this->hasMany(DsarChase::class);
    }

    /**
     * The outbound ContactMessage created when this DSAR was emailed.
     * Preferred over emailSend() for DSARs sent via the new contact pipeline.
     */
    public function outboundMessage() {
        return $this->morphOne(ContactMessage::class, 'messageable')
            ->where('direction', MessageDirection::OUTBOUND->value)
            ->latest();
    }

    public function evidenceAttachments(): Collection
    {
        return ContactMessageAttachment::whereIn(
            'contact_message_id',
            ContactMessage::where('messageable_type', static::class)
                ->where('messageable_id', $this->id)
                ->where('triage_queue', 'dsar_evidence')
                ->select('id')
        )->with('evidenceItems')->get();
    }

    public function getDocumentStoragePath(): string {
        return "dsars/" . $this->slug . "/";
    }

    public function generateReference(): string {
        return 'DSAR-' . now()->format('Ymd') . '-' . strtoupper(substr($this->slug, 0, 6));
    }
}
