<?php

namespace App\Models;

use App\Enums\DeclarationPriority;
use App\Enums\DeclarationStatus;
use App\Enums\DeclarationType;
use App\Enums\WorkspaceUserRole;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Spatie\Activitylog\LogOptions;
use Spatie\Activitylog\Traits\LogsActivity;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;

class Declaration extends Model implements HasMedia
{
    /** @use HasFactory<\Database\Factories\DeclarationFactory> */
    use HasFactory, InteractsWithMedia, LogsActivity, SoftDeletes;

    protected $table = 'declarations';

    /**
     * The attributes that are mass assignable.
     *
     * @var list<string>
     */
    protected $fillable = [
        'workspace_id',
        'client_id',
        'created_by',
        'title',
        'type',
        'period_year',
        'period_month',
        'period_quarter',
        'due_date',
        'status',
        'priority',
        'assigned_to',
        'validated_at',
        'closed_at',
        'confirmation_requested_at',
        'confirmation_media_id',
        'confirmed_by_type',
        'confirmed_by_id',
        'confirmation_signature',
        'refused_at',
        'refusal_reason',
        'notes_internal',
        'notes_client',
        'archived_at',
        'created_at',
    ];

    /**
     * Get the attributes that should be cast.
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'type' => DeclarationType::class,
            'status' => DeclarationStatus::class,
            'priority' => DeclarationPriority::class,
            'validated_at' => 'datetime',
            'closed_at' => 'datetime',
            'confirmation_requested_at' => 'datetime',
            'refused_at' => 'datetime',
            'archived_at' => 'datetime',
            'due_date' => 'date',
        ];
    }

    /**
     * Register media collections.
     */
    public function registerMediaCollections(): void
    {
        $this->addMediaCollection('documents')->useDisk('local');
    }

    /**
     * Get the workspace that owns the declaration.
     *
     * @return BelongsTo<Workspace, $this>
     */
    public function workspace(): BelongsTo
    {
        return $this->belongsTo(Workspace::class);
    }

    /**
     * Get the client that owns the declaration.
     *
     * @return BelongsTo<Client, $this>
     */
    public function client(): BelongsTo
    {
        return $this->belongsTo(Client::class);
    }

    /**
     * Get the user who created the declaration.
     *
     * @return BelongsTo<User, $this>
     */
    public function creator(): BelongsTo
    {
        return $this->belongsTo(User::class, 'created_by');
    }

    /**
     * Get the user assigned to the declaration.
     *
     * @return BelongsTo<User, $this>
     */
    public function assignee(): BelongsTo
    {
        return $this->belongsTo(User::class, 'assigned_to');
    }

    /**
     * Get the messages for the declaration.
     *
     * @return HasMany<Message>
     */
    public function messages(): HasMany
    {
        return $this->hasMany(Message::class);
    }

    /**
     * Get the invitations for the declaration.
     *
     * @return HasMany<DeclarationInvitation>
     */
    public function invitations(): HasMany
    {
        return $this->hasMany(DeclarationInvitation::class);
    }

    /**
     * Scope declarations based on user role.
     * Workers see only declarations assigned to them; Owners/Managers see all.
     */
    public function scopeForUser(Builder $query, User $user, WorkspaceUser $workspaceUser): Builder
    {
        if ($workspaceUser->role->is(WorkspaceUserRole::Worker)) {
            return $query->where('assigned_to', $user->id);
        }

        return $query;
    }

    /**
     * Scope a query to only include active (non-archived) declarations.
     */
    public function scopeActive(Builder $query): Builder
    {
        return $query->whereNull('archived_at');
    }

    /**
     * Scope a query to only include archived declarations.
     */
    public function scopeArchived(Builder $query): Builder
    {
        return $query->whereNotNull('archived_at');
    }

    public function getActivitylogOptions(): LogOptions
    {
        return LogOptions::defaults()
            ->logFillable()
            ->logOnlyDirty()
            ->dontSubmitEmptyLogs();
    }
}
