<?php

namespace App\Models;

use App\Enums\NocTrackingStatus;
use App\Enums\WorkStatus;
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 Illuminate\Support\Collection;
use OwenIt\Auditing\Auditable as AuditableTrait;
use OwenIt\Auditing\Contracts\Auditable as AuditableContract;
use OwenIt\Auditing\Models\Audit;

class Work extends Model implements AuditableContract
{
    use AuditableTrait;
    use HasFactory, SoftDeletes;

    /** Disco de almacenamiento de adjuntos de OT (proyecto: siempre `public`). */
    public const WORK_FILES_DISK = 'public';

    /** Máximo de filas de auditoría en ficha/modal (scroll + límite en consulta). */
    public const AUDIT_HISTORY_LIMIT = 200;

    protected $fillable = [
        'ot',
        'work_status',
        'scale_datetime',
        'clearance_datetime',
        'sla_hours',
        'priority',
        'observation',
        'scheduled_date',
        'internal_status',
        'site_id',
        'work_type_id',
        'noc_id',
        'technician_id',
        'coordinator_id',
        'noc_tracking_status',
        'noc_comment',
    ];

    protected function casts(): array
    {
        return [
            'scale_datetime' => 'datetime',
            'clearance_datetime' => 'datetime',
            'scheduled_date' => 'datetime',
        ];
    }

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

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

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

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

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

    public function nocTrackingEnum(): ?NocTrackingStatus
    {
        return NocTrackingStatus::tryFrom((string) ($this->noc_tracking_status ?? ''));
    }

    /** @return HasMany<File, Work> */
    public function files(): HasMany
    {
        return $this->hasMany(File::class)->orderByDesc('created_at');
    }

    /** @return HasMany<WorkAssignment, Work> */
    public function assignments(): HasMany
    {
        return $this->hasMany(WorkAssignment::class);
    }

    public function hasTechnicianAssigned(int $userId): bool
    {
        return $this->assignments()->where('technician_id', $userId)->exists();
    }

    /**
     * Relaciones eager-load para la página de detalle de la OT.
     *
     * @return list<string>
     */
    public static function relationsForWorkShow(): array
    {
        return [
            'site:id,code,name,project_id,type',
            'site.project:id,name,color',
            'workType:id,name',
            'noc:id,name,paternal_surname,maternal_surname',
            'technician:id,name,paternal_surname,maternal_surname',
            'coordinator:id,name,paternal_surname,maternal_surname',
            'assignments' => fn ($q) => $q->latest('recorded_at')->limit(8)->with([
                'technician:id,name,paternal_surname,maternal_surname',
                'coordinator:id,name,paternal_surname,maternal_surname',
            ]),
            'files.uploadedBy:id,name,paternal_surname,maternal_surname',
        ];
    }

    /**
     * La OT superó el SLA (escala + horas) y sigue abierta o pendiente.
     */
    public function isSlaBreached(): bool
    {
        if ($this->scale_datetime === null) {
            return false;
        }

        $status = WorkStatus::tryFrom((string) $this->work_status);

        if ($status === WorkStatus::CERRADO || $status === WorkStatus::CANCELADO) {
            return false;
        }

        $deadline = $this->scale_datetime->copy()->addHours(max(0, (int) $this->sla_hours));

        return now()->gt($deadline);
    }

    /**
     * Historial de auditoría de la OT y de sus adjuntos (altas, cambios, bajas).
     *
     * @return Collection<int, Audit>
     */
    public function historyAudits(?int $limit = null): Collection
    {
        $limit ??= self::AUDIT_HISTORY_LIMIT;

        $fileIds = File::withTrashed()
            ->where('work_id', $this->id)
            ->pluck('id')
            ->all();

        return Audit::query()
            ->where(function ($q) use ($fileIds) {
                $q->where(function ($q2) {
                    $q2->where('auditable_type', self::class)
                        ->where('auditable_id', $this->id);
                });
                if ($fileIds !== []) {
                    $q->orWhere(function ($q2) use ($fileIds) {
                        $q2->where('auditable_type', File::class)
                            ->whereIn('auditable_id', $fileIds);
                    });
                }
            })
            ->with('user')
            ->latest('created_at')
            ->limit($limit)
            ->get();
    }
}
