<?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\HasOne;
use Illuminate\Support\Str;

/**
 * KnowledgeBaseQuestion Model
 * 
 * Represents a Q&A question in the knowledge base.
 * Managed by authorized users (Managers+) with proper workflow.
 * 
 * @property int $id
 * @property string $title
 * @property string $slug
 * @property string $content
 * @property string|null $excerpt
 * @property int $category_id
 * @property int $user_id
 * @property string $status
 * @property bool $is_published
 * @property bool $is_featured
 * @property int $view_count
 * @property int $answer_count
 * @property int $helpful_count
 * @property string $difficulty
 * @property array|null $tags
 * @property string|null $meta_title
 * @property string|null $meta_description
 * @property string|null $meta_keywords
 * @property array|null $schema_data
 * @property \Carbon\Carbon|null $published_at
 * @property \Carbon\Carbon|null $created_at
 * @property \Carbon\Carbon|null $updated_at
 * @property \Carbon\Carbon|null $deleted_at
 */
class KnowledgeBaseQuestion extends Model
{
    use HasFactory, SoftDeletes;

    /**
     * Status constants.
     */
    const STATUS_DRAFT = 'draft';
    const STATUS_PUBLISHED = 'published';
    const STATUS_ARCHIVED = 'archived';
    const STATUS_PENDING_REVIEW = 'pending_review';

