<?php

namespace App\Services;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Collection;

/**
 * 知识掌握度计算引擎（PHP版本）
 * 基于BKT（Bayesian Knowledge Tracing）模型和多种因素综合计算
 *
 * 参考LearningAnalytics的Python实现迁移而来
 */
class MasteryCalculator
{
    /**
     * 难度权重配置
     * 简单题目权重低，困难题目权重高
     */
    private const DIFFICULTY_WEIGHTS = [
        0.30 => 0.8,   // 简单题目权重
        0.60 => 1.0,   // 中等题目权重
        0.85 => 1.3,   // 困难题目权重
    ];

    /**
     * 时间效率基准值（秒）
     * 不同难度题目的平均完成时间
     */
    private const TIME_BASELINE = [
        0.30 => 60,    // 简单题平均用时
        0.60 => 120,   // 中等题平均用时
        0.85 => 180,   // 困难题平均用时
    ];

    /**
     * 掌握度阈值配置
     */
    private const MASTERY_THRESHOLD_WEAK = 0.50;   // 薄弱点阈值
    private const MASTERY_THRESHOLD_GOOD = 0.70;   // 良好阈值
    private const MASTERY_THRESHOLD_MASTER = 0.85; // 掌握阈值

    /**
     * 最小练习题目数量
     */
    private const MIN_PRACTICE_QUESTIONS = 5;

    /**
     * 最小正确率要求
     */
    private const MIN_CORRECT_RATE = 0.60;

    /**
     * 计算学生对指定知识点的掌握度
     *
     * @param string $studentId 学生ID
     * @param string $kpCode 知识点编码
     * @param array|null $attempts 答题记录（可选，默认从数据库查询）
     * @return array 返回['mastery' => 掌握度, 'confidence' => 置信度, 'trend' => 趋势]
     */
    public function calculateMasteryLevel(string $studentId, string $kpCode, ?array $attempts = null): array
    {
        // 如果没有提供答题记录，从数据库查询
        if ($attempts === null) {
            $attempts = $this->getStudentAttempts($studentId, $kpCode);
        }

        if (empty($attempts)) {
            return [
                'mastery' => 0.0,
                'confidence' => 0.0,
                'trend' => 'insufficient',
                'total_attempts' => 0,
                'correct_attempts' => 0,
                'accuracy_rate' => 0.0,
            ];
        }

        // 1. 计算基础正确率
        $accuracyRate = $this->calculateAccuracyRate($attempts);

        // 2. 计算难度加权分数
        $difficultyScore = $this->calculateDifficultyScore($attempts);

        // 3. 计算时间效率分数
        $timeScore = $this->calculateTimeEfficiency($attempts);

        // 4. 计算技能熟练度影响
        $skillFactor = $this->calculateSkillFactor($attempts);

        // 5. 应用遗忘曲线衰减
        $decayFactor = $this->calculateDecayFactor($attempts);

        // 6. 综合计算掌握度
        $baseMastery = $accuracyRate *
                      $difficultyScore *
                      $timeScore *
                      $skillFactor *
                      $decayFactor;

        // 7. 计算置信度
        $confidence = $this->calculateConfidence($attempts);

        // 8. 判断趋势
        $trend = $this->determineTrend($attempts);

        // 9. 计算统计信息
        $totalAttempts = count($attempts);
        $correctAttempts = count(array_filter($attempts, fn($a) => $a['is_correct']));

        Log::info('MasteryCalculator::calculateMasteryLevel', [
            'student_id' => $studentId,
            'kp_code' => $kpCode,
            'total_attempts' => $totalAttempts,
            'correct_attempts' => $correctAttempts,
            'accuracy_rate' => $accuracyRate,
            'difficulty_score' => $difficultyScore,
            'time_score' => $timeScore,
            'skill_factor' => $skillFactor,
            'decay_factor' => $decayFactor,
            'final_mastery' => $baseMastery,
            'confidence' => $confidence,
            'trend' => $trend,
        ]);

        return [
            'mastery' => round($baseMastery, 4),
            'confidence' => round($confidence, 4),
            'trend' => $trend,
            'total_attempts' => $totalAttempts,
            'correct_attempts' => $correctAttempts,
            'accuracy_rate' => round($accuracyRate * 100, 2),
            'details' => [
                'accuracy_rate' => $accuracyRate,
                'difficulty_score' => $difficultyScore,
                'time_score' => $timeScore,
                'skill_factor' => $skillFactor,
                'decay_factor' => $decayFactor,
            ],
        ];
    }

