<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class StudentKnowledgeMastery extends Model
{
    use HasFactory;

    protected $table = 'student_knowledge_mastery';

    protected $fillable = [
        'student_id',
        'kp_code',
        'mastery_level',
        'direct_mastery_level', // 直接学习掌握度（答题计算），判断达标时优先使用
        'confidence_level',
        'total_attempts',
        'correct_attempts',
        'incorrect_attempts',
        'partial_attempts',
        'avg_time_seconds',
        'fastest_time',
        'slowest_time',
        'attempts_easy',
        'attempts_medium',
        'attempts_hard',
        'correct_easy',
        'correct_medium',
        'correct_hard',
        'first_attempt_at',
        'last_attempt_at',
        'last_mastery_update',
        'mastery_trend',
        'mastery_change',
        'calculation_version',
        'notes',
    ];

    protected $casts = [
        'mastery_level' => 'decimal:4',
        'direct_mastery_level' => 'decimal:4',
        'confidence_level' => 'decimal:4',
        'mastery_change' => 'decimal:4',
        'avg_time_seconds' => 'decimal:2',
        'first_attempt_at' => 'datetime',
        'last_attempt_at' => 'datetime',
        'last_mastery_update' => 'datetime',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
    ];

    /**
     * 关联学生
     */
    public function student(): BelongsTo
    {
        return $this->belongsTo(Student::class, 'student_id', 'student_id');
    }

    /**
     * 关联知识点
     */
    public function knowledgePoint(): BelongsTo
    {
        return $this->belongsTo(KnowledgePoint::class, 'kp_code', 'kp_code');
    }

    /**
     * 作用域：按学生筛选
     */
    public function scopeForStudent($query, string $studentId)
    {
        return $query->where('student_id', $studentId);
    }

    /**
     * 作用域：按知识点筛选
     */
    public function scopeForKnowledgePoint($query, string $kpCode)
    {
        return $query->where('kp_code', $kpCode);
    }

    /**
     * 作用域：薄弱点（掌握度低于阈值）
     */
    public function scopeWeaknesses($query, float $threshold = 0.7)
    {
        return $query->where('mastery_level', '<', $threshold);
    }

    /**
     * 作用域：按掌握度排序
     */
    public function scopeOrderByMastery($query, string $direction = 'asc')
    {
        return $query->orderBy('mastery_level', $direction);
    }

    /**
     * 获取薄弱点列表
     */
    public static function getWeaknesses(string $studentId, float $threshold = 0.7, int $limit = 20): array
    {
        return self::forStudent($studentId)
            ->weaknesses($threshold)
            ->orderByMastery('asc')
            ->limit($limit)
            ->get()
            ->toArray();
    }

    public static function allAtLeast(int $studentId, array $kpCodes, float $threshold): bool
    {
        if (empty($kpCodes)) {
            return false;
        }

        // 使用 DB::table 避免 Eloquent accessor 把数字转成文字标签
        // 【新增】同时获取 direct_mastery_level，判断时优先使用
        $records = \Illuminate\Support\Facades\DB::table('student_knowledge_mastery')
            ->where('student_id', $studentId)
            ->whereIn('kp_code', $kpCodes)
            ->get(['kp_code', 'mastery_level', 'direct_mastery_level'])
            ->keyBy('kp_code');

        foreach ($kpCodes as $kpCode) {
            $record = $records->get($kpCode);
            // 取 direct_mastery_level 和 mastery_level 的最大值
            // 避免"学了之后反而从达标变成未达标"的问题
            if ($record) {
                $direct = $record->direct_mastery_level;
                $mastery = (float) $record->mastery_level;
                $level = $direct !== null ? max((float) $direct, $mastery) : $mastery;
            } else {
                $level = 0.0;
            }
            if ($level < $threshold) {
                return false;
            }
        }

        return true;
    }

    /**
     * 判断所有知识点是否达标（跳过没有题目的知识点）
     * 用于章节摸底后的知识点学习流程
     *
     * @param  int  $studentId  学生ID
     * @param  array  $kpCodes  知识点编码列表
     * @param  float  $threshold  达标阈值（默认0.9）
     * @return bool 是否全部达标
     */
    public static function allAtLeastSkipNoQuestions(int $studentId, array $kpCodes, float $threshold = 0.9): bool
    {
        if (empty($kpCodes)) {
            return true; // 没有知识点，视为达标
        }

        // 获取掌握度（使用 DB::table 避免 Eloquent accessor 把数字转成文字标签）
        // 【新增】同时获取 direct_mastery_level，判断时优先使用
        $records = \Illuminate\Support\Facades\DB::table('student_knowledge_mastery')
            ->where('student_id', $studentId)
            ->whereIn('kp_code', $kpCodes)
            ->get(['kp_code', 'mastery_level', 'direct_mastery_level'])
            ->keyBy('kp_code');

        // 获取有题目的知识点
        $kpCodesWithQuestions = \App\Models\Question::query()
            ->whereIn('kp_code', $kpCodes)
            ->distinct()
            ->pluck('kp_code')
            ->toArray();

        $hasAnyKpWithQuestions = false;

        foreach ($kpCodes as $kpCode) {
            // 跳过没有题目的知识点
            if (! in_array($kpCode, $kpCodesWithQuestions)) {
                continue;
            }

            $hasAnyKpWithQuestions = true;

            // 取 direct_mastery_level 和 mastery_level 的最大值
            // 避免"学了之后反而从达标变成未达标"的问题
            $record = $records->get($kpCode);
            if ($record) {
                $direct = $record->direct_mastery_level;
                $mastery = (float) $record->mastery_level;
                $level = $direct !== null ? max((float) $direct, $mastery) : $mastery;
            } else {
                $level = 0.0;
            }
            if ($level < $threshold) {
                return false;
            }
        }

        // 如果没有任何有题的知识点，视为达标
        return $hasAnyKpWithQuestions ? true : true;
    }

    /**
     * 获取第一个未达标的知识点（跳过没有题目的知识点）
     *
     * @param  int  $studentId  学生ID
     * @param  array  $kpCodes  知识点编码列表（按顺序）
     * @param  float  $threshold  达标阈值（默认0.9）
     * @return string|null 第一个未达标的知识点编码，如果全部达标返回null
     */
    public static function getFirstUnmasteredKpCode(int $studentId, array $kpCodes, float $threshold = 0.9): ?string
    {
        if (empty($kpCodes)) {
            return null;
        }

        // 获取掌握度（使用 DB::table 避免 Eloquent accessor 把数字转成文字标签）
        // 【新增】同时获取 direct_mastery_level，判断时优先使用
        $records = \Illuminate\Support\Facades\DB::table('student_knowledge_mastery')
            ->where('student_id', $studentId)
            ->whereIn('kp_code', $kpCodes)
            ->get(['kp_code', 'mastery_level', 'direct_mastery_level'])
            ->keyBy('kp_code');

        // 获取有题目的知识点
        $kpCodesWithQuestions = \App\Models\Question::query()
            ->whereIn('kp_code', $kpCodes)
            ->distinct()
            ->pluck('kp_code')
            ->toArray();

        foreach ($kpCodes as $kpCode) {
            // 跳过没有题目的知识点
            if (! in_array($kpCode, $kpCodesWithQuestions)) {
                continue;
            }

            // 取 direct_mastery_level 和 mastery_level 的最大值
            // 避免"学了之后反而从达标变成未达标"的问题
            $record = $records->get($kpCode);
            if ($record) {
                $direct = $record->direct_mastery_level;
                $mastery = (float) $record->mastery_level;
                $level = $direct !== null ? max((float) $direct, $mastery) : $mastery;
            } else {
                $level = 0.0;
            }
            if ($level < $threshold) {
                return $kpCode;
            }
        }

        return null; // 全部达标
    }

    /**
     * 计算掌握度等级
     */
    public function getMasteryLevelAttribute($value): float
    {
        return (float) $value;
    }

    /**
     * 获取掌握度等级标签
     */
    public function getMasteryLevelLabelAttribute(): string
    {
        $value = $this->mastery_level;
        if ($value >= 0.9) {
            return '优秀';
        } elseif ($value >= 0.70) {
            return '良好';
        } elseif ($value >= 0.50) {
            return '及格';
        } else {
            return '薄弱';
        }
    }

    /**
     * 获取趋势标签
     */
    public function getTrendLabelAttribute(): string
    {
        return match ($this->mastery_trend) {
            'improving' => '上升',
            'declining' => '下降',
            'stable' => '稳定',
            'insufficient' => '数据不足',
            default => '未知',
        };
    }

    /**
     * 计算成功率
     */
    public function getSuccessRateAttribute(): float
    {
        if ($this->total_attempts <= 0) {
            return 0.0;
        }

        return round(($this->correct_attempts / $this->total_attempts) * 100, 2);
    }
}
