<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use App\Models\PreQuestionCandidate;

class MarkdownImport extends Model
{
    use HasFactory;

    protected $fillable = [
        'file_name',
        'remote_url',
        'original_markdown',
        'parsed_json',
        'source_type',
        'source_name',
        'status',
        'error_message',
        'progress_stage',
        'progress_message',
        'progress_current',
        'progress_total',
        'progress_updated_at',
        'processing_started_at',
        'processing_finished_at',
    ];

    protected $casts = [
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
        'progress_updated_at' => 'datetime',
        'processing_started_at' => 'datetime',
        'processing_finished_at' => 'datetime',
    ];

    public const STATUS_PENDING = 'pending';
    public const STATUS_PARSED = 'parsed';
    public const STATUS_REVIEWED = 'reviewed';
    public const STATUS_COMPLETED = 'completed';
    public const STATUS_PROCESSING = 'processing';
    public const STATUS_FAILED = 'failed';

    public const STAGE_QUEUED = 'queued';
    public const STAGE_SPLITTING = 'splitting';
    public const STAGE_AI_PARSING = 'ai_parsing';
    public const STAGE_WRITING = 'writing';
    public const STAGE_PARSED = 'parsed';
    public const STAGE_COMPLETED = 'completed';
    public const STAGE_FAILED = 'failed';

    public function candidates(): HasMany
    {
        return $this->hasMany(PreQuestionCandidate::class, 'import_id');
    }

    public function preQuestions(): HasMany
    {
        return $this->hasMany(PreQuestion::class, 'import_id');
    }

    public function getStatusBadgeAttribute(): string
    {
        $badges = [
            self::STATUS_PENDING => 'gray',
            self::STATUS_PARSED => 'info',
            self::STATUS_REVIEWED => 'warning',
            self::STATUS_COMPLETED => 'success',
        ];

        return $badges[$this->status] ?? 'gray';
    }

    public function getProgressLabelAttribute(): string
    {
        $stageLabel = match ($this->progress_stage) {
            self::STAGE_QUEUED => '已排队',
            self::STAGE_SPLITTING => '拆题中',
            self::STAGE_AI_PARSING => 'AI 解析中',
            self::STAGE_WRITING => '写入候选库',
            self::STAGE_PARSED => '已解析',
            self::STAGE_COMPLETED => '已完成',
            self::STAGE_FAILED => '失败',
            default => $this->progress_stage ?: '—',
        };

        if (($this->progress_total ?? 0) > 0) {
            $total = (int) $this->progress_total;
            $current = min((int) ($this->progress_current ?? 0), $total);
            return sprintf(
                '%s %d/%d',
                $stageLabel,
                $current,
                $total
            );
        }

        return $stageLabel;
    }

    public function getProgressPercentAttribute(): ?int
    {
        $total = (int) ($this->progress_total ?? 0);
        if ($total <= 0) {
            return null;
        }

        $current = (int) ($this->progress_current ?? 0);
        return (int) max(0, min(100, round(($current / $total) * 100)));
    }

    public function getParsedCountAttribute(): int
    {
        if (array_key_exists('parsed_count', $this->attributes)) {
            return (int) $this->attributes['parsed_count'];
        }

        return $this->candidates()
            ->where('status', '!=', PreQuestionCandidate::STATUS_SUPERSEDED)
            ->count();
    }

    public function getAcceptedCountAttribute(): int
    {
        if (array_key_exists('accepted_count', $this->attributes)) {
            return (int) $this->attributes['accepted_count'];
        }

        return $this->candidates()
            ->where('status', '!=', PreQuestionCandidate::STATUS_SUPERSEDED)
            ->where('is_question_candidate', true)
            ->count();
    }

    /**
     * 获取切分后的候选题目（新的切分格式）
     */
    public function getSplitCandidatesAttribute(): array
    {
        if (!$this->parsed_json) {
            return [];
        }

        $data = json_decode($this->parsed_json, true);

        return $data['candidates'] ?? [];
    }

