<?php

namespace App\Models;

use App\Notifications\TaskAssignedNotification;
use App\Notifications\TaskStatusChangedNotification;
use App\Traits\LogsActivity;
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\Relations\MorphMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Laravel\Scout\Searchable;

class Task extends Model
{
    use HasFactory, LogsActivity, SoftDeletes, Searchable;

    protected $fillable = [
        'project_id',
        'phase_id',
        'parent_task_id',
        'title',
        'description',
        'status',
        'priority',
        'created_by',
        'assigned_to',
        'due_date',
        'start_date',
        'completed_at',
        'completed_by',
        'estimated_hours',
        'actual_hours',
        'order',
        'uuid',
        'client_updated_at',
    ];

    protected $casts = [
        'due_date' => 'date',
        'start_date' => 'date',
        'completed_at' => 'datetime',
        'estimated_hours' => 'integer',
        'actual_hours' => 'integer',
        'order' => 'integer',
    ];

    // ============================================================
    // Events / Observers
    // ============================================================

    protected static function booted(): void
    {
        static::created(function (Task $task) {
            if ($task->assigned_to) {
                $assignee = $task->assignee;
                if ($assignee && $assignee->id !== auth()->id()) {
                    $assignee->notify(new TaskAssignedNotification($task));
                }
            }
        });

        static::updated(function (Task $task) {
            // Notify on assignment change
            if ($task->isDirty('assigned_to')) {
                $newAssigneeId = $task->assigned_to;
                if ($newAssigneeId) {
                    $assignee = User::find($newAssigneeId);
                    if ($assignee && $assignee->id !== auth()->id()) {
                        $assignee->notify(new TaskAssignedNotification($task));
                    }
                }
            }

            // Notify on status change
            if ($task->isDirty('status')) {
                $oldStatus = $task->getOriginal('status');
                $task->creator?->notify(new TaskStatusChangedNotification($task, $oldStatus));
                if ($task->assigned_to && $task->assigned_to !== $task->created_by) {
                    $task->assignee?->notify(new TaskStatusChangedNotification($task, $oldStatus));
                }
            }
        });
    }

    // ============================================================
    // Relationships
    // ============================================================

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

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

    public function parent(): BelongsTo
    {
        return $this->belongsTo(Task::class, 'parent_task_id');
    }

    public function subtasks(): HasMany
    {
        return $this->hasMany(Task::class, 'parent_task_id')->orderBy('order')->orderBy('id');
    }

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

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

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

    public function media(): MorphMany
    {
        return $this->morphMany(Media::class, 'mediable');
    }

    public function comments(): MorphMany
    {
        return $this->morphMany(Comment::class, 'commentable')->orderBy('created_at');
    }

    public function activityLogs(): MorphMany
    {
        return $this->morphMany(ActivityLog::class, 'model');
    }

    public function progressSnapshots(): MorphMany
    {
        return $this->morphMany(ProgressSnapshot::class, 'trackable');
    }

    // ============================================================
    // Scopes
    // ============================================================

    public function scopePending($query)
    {
        return $query->where('status', 'pending');
    }

    public function scopeInProgress($query)
    {
        return $query->where('status', 'in_progress');
    }

    public function scopeCompleted($query)
    {
        return $query->where('status', 'completed');
    }

    public function scopeCancelled($query)
    {
        return $query->where('status', 'cancelled');
    }

    public function scopeNotCompleted($query)
    {
        return $query->where('status', '!=', 'completed');
    }

    public function scopeOverdue($query)
    {
        return $query->where('status', '!=', 'completed')
            ->whereNotNull('due_date')
            ->whereDate('due_date', '<', now()->toDateString());
    }

    public function scopeDueToday($query)
    {
        return $query->where('status', '!=', 'completed')
            ->whereDate('due_date', now()->toDateString());
    }

    public function scopeAccessibleBy($query, User $user)
    {
        if ($user->can('manage all tasks')) {
            return $query;
        }

        return $query->whereHas('project', function ($q) use ($user) {
            $q->whereHas('users', function ($sub) use ($user) {
                $sub->where('user_id', $user->id);
            });
        });
    }

    // ============================================================
    // Accessors / Helpers
    // ============================================================

    public function getIsOverdueAttribute(): bool
    {
        return $this->status !== 'completed'
            && $this->due_date
            && $this->due_date->isPast();
    }

    public function getIsDueTodayAttribute(): bool
    {
        return $this->status !== 'completed'
            && $this->due_date
            && $this->due_date->isToday();
    }

    public function getProgressAttribute(): int
    {
        $total = $this->subtasks->count();
        if ($total === 0) {
            return in_array($this->status, ['completed'], true) ? 100 : 0;
        }

        return (int) round($this->subtasks->where('status', 'completed')->count() / $total * 100);
    }

    public function getPriorityColorAttribute(): string
    {
        return match ($this->priority) {
            'low' => '#6b7280', // gray
            'medium' => '#f59e0b', // amber
            'high' => '#ef4444', // red
            'critical' => '#7c3aed', // purple
            default => '#6b7280',
        };
    }

    public function getStatusColorAttribute(): string
    {
        return match ($this->status) {
            'pending' => '#6b7280', // gray
            'in_progress' => '#3b82f6', // blue
            'completed' => '#10b981', // green
            'cancelled' => '#ef4444', // red
            default => '#6b7280',
        };
    }

    public function getStatusLabelAttribute(): string
    {
        return match ($this->status) {
            'pending' => 'Pendiente',
            'in_progress' => 'En progreso',
            'completed' => 'Completada',
            'cancelled' => 'Cancelada',
            default => ucfirst((string) $this->status),
        };
    }

    public function getPriorityLabelAttribute(): string
    {
        return match ($this->priority) {
            'low' => 'Baja',
            'medium' => 'Media',
            'high' => 'Alta',
            'critical' => 'Crítica',
            default => ucfirst((string) $this->priority),
        };
    }

    // ============================================================
    // State Transitions
    // ============================================================

    public function start(): void
    {
        $this->update([
            'status' => 'in_progress',
            'start_date' => $this->start_date ?? now()->toDateString(),
        ]);
    }

    public function complete(?User $user = null): void
    {
        $this->update([
            'status' => 'completed',
            'completed_at' => now(),
            'completed_by' => $user?->id ?? auth()->id(),
        ]);
    }

    public function reopen(): void
    {
        $this->update([
            'status' => 'pending',
            'completed_at' => null,
            'completed_by' => null,
        ]);
    }

    public function cancel(): void
    {
        $this->update(['status' => 'cancelled']);
    }

    // ============================================================
    // Static Helpers
    // ============================================================

    public static function statusOptions(): array
    {
        return [
            'pending' => 'Pendiente',
            'in_progress' => 'En progreso',
            'completed' => 'Completada',
            'cancelled' => 'Cancelada',
        ];
    }

    public static function priorityOptions(): array
    {
        return [
            'low' => 'Baja',
            'medium' => 'Media',
            'high' => 'Alta',
            'critical' => 'Crítica',
        ];
    }

    public function toSearchableArray(): array
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'description' => $this->description,
            'project_id' => $this->project_id,
            'phase_id' => $this->phase_id,
            'parent_task_id' => $this->parent_task_id,
            'status' => $this->status,
            'priority' => $this->priority,
            'assigned_to' => $this->assigned_to,
            'due_date' => $this->due_date?->toDateString(),
            'start_date' => $this->start_date?->toDateString(),
            'completed_at' => $this->completed_at?->toDateTimeString(),
        ];
    }

    public function getScoutKey(): string
    {
        return (string) $this->id;
    }
}