    /**
     * 计算正确率
     */
    private function calculateAccuracyRate(array $attempts): float
    {
        if (empty($attempts)) {
            return 0.0;
        }

        $totalAttempts = count($attempts);
        $correctAttempts = count(array_filter($attempts, fn($a) => $a['is_correct']));
        $partialAttempts = count(array_filter($attempts, function($a) {
            return isset($a['partial_score']) && floatval($a['partial_score']) > 0;
        }));

        // 部分正确按50%计算
        $correctScore = $correctAttempts + $partialAttempts * 0.5;
        $accuracy = $correctScore / $totalAttempts;

        return min($accuracy, 1.0);
    }

    /**
     * 计算难度加权分数
     */
    private function calculateDifficultyScore(array $attempts): float
    {
        if (empty($attempts)) {
            return 0.0;
        }

        $weightedSum = 0.0;
        $totalWeight = 0.0;

        foreach ($attempts as $attempt) {
            $difficulty = floatval($attempt['question_difficulty'] ?? 0.6);
            $weight = self::DIFFICULTY_WEIGHTS[$difficulty] ?? 1.0;
            $score = $attempt['is_correct'] ? 1.0 : 0.0;

            $weightedSum += $score * $weight;
            $totalWeight += $weight;
        }

        if ($totalWeight == 0) {
            return 0.0;
        }

        return $weightedSum / $totalWeight;
    }

    /**
     * 计算时间效率分数
     */
    private function calculateTimeEfficiency(array $attempts): float
    {
        if (empty($attempts)) {
            return 0.0;
        }

        $efficiencyScores = [];

        foreach ($attempts as $attempt) {
            $difficulty = floatval($attempt['question_difficulty'] ?? 0.6);
            $baseline = self::TIME_BASELINE[$difficulty] ?? 120;
            $actualTime = floatval($attempt['attempt_time_seconds'] ?? 120);

            // 时间效率：基准时间/实际用时，最大不超过1.5
            $efficiency = min($baseline / max($actualTime, 1), 1.5);
            $efficiencyScores[] = $efficiency;
        }

        // 取最近5次答题的平均效率
        $recentEfficiency = array_slice($efficiencyScores, -5);
        $avgEfficiency = array_sum($recentEfficiency) / count($recentEfficiency);

        return min($avgEfficiency, 1.0);
    }

    /**
     * 计算技能熟练度影响
     */
    private function calculateSkillFactor(array $attempts, ?array $skillProficiency = null): float
    {
        // 简化实现：如果有技能熟练度数据，使用它；否则返回1.0
        if ($skillProficiency && !empty($skillProficiency)) {
            // 计算平均技能熟练度
            $avgProficiency = array_sum($skillProficiency) / count($skillProficiency);
            // 技能熟练度加权：范围0.8-1.2
            return 0.8 + ($avgProficiency * 0.4);
        }

        return 1.0;
    }

    /**
     * 计算遗忘曲线衰减因子
     */
    private function calculateDecayFactor(array $attempts): float
    {
        if (empty($attempts)) {
            return 0.0;
        }

        // 获取最近一次答题时间
        $lastAttemptTime = null;
        foreach ($attempts as $attempt) {
            $attemptTime = strtotime($attempt['completed_at'] ?? $attempt['created_at'] ?? 'now');
            if ($lastAttemptTime === null || $attemptTime > $lastAttemptTime) {
                $lastAttemptTime = $attemptTime;
            }
        }

        if ($lastAttemptTime === null) {
            return 1.0;
        }

        // 计算距离现在的天数
        $daysSinceLastAttempt = (time() - $lastAttemptTime) / 86400; // 86400 = 24*60*60

        // 遗忘曲线：每天衰减2%，最大衰减50%
        $decayRate = min($daysSinceLastAttempt * 0.02, 0.5);
        $decayFactor = 1.0 - $decayRate;

        return max($decayFactor, 0.5); // 最低保持50%
    }

    /**
     * 计算置信度
     */
    private function calculateConfidence(array $attempts): float
    {
        if (empty($attempts)) {
            return 0.0;
        }

        $totalAttempts = count($attempts);

        // 基于答题次数的置信度：答题越多，置信度越高
        // 5次以下线性增长，5次以上增长放缓
        if ($totalAttempts < 5) {
            $baseConfidence = $totalAttempts / 5.0;
        } else {
            $baseConfidence = 0.5 + (1.0 - 0.5) * (1 - exp(-($totalAttempts - 5) / 10));
        }

        // 正确率也影响置信度
        $accuracyRate = $this->calculateAccuracyRate($attempts);
        $accuracyFactor = 0.5 + $accuracyRate * 0.5;

        // 综合置信度
        $confidence = $baseConfidence * $accuracyFactor;

        return min($confidence, 1.0);
    }

