<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Builder;

/**
 * EmailMessage Model
 * 
 * Represents an email message record with tracking.
 * Integrates with existing EmailService.
 * 
 * Requirements: 3.1, 3.3, 3.7, 3.10, 8.2
 * 
 * @property int $id
 * @property int $sender_id
 * @property array $to_recipients
 * @property array|null $cc_recipients
 * @property array|null $bcc_recipients
 * @property string $subject
 * @property string|null $html_body
 * @property string|null $text_body
 * @property int|null $template_id
 * @property int|null $reply_to_id
 * @property string|null $in_reply_to
 * @property string|null $references
 * @property \Carbon\Carbon|null $scheduled_at
 * @property \Carbon\Carbon|null $sent_at
 * @property string $status
 * @property string|null $message_id
 * @property array|null $attachments
 * @property string $priority
 * @property string $recipient_type
 * @property string|null $target_role
 * @property string|null $error_message
 */
class EmailMessage extends Model
{
    use SoftDeletes;

    /**
     * Status constants
     */
    const STATUS_DRAFT = 'draft';
    const STATUS_SCHEDULED = 'scheduled';
    const STATUS_SENDING = 'sending';
    const STATUS_SENT = 'sent';
    const STATUS_FAILED = 'failed';
    const STATUS_PARTIAL = 'partial';

