<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Support\Str;

/**
 * Model: RForumReply (Forum Reply/Comment)
 * 
 * Represents replies to forum threads with threading support.
 * Supports mentions, reactions, and moderation.
 * 
 * @property int $id
 * @property int $thread_id
 * @property int $user_id
 * @property int|null $parent_id
 * @property string $content
 * @property array|null $mentions
 * @property string $status
 * @property bool $is_approved
 * @property int $helpful_count
 * @property int $reactions_count
 * @property bool $is_best_answer
 * @property bool $is_edited
 * @property \Carbon\Carbon|null $edited_at
 */
class RForumReply extends Model
{
    use HasFactory, SoftDeletes;

    protected $table = 'r_forum_replies';

    protected $fillable = [
        'thread_id',
        'user_id',
        'parent_id',
        'content',
        'mentions',
        'status',
        'is_approved',
        'helpful_count',
        'reactions_count',
        'is_best_answer',
        'marked_best_by',
        'is_edited',
        'edited_at',
        'edited_by',
        'ip_address',
    ];

    protected $casts = [
        'mentions' => 'array',
        'is_approved' => 'boolean',
        'helpful_count' => 'integer',
        'reactions_count' => 'integer',
        'is_best_answer' => 'boolean',
        'is_edited' => 'boolean',
        'edited_at' => 'datetime',
    ];

    /**
     * Status constants.
     */
    const STATUS_PUBLISHED = 'published';
    const STATUS_HIDDEN = 'hidden';
    const STATUS_DELETED = 'deleted';
    const STATUS_PENDING = 'pending';
    const STATUS_SPAM = 'spam';

    /**
     * Get the thread this reply belongs to.
     */
    public function thread(): BelongsTo
    {
        return $this->belongsTo(RForumThread::class, 'thread_id');
    }

    /**
     * Get the reply author.
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class, 'user_id');
    }

    /**
     * Get the parent reply (for nested replies).
     */
    public function parent(): BelongsTo
    {
        return $this->belongsTo(self::class, 'parent_id');
    }

    /**
     * Get child replies (nested).
     */
    public function replies(): HasMany
    {
        return $this->hasMany(self::class, 'parent_id')
                    ->where('status', self::STATUS_PUBLISHED)
                    ->orderBy('created_at');
    }

    /**
     * Get file attachments for this reply.
     */
    public function attachments(): MorphMany
    {
        return $this->morphMany(RForumAttachment::class, 'attachable');
    }

    /**
     * Get the user who marked as best answer.
     */
    public function markedBestByUser(): BelongsTo
    {
        return $this->belongsTo(User::class, 'marked_best_by');
    }

    /**
     * Get the user who edited.
     */
    public function editedByUser(): BelongsTo
    {
        return $this->belongsTo(User::class, 'edited_by');
    }

    /**
     * Scope: Published replies.
     */
    public function scopePublished($query)
    {
        return $query->where('status', self::STATUS_PUBLISHED)
                     ->where('is_approved', true);
    }

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

    /**
     * Scope: Best answers.
     */
    public function scopeBestAnswers($query)
    {
        return $query->where('is_best_answer', true);
    }

    /**
     * Scope: Root replies (not nested).
     */
    public function scopeRoot($query)
    {
        return $query->whereNull('parent_id');
    }

    /**
     * Scope: By thread.
     */
    public function scopeForThread($query, int $threadId)
    {
        return $query->where('thread_id', $threadId);
    }

    /**
     * Scope: By user.
     */
    public function scopeByUser($query, int $userId)
    {
        return $query->where('user_id', $userId);
    }

    /**
     * Scope: With helpful count.
     */
    public function scopeWithHelpful($query)
    {
        return $query->where('helpful_count', '>', 0)
                     ->orderByDesc('helpful_count');
    }

    /**
     * Check if reply is visible.
     */
    public function isVisible(): bool
    {
        return $this->status === self::STATUS_PUBLISHED && $this->is_approved;
    }

    /**
     * Check if reply can be edited.
     */
    public function canEdit(): bool
    {
        // Can edit within 30 minutes of posting
        return $this->created_at->diffInMinutes(now()) <= 30;
    }

    /**
     * Check if user is author.
     */
    public function isAuthor(int $userId): bool
    {
        return $this->user_id === $userId;
    }

    /**
     * Check if is a nested reply.
     */
    public function isNested(): bool
    {
        return $this->parent_id !== null;
    }

    /**
     * Mark as best answer.
     */
    public function markAsBest(int $userId): void
    {
        // Remove best answer from other replies
        static::where('thread_id', $this->thread_id)
              ->where('is_best_answer', true)
              ->update(['is_best_answer' => false]);

        $this->update([
            'is_best_answer' => true,
            'marked_best_by' => $userId,
        ]);
    }

    /**
     * Unmark as best answer.
     */
    public function unmarkAsBest(): void
    {
        $this->update([
            'is_best_answer' => false,
            'marked_best_by' => null,
        ]);
    }

    /**
     * Increment helpful count.
     */
    public function markHelpful(): void
    {
        $this->increment('helpful_count');
    }

    /**
     * Decrement helpful count.
     */
    public function unmarkHelpful(): void
    {
        if ($this->helpful_count > 0) {
            $this->decrement('helpful_count');
        }
    }

    /**
     * Hide the reply.
     */
    public function hide(): void
    {
        $this->update(['status' => self::STATUS_HIDDEN]);
    }

    /**
     * Restore the reply.
     */
    public function restoreReply(): void
    {
        $this->update(['status' => self::STATUS_PUBLISHED]);
    }

    /**
     * Mark as edited.
     */
    public function markAsEdited(int $userId): void
    {
        $this->update([
            'is_edited' => true,
            'edited_at' => now(),
            'edited_by' => $userId,
        ]);
    }

    /**
     * Extract mentions from content.
     */
    public function extractMentions(): array
    {
        preg_match_all('/@(\w+)/', $this->content, $matches);
        return $matches[1] ?? [];
    }

    /**
     * Get excerpt for preview.
     */
    public function getExcerptAttribute(): string
    {
        return Str::limit(strip_tags($this->content), 150);
    }

    /**
     * Get status color.
     */
    public function getStatusColorAttribute(): string
    {
        return match($this->status) {
            self::STATUS_PUBLISHED => 'green',
            self::STATUS_HIDDEN => 'yellow',
            self::STATUS_DELETED => 'red',
            self::STATUS_PENDING => 'blue',
            self::STATUS_SPAM => 'red',
            default => 'gray',
        };
    }

    /**
     * Get depth level for nested replies.
     */
    public function getDepthAttribute(): int
    {
        $depth = 0;
        $parent = $this->parent;

        while ($parent) {
            $depth++;
            $parent = $parent->parent;
        }

        return $depth;
    }
}
