<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Str;
use Illuminate\Database\Eloquent\Builder;

/**
 * Ticket Model
 * 
 * Represents a support ticket in the Communication Module.
 * Supports all 10 system roles as creators.
 * 
 * Requirements: 1.1, 1.4, 1.5, 8.1
 * 
 * @property int $id
 * @property int $user_id
 * @property string $title
 * @property string $description
 * @property string $status
 * @property string $priority
 * @property string $unique_identifier
 * @property int|null $assigned_to
 * @property string|null $category
 * @property \Carbon\Carbon|null $last_activity_at
 * @property string|null $resolution_notes
 * @property \Carbon\Carbon|null $resolved_at
 * @property int|null $resolved_by
 */
class Ticket extends Model
{
    use SoftDeletes;

    /**
     * Status constants for consistency
     */
    const STATUS_PENDING = 'pending';
    const STATUS_IN_PROGRESS = 'in_progress';
    const STATUS_RESOLVED = 'resolved';
    const STATUS_CLOSED = 'closed';

    /**
     * Priority constants
     */
    const PRIORITY_LOW = 'low';
    const PRIORITY_MEDIUM = 'medium';
    const PRIORITY_HIGH = 'high';
    const PRIORITY_URGENT = 'urgent';

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'user_id',
        'title',
        'description',
        'status',
        'priority',
        'unique_identifier',
        'assigned_to',
        'category',
        'last_activity_at',
        'resolution_notes',
        'resolved_at',
        'resolved_by',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'last_activity_at' => 'datetime',
        'resolved_at' => 'datetime',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
        'deleted_at' => 'datetime',
    ];

    /**
     * Status color mapping for UI
     */
    public static function statusColors(): array
    {
        return [
            self::STATUS_PENDING => 'bg-yellow-100 text-yellow-800',
            self::STATUS_IN_PROGRESS => 'bg-blue-100 text-blue-800',
            self::STATUS_RESOLVED => 'bg-green-100 text-green-800',
            self::STATUS_CLOSED => 'bg-gray-100 text-gray-800',
        ];
    }

    /**
     * Priority color mapping for UI
     */
    public static function priorityColors(): array
    {
        return [
            self::PRIORITY_LOW => 'bg-gray-100 text-gray-800',
            self::PRIORITY_MEDIUM => 'bg-blue-100 text-blue-800',
            self::PRIORITY_HIGH => 'bg-orange-100 text-orange-800',
            self::PRIORITY_URGENT => 'bg-red-100 text-red-800',
        ];
    }

    /**
     * Boot the model.
     */
    protected static function booted(): void
    {
        // Generate unique identifier on creation
        static::creating(function (self $ticket) {
            if (empty($ticket->unique_identifier)) {
                $ticket->unique_identifier = self::generateUniqueIdentifier();
            }
        });

        // Update last_activity_at on creation
        static::created(function (self $ticket) {
            $ticket->updateQuietly(['last_activity_at' => now()]);
        });
    }

    /**
     * Generate a unique ticket identifier.
     * Format: TKT-YYYYMMDD-XXXX
     */
    public static function generateUniqueIdentifier(): string
    {
        $date = now()->format('Ymd');
        $random = strtoupper(Str::random(4));
        $identifier = "TKT-{$date}-{$random}";

        // Ensure uniqueness
        while (self::where('unique_identifier', $identifier)->exists()) {
            $random = strtoupper(Str::random(4));
            $identifier = "TKT-{$date}-{$random}";
        }

        return $identifier;
    }

    /**
     * Get the user who created this ticket.
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

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

    /**
     * Get the user who resolved this ticket.
     */
    public function resolver(): BelongsTo
    {
        return $this->belongsTo(User::class, 'resolved_by');
    }

    /**
     * Get all replies for this ticket.
     */
    public function replies(): HasMany
    {
        return $this->hasMany(TicketReply::class)->latest();
    }

    /**
     * Get public replies only (not internal notes).
     */
    public function publicReplies(): HasMany
    {
        return $this->hasMany(TicketReply::class)
            ->where('is_internal', false)
            ->latest();
    }

    /**
     * Get internal notes only.
     */
    public function internalNotes(): HasMany
    {
        return $this->hasMany(TicketReply::class)
            ->where('is_internal', true)
            ->latest();
    }

    /**
     * Scope for pending tickets.
     */
    public function scopePending(Builder $query): Builder
    {
        return $query->where('status', self::STATUS_PENDING);
    }

    /**
     * Scope for in-progress tickets.
     */
    public function scopeInProgress(Builder $query): Builder
    {
        return $query->where('status', self::STATUS_IN_PROGRESS);
    }

    /**
     * Scope for resolved tickets.
     */
    public function scopeResolved(Builder $query): Builder
    {
        return $query->where('status', self::STATUS_RESOLVED);
    }

    /**
     * Scope for closed tickets.
     */
    public function scopeClosed(Builder $query): Builder
    {
        return $query->where('status', self::STATUS_CLOSED);
    }

    /**
     * Scope for open tickets (pending or in_progress).
     */
    public function scopeOpen(Builder $query): Builder
    {
        return $query->whereIn('status', [self::STATUS_PENDING, self::STATUS_IN_PROGRESS]);
    }

    /**
     * Scope for high priority tickets.
     */
    public function scopeHighPriority(Builder $query): Builder
    {
        return $query->whereIn('priority', [self::PRIORITY_HIGH, self::PRIORITY_URGENT]);
    }

    /**
     * Scope for tickets assigned to a specific user.
     */
    public function scopeAssignedTo(Builder $query, int $userId): Builder
    {
        return $query->where('assigned_to', $userId);
    }

    /**
     * Scope for tickets created by a specific user.
     */
    public function scopeCreatedBy(Builder $query, int $userId): Builder
    {
        return $query->where('user_id', $userId);
    }

    /**
     * Scope for tickets by category.
     */
    public function scopeByCategory(Builder $query, string $category): Builder
    {
        return $query->where('category', $category);
    }

    /**
     * Scope for searching tickets.
     */
    public function scopeSearch(Builder $query, string $search): Builder
    {
        return $query->where(function ($q) use ($search) {
            $q->where('title', 'like', "%{$search}%")
              ->orWhere('unique_identifier', 'like', "%{$search}%")
              ->orWhere('description', 'like', "%{$search}%");
        });
    }

    /**
     * Check if ticket is open.
     */
    public function isOpen(): bool
    {
        return in_array($this->status, [self::STATUS_PENDING, self::STATUS_IN_PROGRESS]);
    }

    /**
     * Check if ticket is closed.
     */
    public function isClosed(): bool
    {
        return in_array($this->status, [self::STATUS_RESOLVED, self::STATUS_CLOSED]);
    }

    /**
     * Get the status badge HTML.
     */
    public function getStatusBadgeAttribute(): string
    {
        $color = self::statusColors()[$this->status] ?? 'bg-gray-100 text-gray-800';
        return '<span class="px-3 py-1 rounded-full text-xs font-semibold ' . $color . '">' .
               ucfirst(str_replace('_', ' ', $this->status)) . '</span>';
    }

    /**
     * Get the priority badge HTML.
     */
    public function getPriorityBadgeAttribute(): string
    {
        $color = self::priorityColors()[$this->priority] ?? 'bg-gray-100 text-gray-800';
        return '<span class="px-3 py-1 rounded-full text-xs font-semibold ' . $color . '">' .
               ucfirst($this->priority) . '</span>';
    }

    /**
     * Get the time elapsed since last activity.
     */
    public function getLastActivityHumanAttribute(): string
    {
        return $this->last_activity_at?->diffForHumans() ?? 'No activity';
    }

    /**
     * Update last activity timestamp.
     */
    public function touchLastActivity(): void
    {
        $this->update(['last_activity_at' => now()]);
    }

    /**
     * Mark ticket as resolved.
     */
    public function resolve(int $resolvedBy, ?string $notes = null): void
    {
        $this->update([
            'status' => self::STATUS_RESOLVED,
            'resolved_at' => now(),
            'resolved_by' => $resolvedBy,
            'resolution_notes' => $notes,
            'last_activity_at' => now(),
        ]);
    }

    /**
     * Close the ticket.
     */
    public function close(): void
    {
        $this->update([
            'status' => self::STATUS_CLOSED,
            'last_activity_at' => now(),
        ]);
    }

    /**
     * Reopen the ticket.
     */
    public function reopen(): void
    {
        $this->update([
            'status' => self::STATUS_PENDING,
            'resolved_at' => null,
            'resolved_by' => null,
            'last_activity_at' => now(),
        ]);
    }

    /**
     * Assign to a user.
     */
    public function assignTo(?int $userId): void
    {
        $this->update([
            'assigned_to' => $userId,
            'status' => $userId ? self::STATUS_IN_PROGRESS : $this->status,
            'last_activity_at' => now(),
        ]);
    }
}