    /**
     * 判断学习趋势
     */
    private function determineTrend(array $attempts): string
    {
        if (count($attempts) < 3) {
            return 'insufficient'; // 数据不足
        }

        // 按时间排序
        usort($attempts, function($a, $b) {
            $timeA = strtotime($a['completed_at'] ?? $a['created_at'] ?? 0);
            $timeB = strtotime($b['completed_at'] ?? $b['created_at'] ?? 0);
            return $timeA <=> $timeB;
        });

        // 分为前后两部分
        $midPoint = intdiv(count($attempts), 2);
        $firstHalf = array_slice($attempts, 0, $midPoint);
        $secondHalf = array_slice($attempts, $midPoint);

        $firstHalfAccuracy = $this->calculateAccuracyRate($firstHalf);
        $secondHalfAccuracy = $this->calculateAccuracyRate($secondHalf);

        $improvement = $secondHalfAccuracy - $firstHalfAccuracy;

        if ($improvement > 0.1) {
            return 'improving'; // 提升
        } elseif ($improvement < -0.1) {
            return 'declining'; // 下降
        } else {
            return 'stable'; // 稳定
        }
    }

    /**
     * 获取学生的答题记录
     */
    private function getStudentAttempts(string $studentId, string $kpCode): array
    {
        $attempts = DB::table('student_attempts')
            ->where('student_id', $studentId)
            ->where('kp_code', $kpCode)
            ->orderBy('created_at', 'asc')
            ->get();

        return $attempts->map(function ($item) {
            return (array) $item;
        })->toArray();
    }

    /**
     * 批量更新学生掌握度
     */
    public function batchUpdateMastery(string $studentId, array $kpCodes): array
    {
        $results = [];

        foreach ($kpCodes as $kpCode) {
            $masteryData = $this->calculateMasteryLevel($studentId, $kpCode);

            // 保存到数据库
            DB::table('student_knowledge_mastery')
                ->updateOrInsert(
                    ['student_id' => $studentId, 'kp_code' => $kpCode],
                    [
                        'mastery_level' => $masteryData['mastery'],
                        'confidence_level' => $masteryData['confidence'],
                        'total_attempts' => $masteryData['total_attempts'],
                        'correct_attempts' => $masteryData['correct_attempts'],
                        'mastery_trend' => $masteryData['trend'],
                        'last_mastery_update' => now(),
                        'updated_at' => now(),
                    ]
                );

            $results[$kpCode] = $masteryData;
        }

        return $results;
    }

    /**
     * 获取学生所有知识点的掌握度概览
     */
    public function getStudentMasteryOverview(string $studentId): array
    {
        $masteryList = DB::table('student_knowledge_mastery')
            ->where('student_id', $studentId)
            ->get();

        if ($masteryList->isEmpty()) {
            return [
                'total_knowledge_points' => 0,
                'average_mastery_level' => 0.0,
                'mastered_knowledge_points' => 0,
                'good_knowledge_points' => 0,
                'weak_knowledge_points' => 0,
                'weak_knowledge_points_list' => [],
                'details' => [],
            ];
        }

        $masteryArray = $masteryList->toArray();

        $total = count($masteryArray);
        $average = $masteryArray ? array_sum(array_column($masteryArray, 'mastery_level')) / $total : 0;

        $mastered = [];
        $good = [];
        $weak = [];

        foreach ($masteryArray as $item) {
            $level = floatval($item->mastery_level);
            if ($level >= self::MASTERY_THRESHOLD_MASTER) {
                $mastered[] = $item;
            } elseif ($level >= self::MASTERY_THRESHOLD_GOOD) {
                $good[] = $item;
            } else {
                $weak[] = $item;
            }
        }

        return [
            'total_knowledge_points' => $total,
            'average_mastery_level' => round($average, 4),
            'mastered_knowledge_points' => count($mastered),
            'good_knowledge_points' => count($good),
            'weak_knowledge_points' => count($weak),
            'weak_knowledge_points_list' => $weak,
            'details' => $masteryArray,
        ];
    }
}