    /**
     * Priority constants
     */
    const PRIORITY_LOW = 'low';
    const PRIORITY_NORMAL = 'normal';
    const PRIORITY_HIGH = 'high';

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'sender_id',
        'to_recipients',
        'cc_recipients',
        'bcc_recipients',
        'subject',
        'html_body',
        'text_body',
        'template_id',
        'reply_to_id',
        'in_reply_to',
        'references',
        'scheduled_at',
        'sent_at',
        'status',
        'message_id',
        'attachments',
        'priority',
        'recipient_type',
        'target_role',
        'error_message',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'to_recipients' => 'array',
        'cc_recipients' => 'array',
        'bcc_recipients' => 'array',
        'attachments' => 'array',
        'scheduled_at' => 'datetime',
        'sent_at' => 'datetime',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
        'deleted_at' => 'datetime',
    ];

    /**
     * Status color mapping for UI.
     */
    public static function statusColors(): array
    {
        return [
            self::STATUS_DRAFT => 'bg-gray-100 text-gray-800',
            self::STATUS_SCHEDULED => 'bg-blue-100 text-blue-800',
            self::STATUS_SENDING => 'bg-yellow-100 text-yellow-800',
            self::STATUS_SENT => 'bg-green-100 text-green-800',
            self::STATUS_FAILED => 'bg-red-100 text-red-800',
            self::STATUS_PARTIAL => 'bg-orange-100 text-orange-800',
        ];
    }

    /**
     * Get the user who sent this email.
     */
    public function sender(): BelongsTo
    {
        return $this->belongsTo(User::class, 'sender_id');
    }

    /**
     * Get the template used (if any).
     */
    public function template(): BelongsTo
    {
        return $this->belongsTo(EmailTemplate::class, 'template_id');
    }

    /**
     * Get the original message this is a reply to.
     */
    public function originalMessage(): BelongsTo
    {
        return $this->belongsTo(EmailMessage::class, 'reply_to_id');
    }

    /**
     * Get replies to this message.
     */
    public function replies()
    {
        return $this->hasMany(EmailMessage::class, 'reply_to_id');
    }

    /**
     * Scope for sent messages.
     */
    public function scopeSent(Builder $query): Builder
    {
        return $query->where('status', self::STATUS_SENT);
    }

    /**
     * Scope for scheduled messages.
     */
    public function scopeScheduled(Builder $query): Builder
    {
        return $query->where('status', self::STATUS_SCHEDULED);
    }

    /**
     * Scope for draft messages.
     */
    public function scopeDraft(Builder $query): Builder
    {
        return $query->where('status', self::STATUS_DRAFT);
    }

    /**
     * Scope for failed messages.
     */
    public function scopeFailed(Builder $query): Builder
    {
        return $query->where('status', self::STATUS_FAILED);
    }

    /**
     * Scope for messages sent by a specific user.
     */
    public function scopeSentBy(Builder $query, int $userId): Builder
    {
        return $query->where('sender_id', $userId);
    }

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

    /**
     * Scope for messages in a date range.
     */
    public function scopeDateRange(Builder $query, $startDate, $endDate): Builder
    {
        return $query->whereBetween('created_at', [$startDate, $endDate]);
    }

    /**
     * Scope for pending scheduled messages.
     */
    public function scopePendingScheduled(Builder $query): Builder
    {
        return $query->where('status', self::STATUS_SCHEDULED)
                     ->where('scheduled_at', '<=', now());
    }

    /**
     * Scope for high priority messages.
     */
    public function scopeHighPriority(Builder $query): Builder
    {
        return $query->where('priority', self::PRIORITY_HIGH);
    }

    /**
     * Scope for messages that are replies.
     */
    public function scopeReplies(Builder $query): Builder
    {
        return $query->whereNotNull('reply_to_id');
    }

    /**
     * Get the total number of recipients.
     */
    public function getTotalRecipientsAttribute(): int
    {
        return count($this->to_recipients ?? []) +
               count($this->cc_recipients ?? []) +
               count($this->bcc_recipients ?? []);
    }

    /**
     * Get primary recipients email addresses.
     */
    public function getToEmails(): array
    {
        return collect($this->to_recipients ?? [])
            ->pluck('email')
            ->filter()
            ->toArray();
    }

    /**
     * Get CC email addresses.
     */
    public function getCcEmails(): array
    {
        return collect($this->cc_recipients ?? [])
            ->pluck('email')
            ->filter()
            ->toArray();
    }

    /**
     * Get BCC email addresses.
     */
    public function getBccEmails(): array
    {
        return collect($this->bcc_recipients ?? [])
            ->pluck('email')
            ->filter()
            ->toArray();
    }

    /**
     * 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($this->status) . '</span>';
    }

    /**
     * Get the preview text (first 150 chars of body).
     */
    public function getPreviewAttribute(): string
    {
        $text = $this->text_body ?? strip_tags($this->html_body ?? '');
        return Str::limit($text, 150);
    }

    /**
     * Check if email is scheduled for future.
     */
    public function isScheduled(): bool
    {
        return $this->status === self::STATUS_SCHEDULED && 
               $this->scheduled_at && 
               $this->scheduled_at->isFuture();
    }

    /**
     * Check if email was sent.
     */
    public function isSent(): bool
    {
        return $this->status === self::STATUS_SENT;
    }

    /**
     * Check if email is a reply.
     */
    public function isReply(): bool
    {
        return !is_null($this->reply_to_id);
    }

    /**
     * Check if email has attachments.
     */
    public function hasAttachments(): bool
    {
        return !empty($this->attachments);
    }

    /**
     * Get attachment count.
     */
    public function getAttachmentCountAttribute(): int
    {
        return count($this->attachments ?? []);
    }

    /**
     * Mark as sent.
     */
    public function markAsSent(string $messageId): void
    {
        $this->update([
            'status' => self::STATUS_SENT,
            'message_id' => $messageId,
            'sent_at' => now(),
        ]);
    }

    /**
     * Mark as failed.
     */
    public function markAsFailed(string $errorMessage): void
    {
        $this->update([
            'status' => self::STATUS_FAILED,
            'error_message' => $errorMessage,
        ]);
    }

    /**
     * Mark as sending.
     */
    public function markAsSending(): void
    {
        $this->update(['status' => self::STATUS_SENDING]);
    }

    /**
     * Create a reply to this email.
     */
    public function createReply(string $body, int $senderId): self
    {
        return self::create([
            'sender_id' => $senderId,
            'to_recipients' => $this->to_recipients,
            'subject' => 'Re: ' . $this->subject,
            'html_body' => $body,
            'reply_to_id' => $this->id,
            'in_reply_to' => $this->message_id,
            'references' => trim(($this->references ?? '') . ' ' . $this->message_id),
            'status' => self::STATUS_DRAFT,
        ]);
    }

    /**
     * Get email headers for threading.
     */
    public function getThreadingHeaders(): array
    {
        $headers = [];
        
        if ($this->in_reply_to) {
            $headers['In-Reply-To'] = $this->in_reply_to;
        }
        
        if ($this->references) {
            $headers['References'] = $this->references;
        }
        
        return $headers;
    }
}