    /**
     * Difficulty levels.
     */
    const DIFFICULTY_BEGINNER = 'beginner';
    const DIFFICULTY_INTERMEDIATE = 'intermediate';
    const DIFFICULTY_ADVANCED = 'advanced';

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'title',
        'slug',
        'content',
        'excerpt',
        'category_id',
        'user_id',
        'status',
        'is_published',
        'is_featured',
        'view_count',
        'answer_count',
        'helpful_count',
        'difficulty',
        'tags',
        'meta_title',
        'meta_description',
        'meta_keywords',
        'schema_data',
        'published_at',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'is_published' => 'boolean',
        'is_featured' => 'boolean',
        'view_count' => 'integer',
        'answer_count' => 'integer',
        'helpful_count' => 'integer',
        'tags' => 'array',
        'schema_data' => 'array',
        'published_at' => 'datetime',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
        'deleted_at' => 'datetime',
    ];

    /**
     * The attributes that should be appended.
     *
     * @var array<int, string>
     */
    protected $appends = [
        'url',
        'excerpt_preview',
        'has_accepted_answer',
    ];

    /**
     * The "booted" method of the model.
     */
    protected static function booted(): void
    {
        static::creating(function (self $question) {
            if (empty($question->slug)) {
                $question->slug = static::generateUniqueSlug($question->title);
            }
            if (empty($question->excerpt)) {
                $question->excerpt = Str::limit(strip_tags($question->content), 200);
            }
        });

        static::updating(function (self $question) {
            if ($question->isDirty('title') && empty($question->slug)) {
                $question->slug = static::generateUniqueSlug($question->title);
            }
            if ($question->isDirty('content')) {
                $question->excerpt = Str::limit(strip_tags($question->content), 200);
            }
            // Set published_at when first published
            if ($question->isDirty('is_published') && $question->is_published && !$question->published_at) {
                $question->published_at = now();
            }
        });
    }

    /**
     * Generate a unique slug for the question.
     *
     * @param string $title
     * @return string
     */
    public static function generateUniqueSlug(string $title): string
    {
        $slug = Str::slug($title);
        $count = static::withTrashed()
            ->where('slug', 'like', "{$slug}%")
            ->count();

        return $count > 0 ? "{$slug}-{$count}" : $slug;
    }

    /**
     * Get the category this question belongs to.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function category(): BelongsTo
    {
        return $this->belongsTo(KnowledgeBaseCategory::class, 'category_id');
    }

    /**
     * Get the user who created this question.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    /**
     * Get all answers for this question.
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function answers(): HasMany
    {
        return $this->hasMany(KnowledgeBaseAnswer::class, 'question_id');
    }

    /**
     * Get published answers for this question.
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function publishedAnswers(): HasMany
    {
        return $this->answers()
            ->where('is_published', true)
            ->orderByDesc('is_accepted')
            ->orderBy('sort_order');
    }

    /**
     * Get the accepted answer for this question.
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
     */
    public function acceptedAnswer(): HasOne
    {
        return $this->hasOne(KnowledgeBaseAnswer::class, 'question_id')
            ->where('is_accepted', true);
    }

    /**
     * Scope a query to only include published questions.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopePublished($query)
    {
        return $query->where('is_published', true)
            ->where('status', self::STATUS_PUBLISHED);
    }

    /**
     * Scope a query to only include featured questions.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeFeatured($query)
    {
        return $query->where('is_featured', true);
    }

    /**
     * Scope a query to filter by category.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @param int $categoryId
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeByCategory($query, int $categoryId)
    {
        return $query->where('category_id', $categoryId);
    }

    /**
     * Scope a query to filter by difficulty.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @param string $difficulty
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeByDifficulty($query, string $difficulty)
    {
        return $query->where('difficulty', $difficulty);
    }

    /**
     * Scope a query to order by popularity.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopePopular($query)
    {
        return $query->orderByDesc('view_count')
            ->orderByDesc('helpful_count');
    }

    /**
     * Scope a query to order by recent.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeRecent($query)
    {
        return $query->orderByDesc('published_at');
    }

    /**
     * Scope a query to search by title or content.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @param string $search
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeSearch($query, string $search)
    {
        return $query->where(function ($q) use ($search) {
            $q->where('title', 'like', "%{$search}%")
                ->orWhere('content', 'like', "%{$search}%")
                ->orWhereJsonContains('tags', $search);
        });
    }

    /**
     * Increment the view count.
     *
     * @return void
     */
    public function incrementViewCount(): void
    {
        $this->increment('view_count');
    }

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

    /**
     * Update answer count.
     *
     * @return void
     */
    public function updateAnswerCount(): void
    {
        $this->answer_count = $this->answers()->where('is_published', true)->count();
        $this->save();
    }

    /**
     * Check if question has an accepted answer.
     *
     * @return bool
     */
    public function hasAcceptedAnswer(): bool
    {
        return $this->answers()->where('is_accepted', true)->exists();
    }

    /**
     * Get the has_accepted_answer attribute.
     *
     * @return bool
     */
    public function getHasAcceptedAnswerAttribute(): bool
    {
        return $this->hasAcceptedAnswer();
    }

    /**
     * Check if question is published.
     *
     * @return bool
     */
    public function isPublished(): bool
    {
        return $this->is_published && $this->status === self::STATUS_PUBLISHED;
    }

    /**
     * Check if question belongs to user.
     *
     * @param \App\Models\User $user
     * @return bool
     */
    public function isOwnedBy(User $user): bool
    {
        return $this->user_id === $user->id;
    }

    /**
     * Publish the question.
     *
     * @return void
     */
    public function publish(): void
    {
        $this->update([
            'status' => self::STATUS_PUBLISHED,
            'is_published' => true,
            'published_at' => $this->published_at ?? now(),
        ]);

        // Update category questions count
        $this->category?->updateQuestionsCount();
    }

    /**
     * Archive the question.
     *
     * @return void
     */
    public function archive(): void
    {
        $this->update([
            'status' => self::STATUS_ARCHIVED,
            'is_published' => false,
        ]);

        // Update category questions count
        $this->category?->updateQuestionsCount();
    }

    /**
     * Get the URL for this question.
     *
     * @return string
     */
    public function getUrlAttribute(): string
    {
        return route('public.knowledge-base.show', $this->slug);
    }

    /**
     * Get excerpt preview for display.
     *
     * @return string
     */
    public function getExcerptPreviewAttribute(): string
    {
        return $this->excerpt ?? Str::limit(strip_tags($this->content), 200);
    }

    /**
     * Get SEO-friendly meta title.
     *
     * @return string
     */
    public function getSeoTitleAttribute(): string
    {
        return $this->meta_title ?? $this->title . ' - Knowledge Base';
    }

    /**
     * Get SEO-friendly meta description.
     *
     * @return string
     */
    public function getSeoDescriptionAttribute(): string
    {
        return $this->meta_description ?? Str::limit(strip_tags($this->excerpt_preview), 160);
    }

    /**
     * Get reading time in minutes.
     *
     * @return int
     */
    public function getReadingTimeAttribute(): int
    {
        $wordCount = str_word_count(strip_tags($this->content));
        return max(1, (int) ceil($wordCount / 200));
    }

    /**
     * Generate schema.org structured data.
     *
     * @return array
     */
    public function generateSchemaData(): array
    {
        $schema = [
            '@context' => 'https://schema.org',
            '@type' => 'QAPage',
            'mainEntity' => [
                '@type' => 'Question',
                'name' => $this->title,
                'text' => strip_tags($this->content),
                'dateCreated' => $this->created_at->toIso8601String(),
                'author' => [
                    '@type' => 'Person',
                    'name' => $this->user->name ?? 'Anonymous',
                ],
                'answerCount' => $this->answer_count,
            ],
        ];

        if ($this->acceptedAnswer) {
            $schema['mainEntity']['acceptedAnswer'] = [
                '@type' => 'Answer',
                'text' => strip_tags($this->acceptedAnswer->content),
                'dateCreated' => $this->acceptedAnswer->created_at->toIso8601String(),
                'author' => [
                    '@type' => 'Person',
                    'name' => $this->acceptedAnswer->user->name ?? 'Anonymous',
                ],
            ];
        }

        return $schema;
    }
}