    /**
     * 获取统计信息
     */
    public function getSplitStatisticsAttribute(): array
    {
        if (!$this->parsed_json) {
            return [];
        }

        $data = json_decode($this->parsed_json, true);

        return $data['statistics'] ?? [];
    }

    /**
     * 检查是否已完成
     */
    public function isCompleted(): bool
    {
        return $this->status === self::STATUS_COMPLETED;
    }

    /**
     * 检查是否正在处理
     */
    public function isProcessing(): bool
    {
        return $this->status === self::STATUS_PROCESSING;
    }

    /**
     * 检查是否失败
     */
    public function isFailed(): bool
    {
        return $this->status === self::STATUS_FAILED;
    }

    /**
     * 获取状态标签
     */
    public function getStatusLabelAttribute(): string
    {
        return match ($this->status) {
            self::STATUS_PENDING => '等待处理',
            self::STATUS_PROCESSING => '处理中',
            self::STATUS_COMPLETED => '已完成',
            self::STATUS_FAILED => '处理失败',
            self::STATUS_PARSED => '已解析',
            self::STATUS_REVIEWED => '已审核',
            default => '未知',
        };
    }

    /**
     * 获取状态颜色
     */
    public function getSplitStatusColorAttribute(): string
    {
        return match ($this->status) {
            self::STATUS_PENDING => 'gray',
            self::STATUS_PROCESSING => 'warning',
            self::STATUS_COMPLETED => 'success',
            self::STATUS_FAILED => 'danger',
            self::STATUS_PARSED => 'info',
            self::STATUS_REVIEWED => 'primary',
            default => 'gray',
        };
    }

    /**
     * 检查并修复卡住的状态（超过30分钟无进度则重置）
     */
    public function checkAndFixStuckStatus(): void
    {
        if ($this->status !== self::STATUS_PROCESSING) {
            return;
        }

        // 超过30分钟无进度则重置
        if ($this->progress_updated_at?->lt(now()->subMinutes(30))) {
            \Log::warning('Auto-fixing stuck markdown import', [
                'import_id' => $this->id,
                'last_update' => $this->progress_updated_at,
            ]);

            $this->update([
                'status' => self::STATUS_PENDING,
                'progress_stage' => self::STAGE_QUEUED,
                'progress_message' => '自动重置为待处理（超时）',
                'error_message' => '队列任务可能已丢失，请重新提交',
                'processing_finished_at' => now(),
            ]);
        }
    }

    /**
     * 静态方法：批量检查并修复卡住的记录
     */
    public static function checkAndFixAllStuckRecords(): int
    {
        $stuckRecords = self::where('status', self::STATUS_PROCESSING)
            ->where('progress_updated_at', '<', now()->subMinutes(30))
            ->get();

        $fixed = 0;
        foreach ($stuckRecords as $record) {
            $record->checkAndFixStuckStatus();
            $fixed++;
        }

        if ($fixed > 0) {
            \Log::info('Auto-fixed stuck markdown imports', [
                'count' => $fixed,
            ]);
        }

        return $fixed;
    }

    public function parseFilename(): array
    {
        if (empty($this->file_name)) {
            return [];
        }

        $base = pathinfo((string) $this->file_name, PATHINFO_FILENAME);
        $parts = array_map('trim', explode('_', $base));
        if (count($parts) < 4) {
            return [];
        }

        $series = $parts[0] ?? null;
        $grade = isset($parts[1]) && is_numeric($parts[1]) ? (int) $parts[1] : null;
        $termFlag = isset($parts[2]) && is_numeric($parts[2]) ? (int) $parts[2] : null;
        $subject = $parts[3] ?? null;
        $name = trim(implode('_', array_slice($parts, 4)));

        $term = match ($termFlag) {
            1 => '上册',
            2 => '下册',
            0 => '上下册',
            default => null,
        };

        return [
            'series' => $series,
            'grade' => $grade,
            'term' => $term,
            'subject' => $subject,
            'name' => $name !== '' ? $name : $base,
        ];
    }
}
