<?php

namespace App\Services;

use App\Models\Paper;
use App\Models\Question;
use App\Models\Student;
use App\Support\PaperNaming;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class QuestionBankService
{
    protected string $baseUrl;

    protected int $timeout;

    protected int $retry;

    protected int $retryDelay;

    protected string $mode;

    public function __construct()
    {
        $this->baseUrl = '';
        $this->timeout = (int) config('question_bank.timeout', 60);
        $this->retry = (int) config('question_bank.retry', 2);
        $this->retryDelay = (int) config('question_bank.retry_delay', 500);
        $this->mode = 'local';
    }

    private function http()
    {
        return Http::timeout($this->timeout)
            ->retry($this->retry, $this->retryDelay);
    }

    /**
     * 从题目内容中提取选项
     */
    private function extractOptions(string $content): array
    {
        // 匹配 A. B. C. D. 格式的选项
        if (preg_match_all('/([A-D])\.\s*(.+?)(?=[A-D]\.|$)/s', $content, $matches, PREG_SET_ORDER)) {
            $options = [];
            foreach ($matches as $match) {
                $optionText = trim($match[2]);
                // 移除末尾的换行和空白
                $optionText = preg_replace('/\s+$/', '', $optionText);
                $options[] = $optionText;
            }

            return $options;
        }

        return [];
    }

    /**
     * 分离题干内容和选项
     */
    private function separateStemAndOptions(string $content): array
    {
        // 如果没有选项，直接返回
        if (! preg_match('/[A-D]\.\s+/m', $content)) {
            return [$content, []];
        }

        // 提取选项
        $options = $this->extractOptions($content);

        // 提取题干（选项前的部分）
        $stem = preg_replace('/[A-D]\.\s+.+?(?=[A-D]\.|$)/s', '', $content);
        $stem = trim($stem);

        // 移除末尾的括号或空白
        $stem = preg_replace('/（）\s*$/', '', $stem);
        $stem = trim($stem);

        return [$stem, $options];
    }

    /**
     * 获取题目列表
     */
    public function listQuestions(int $page = 1, int $perPage = 50, array $filters = []): array
    {
        if ($this->useLocal()) {
            return $this->local()->listQuestions($page, $perPage, $filters);
        }

        try {
            $response = $this->http()
                ->get($this->baseUrl.'/questions', [
                    'page' => $page,
                    'per_page' => $perPage,
                    ...$filters,
                ]);

            if ($response->successful()) {
                info('QuestionBankService::listQuestions', [$response->json()]);

                return $response->json();
            }

            Log::warning('题库API调用失败', [
                'status' => $response->status(),
            ]);
        } catch (\Exception $e) {
            Log::error('获取题目列表失败', [
                'error' => $e->getMessage(),
            ]);
        }

        return ['data' => [], 'meta' => ['total' => 0]];
    }

    /**
     * 获取题目详情
     */
    public function getQuestion(string $questionCode): ?array
    {
        if ($this->useLocal()) {
            return $this->local()->getQuestionByCode($questionCode);
        }

        try {
            $response = $this->http()
                ->get($this->baseUrl."/questions/{$questionCode}");

            if ($response->successful()) {
                return $response->json();
            }

            Log::warning('获取题目详情失败', [
                'code' => $questionCode,
                'status' => $response->status(),
            ]);
        } catch (\Exception $e) {
            Log::error('获取题目详情异常', [
                'code' => $questionCode,
                'error' => $e->getMessage(),
            ]);
        }

        return null;
    }

    /**
     * 更新题目
     */
    public function updateQuestion(string $questionCode, array $payload): bool
    {
        if ($this->useLocal()) {
            return $this->local()->updateQuestionByCode($questionCode, $payload);
        }

        try {
            $response = Http::timeout(10)
                ->patch($this->baseUrl."/questions/{$questionCode}", $payload);

            if ($response->successful()) {
                return true;
            }

            Log::warning('更新题目失败', [
                'code' => $questionCode,
                'status' => $response->status(),
                'body' => $response->json(),
            ]);
        } catch (\Exception $e) {
            Log::error('更新题目异常', [
                'code' => $questionCode,
                'error' => $e->getMessage(),
            ]);
        }

        return false;
    }

    /**
     * 筛选题目 (支持 kp_codes, skills 等高级筛选)
     */
    public function filterQuestions(array $params): array
    {
        if ($this->useLocal()) {
            return $this->local()->listQuestions(
                (int) ($params['page'] ?? 1),
                (int) ($params['per_page'] ?? 50),
                $params
            );
        }

        try {
            $response = Http::timeout(30)
                ->get($this->baseUrl.'/questions', $params);

            if ($response->successful()) {
                info('QuestionBankService::filterQuestions', [$response->json()]);

                return $response->json();
            }

            Log::warning('筛选题目API调用失败', [
                'status' => $response->status(),
                'params' => $params,
            ]);
        } catch (\Exception $e) {
            Log::error('筛选题目异常', [
                'error' => $e->getMessage(),
                'params' => $params,
            ]);
        }

        return ['data' => []];
    }

    /**
     * 批量获取题目详情（根据题目 ID 列表）
     */
    public function getQuestionsByIds(array $ids): array
    {
        if (empty($ids)) {
            return ['data' => []];
        }
        if ($this->useLocal()) {
            return $this->local()->getQuestionsByIds($ids);
        }
        try {
            $response = $this->http()
                ->get($this->baseUrl.'/questions', [
                    'ids' => implode(',', $ids),
                ]);
            if ($response->successful()) {
                return $response->json();
            }
            Log::warning('批量获取题目失败', [
                'ids' => $ids,
                'status' => $response->status(),
            ]);
        } catch (\Exception $e) {
            Log::error('批量获取题目异常', [
                'ids' => $ids,
                'error' => $e->getMessage(),
            ]);
        }

        return ['data' => []];
    }

    /**
     * 智能生成题目（异步模式）
     */
    public function generateIntelligentQuestions(array $params, ?string $callbackUrl = null): array
    {
        if ($this->useLocal()) {
            // 转换参数格式以匹配本地服务的期望
            $localParams = $params;
            if (isset($params['total_questions'])) {
                $localParams['count'] = $params['total_questions'];
                unset($localParams['total_questions']);
            }

            return $this->local()->generateQuestions($localParams);
        }

        try {
            // 添加回调 URL
            if ($callbackUrl) {
                $params['callback_url'] = $callbackUrl;
            }

            // 注意：这里的请求实际上是同步的，会等待响应
            // 真正的异步应该使用 Http::async()
            $response = $this->http()
                ->post($this->baseUrl.'/ai/generate-intelligent-questions', $params);

            if ($response->successful()) {
                return $response->json();
            }

            Log::warning('题目生成API调用失败', [
                'status' => $response->status(),
                'body' => $response->body(),
            ]);
        } catch (\Illuminate\Http\Client\ConnectionException $e) {
            // 连接超时或网络错误
            Log::error('题目生成连接异常', [
                'error' => $e->getMessage(),
                'message' => '可能的原因：1. AI服务未启动 2. 网络连接问题 3. 服务负载过高',
            ]);

            return [
                'success' => false,
                'message' => '连接AI服务失败，请检查服务是否正常运行',
            ];
        } catch (\Exception $e) {
            Log::error('题目生成异常', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);
        }

        return ['success' => false, 'message' => '生成失败'];
    }

    /**
     * 获取任务状态
     */
    public function getTaskStatus(string $taskId): ?array
    {
        if ($this->useLocal()) {
            return null;
        }

        try {
            $response = Http::timeout(10)
                ->get($this->baseUrl.'/tasks/'.$taskId);

            if ($response->successful()) {
                return $response->json();
            }

            Log::warning('获取任务状态失败', [
                'task_id' => $taskId,
                'status' => $response->status(),
            ]);
        } catch (\Exception $e) {
            Log::error('获取任务状态异常', [
                'task_id' => $taskId,
                'error' => $e->getMessage(),
            ]);
        }

        return null;
    }

    /**
     * 获取任务列表
     */
    public function listTasks(?string $status = null, int $page = 1, int $perPage = 10): array
    {
        if ($this->useLocal()) {
            return ['data' => [], 'meta' => ['total' => 0]];
        }

        try {
            $params = [
                'page' => $page,
                'per_page' => $perPage,
            ];

            if ($status) {
                $params['status'] = $status;
            }

            $response = Http::timeout(10)
                ->get($this->baseUrl.'/tasks', $params);

            if ($response->successful()) {
                return $response->json();
            }

            Log::warning('获取任务列表失败', [
                'status' => $response->status(),
            ]);
        } catch (\Exception $e) {
            Log::error('获取任务列表异常', [
                'error' => $e->getMessage(),
            ]);
        }

        return ['data' => [], 'meta' => ['total' => 0]];
    }

    /**
     * 获取题目统计信息
     */
    public function getStatistics(): array
    {
        if ($this->useLocal()) {
            return $this->local()->getStatistics();
        }

        try {
            $response = Http::timeout(10)
                ->get($this->baseUrl.'/questions/statistics');

            if ($response->successful()) {
                return $response->json();
            }

            Log::warning('获取题目统计失败', [
                'status' => $response->status(),
            ]);
        } catch (\Exception $e) {
            Log::error('获取题目统计异常', [
                'error' => $e->getMessage(),
            ]);
        }

        return [
            'total' => 0,
            'by_difficulty' => [],
            'by_kp' => [],
            'by_source' => [],
        ];
    }

    /**
     * 根据知识点获取题目
     */
    public function getQuestionsByKpCode(string $kpCode, int $limit = 100): array
    {
        if ($this->useLocal()) {
            return $this->local()->getQuestionsByKpCode($kpCode, $limit);
        }

        try {
            $response = Http::timeout(10)
                ->get($this->baseUrl.'/questions', [
                    'kp_code' => $kpCode,
                    'limit' => $limit,
                ]);

            if ($response->successful()) {
                return $response->json();
            }
        } catch (\Exception $e) {
            Log::error('根据知识点获取题目失败', [
                'kp_code' => $kpCode,
                'error' => $e->getMessage(),
            ]);
        }

        return [];
    }

    /**
     * 删除题目
     */
    public function deleteQuestion(string $questionCode): bool
    {
        if ($this->useLocal()) {
            return $this->local()->deleteQuestionByCode($questionCode);
        }

        try {
            $response = Http::timeout(10)
                ->delete($this->baseUrl."/questions/{$questionCode}");

            // 只有返回204（删除成功）才返回true，404（不存在）返回false
            if ($response->status() === 204) {
                return true;
            }

            if ($response->status() === 404) {
                Log::warning('尝试删除不存在的题目', ['question_code' => $questionCode]);

                return false;
            }

            return false;
        } catch (\Exception $e) {
            Log::error('删除题目失败', [
                'question_code' => $questionCode,
                'error' => $e->getMessage(),
            ]);

            return false;
        }
    }

    /**
     * 智能选择试卷题目
     */
    public function selectQuestionsForExam(int $totalQuestions, array $filters): array
    {
        if ($this->useLocal()) {
            return $this->local()->selectQuestionsForExam($totalQuestions, $filters);
        }

        $startTime = microtime(true);

        try {
            $requestData = [
                'total_questions' => $totalQuestions,
                'filters' => $filters,
            ];

            \Log::info('开始调用 selectQuestionsForExam', [
                'baseUrl' => $this->baseUrl,
                'totalQuestions' => $totalQuestions,
                'filters' => $filters,
            ]);

            $response = Http::timeout(30)
                ->post($this->baseUrl.'/exam/select-questions', $requestData);

            \Log::info('API响应', [
                'status' => $response->status(),
                'successful' => $response->successful(),
                'body' => $response->body(),
            ]);

            if ($response->successful()) {
                $data = $response->json('data', []);
                \Log::info('成功解析JSON', [
                    'data字段题目数量' => count($data),
                    '耗时' => round((microtime(true) - $startTime) * 1000, 2).'ms',
                ]);

                return $data;
            }

            \Log::error('API调用失败! 状态码: '.$response->status(), [
                '响应内容' => $response->body(),
            ]);
        } catch (\Exception $e) {
            \Log::error('异常: '.$e->getMessage(), [
                '堆栈' => $e->getTraceAsString(),
            ]);
        }

        \Log::info('返回空数组 - 结束');

        return [];
    }

    /**
     * 保存试卷到数据库（本地 papers 表）
     */
    public function saveExamToDatabase(array $examData): ?string
    {
        \Log::info('saveExamToDatabase 被调用', [
            'questions_count' => count($examData['questions'] ?? []),
            'paper_name' => $examData['paper_name'] ?? 'N/A',
            'student_id' => $examData['student_id'] ?? 'N/A',
            'first_question_id' => ! empty($examData['questions']) ? ($examData['questions'][0]['id'] ?? 'N/A') : 'N/A',
        ]);

        // 数据完整性检查
        if (empty($examData['questions'])) {
            \Log::warning('❌ 题目为空，返回null! 这是导致生成demo ID的原因!');

            return null;
        }

        try {
            // 使用数据库事务确保数据一致性
            return \Illuminate\Support\Facades\DB::transaction(function () use ($examData) {
                if (! isset($examData['assembleType'])) {
                    throw new \InvalidArgumentException('assembleType 缺失，无法保存试卷');
                }

                $assembleType = (int) $examData['assembleType'];

                // 允许外部预分配 paper_id，以保证接口可以同步返回稳定 ID
                $paperId = (string) ($examData['paper_id'] ?? '');
                if ($paperId === '') {
                    $paperId = $this->generatePaperId();
                } elseif (!PaperIdGenerator::validatePaperId($paperId)) {
                    throw new \InvalidArgumentException("paper_id 格式不合法: {$paperId}");
                }
                $studentId = $examData['student_id'] ?? '';
                $studentName = '________';
                if (! empty($studentId)) {
                    $studentName = Student::query()
                        ->where('student_id', $studentId)
                        ->value('name') ?? $studentId;
                }
                $paperDisplayName = PaperNaming::buildPaperDisplayTitle((string) $studentName, $paperId, $assembleType);

                Log::info('开始保存试卷到数据库', [
                    'paper_id' => $paperId,
                    'paper_name' => $paperDisplayName,
                    'question_count' => count($examData['questions']),
                    'assemble_type' => $assembleType,
                ]);

                // 使用Laravel模型保存到 papers 表
                // 注意：total_questions将在题目处理完成后再更新，确保与实际插入的题目数量一致
                $paper = \App\Models\Paper::create([
                    'paper_id' => $paperId,
                    'student_id' => $studentId,
                    'teacher_id' => $examData['teacher_id'] ?? '',
                    'paper_name' => $paperDisplayName,
                    'paper_type' => $assembleType, // assemble_type 唯一来源
                    'diagnostic_chapter_id' => $examData['diagnostic_chapter_id'] ?? null, // 摸底的章节ID（章节摸底时记录）
                    'explanation_kp_codes' => $examData['explanation_kp_codes'] ?? null, // 学案讲解的知识点列表（最多2个）
                    'total_questions' => 0, // 临时设为0，处理完题目后再更新
                    'total_score' => $examData['total_score'] ?? 0,
                    'status' => 'draft',
                    'difficulty_category' => $examData['difficulty_category'] ?? '基础',
                ]);

                // 获取所有题目的正确答案
                $questionBankIds = array_filter(array_map(function ($q) {
                    return $q['id'] ?? $q['question_id'] ?? null;
                }, $examData['questions']));

                $correctAnswersMap = [];
                if (! empty($questionBankIds)) {
                    Log::info('从本地题库获取题目正确答案', [
                        'paper_id' => $paperId,
                        'question_bank_ids' => $questionBankIds,
                    ]);

                    $localQuestions = Question::query()
                        ->whereIn('id', array_values($questionBankIds))
                        ->get(['id', 'answer']);

                    foreach ($localQuestions as $detail) {
                        $correctAnswersMap[$detail->id] = $detail->answer ?? '';
                    }
                }

                // 准备题目数据
                $questionInsertData = [];
                $skippedQuestions = 0;
                Log::info('开始处理题目数据', [
                    'paper_id' => $paperId,
                    'total_questions' => count($examData['questions']),
                ]);

                foreach ($examData['questions'] as $index => $question) {
                    // 验证题目基本数据
                    if (empty($question['stem']) && empty($question['content'])) {
                        $skippedQuestions++;
                        Log::warning('跳过没有内容的题目', [
                            'paper_id' => $paperId,
                            'question_index' => $index,
                            'question_id' => $question['id'] ?? 'N/A',
                            'has_stem' => ! empty($question['stem']),
                            'has_content' => ! empty($question['content']),
                            'stem_preview' => substr($question['stem'] ?? '', 0, 50),
                        ]);

                        continue;
                    }

                    // 处理题目内容：分离题干和选项（如果存在）
                    $rawContent = $question['stem'] ?? $question['content'] ?? '';
                    [$stem, $options] = $this->separateStemAndOptions($rawContent);

                    // 将选项以换行符形式附加到题干末尾，方便后续渲染
                    if (! empty($options)) {
                        $stemWithOptions = $stem."\n".implode("\n", array_map(function ($opt, $idx) {
                            return chr(65 + $idx).'. '.$opt;
                        }, $options, array_keys($options)));
                        $question['stem'] = $stemWithOptions;
                        $question['options'] = $options;
                    } else {
                        $question['stem'] = $stem;
                    }

                    // 处理难度字段：如果是字符串则转换为数字
                    $difficultyValue = $question['difficulty'] ?? 0.5;
                    if (is_string($difficultyValue)) {
                        // 将中文难度转换为数字
                        if (strpos($difficultyValue, '基础') !== false || strpos($difficultyValue, '简单') !== false) {
                            $difficultyValue = 0.3;
                        } elseif (strpos($difficultyValue, '中等') !== false || strpos($difficultyValue, '一般') !== false) {
                            $difficultyValue = 0.6;
                        } elseif (strpos($difficultyValue, '拔高') !== false || strpos($difficultyValue, '困难') !== false) {
                            $difficultyValue = 0.9;
                        } else {
                            $difficultyValue = 0.5;
                        }
                    }

                    // 确保 knowledge_point 有值
                    $knowledgePoint = $question['kp'] ?? $question['kp_code'] ?? $question['knowledge_point'] ?? $question['knowledge_point_code'] ?? '';
                    if (empty($knowledgePoint) && isset($question['kp_code'])) {
                        $knowledgePoint = $question['kp_code'];
                    }

                    // 获取题目类型（以题库原始类型为准，不再二次推断/归一化）
                    $questionType = $question['question_type'] ?? $question['type'] ?? 'answer';

                    // 获取正确答案
                    $questionBankId = $question['id'] ?? $question['question_id'] ?? null;
                    $correctAnswer = $correctAnswersMap[$questionBankId] ?? $question['answer'] ?? $question['correct_answer'] ?? '';

                    $questionInsertData[] = [
                        'paper_id' => $paperId,
                        'question_id' => $question['question_code'] ?? $question['question_id'] ?? null,
                        'question_bank_id' => $question['id'] ?? $question['question_id'] ?? 0,
                        'knowledge_point' => $knowledgePoint,
                        'question_type' => $questionType,
                        'question_text' => is_array($question['stem'] ?? null) ? json_encode($question['stem'], JSON_UNESCAPED_UNICODE) : ($question['stem'] ?? $question['content'] ?? $question['question_text'] ?? ''),
                        'correct_answer' => is_array($correctAnswer) ? json_encode($correctAnswer, JSON_UNESCAPED_UNICODE) : $correctAnswer,  // 保存正确答案
                        'solution' => is_array($question['solution'] ?? null) ? json_encode($question['solution'], JSON_UNESCAPED_UNICODE) : ($question['solution'] ?? ''),  // 保存解题思路
                        'difficulty' => $difficultyValue,
                        'score' => $question['score'] ?? 5, // 默认5分
                        'estimated_time' => $question['estimated_time'] ?? 300,
                        'question_number' => $question['question_number'] ?? ($index + 1),
                    ];
                }

                // 验证是否有有效的题目数据
                if (empty($questionInsertData)) {
                    Log::error('没有有效的题目数据可以保存', [
                        'paper_id' => $paperId,
                        'total_input_questions' => count($examData['questions']),
                        'skipped_questions' => $skippedQuestions,
                    ]);
                    throw new \Exception('没有有效的题目数据');
                }

                Log::info('准备插入题目数据', [
                    'paper_id' => $paperId,
                    'total_input_questions' => count($examData['questions']),
                    'skipped_questions' => $skippedQuestions,
                    'questions_to_insert' => count($questionInsertData),
                ]);

                // 调试：检查第一个题目的solution字段
                if (! empty($questionInsertData)) {
                    $firstQuestion = $questionInsertData[0];
                    Log::debug('试卷保存调试 - 第一个题目', [
                        'paper_id' => $paperId,
                        'question_id' => $firstQuestion['question_id'] ?? '',
                        'question_bank_id' => $firstQuestion['question_bank_id'] ?? '',
                        'has_solution' => ! empty($firstQuestion['solution']),
                        'solution_length' => strlen($firstQuestion['solution'] ?? ''),
                        'solution_preview' => substr($firstQuestion['solution'] ?? '', 0, 80),
                    ]);
                }

                // 使用Laravel模型批量插入题目数据
                \App\Models\PaperQuestion::insert($questionInsertData);

                // 验证插入结果，使用关联关系
                $insertedQuestionCount = $paper->questions()->count();

                Log::info('验证题目插入结果', [
                    'paper_id' => $paperId,
                    'expected_count' => count($questionInsertData),
                    'actual_count' => $insertedQuestionCount,
                    'difference' => $insertedQuestionCount - count($questionInsertData),
                ]);

                if ($insertedQuestionCount !== count($questionInsertData)) {
                    Log::error('题目插入数量不匹配', [
                        'paper_id' => $paperId,
                        'expected' => count($questionInsertData),
                        'actual' => $insertedQuestionCount,
                        'difference' => $insertedQuestionCount - count($questionInsertData),
                        'input_questions_count' => count($examData['questions']),
                        'skipped_questions' => $skippedQuestions,
                    ]);
                    throw new \Exception('题目插入数量不匹配：预期 '.count($questionInsertData)."，实际 {$insertedQuestionCount}");
                }

                // 【重要】更新试卷的total_questions字段为实际插入的题目数量
                $paper->update(['total_questions' => $insertedQuestionCount]);

                Log::info('试卷保存成功', [
                    'paper_id' => $paperId,
                    'expected_questions' => count($questionInsertData),
                    'actual_questions' => $insertedQuestionCount,
                    'paper_name' => $paper->paper_name,
                ]);

                return $paperId;
            });

        } catch (\Exception $e) {
            Log::error('保存试卷到数据库失败', [
                'error' => $e->getMessage(),
                'paper_name' => $examData['paper_name'] ?? '未命名试卷',
                'student_id' => $examData['student_id'] ?? 'unknown',
                'question_count' => count($examData['questions'] ?? []),
                'trace' => $e->getTraceAsString(),
            ]);
        }

        return null;
    }

    /**
     * 生成试卷ID（paper_ + 15位数字）
     */
    public function generatePaperId(): string
    {
        // 防御式重试，确保始终产出合法 15 位数字部分
        for ($i = 0; $i < 3; $i++) {
            $uniqueId = PaperIdGenerator::generate();
            if (PaperIdGenerator::validate($uniqueId)) {
                return 'paper_'.$uniqueId;
            }
        }

        throw new \RuntimeException('无法生成合法的 paper_id');
    }

    private function useLocal(): bool
    {
        return true;
    }

    private function local(): QuestionLocalService
    {
        return app(QuestionLocalService::class);
    }

    private function normalizeQuestionTypeValue(string $type): string
    {
        $type = trim($type);
        $lower = strtolower($type);

        if (in_array($lower, ['choice', 'single_choice', 'multiple_choice'], true)) {
            return 'choice';
        }
        if (in_array($lower, ['fill', 'blank', 'fill_in_the_blank'], true)) {
            return 'fill';
        }
        if (in_array($lower, ['answer', 'calculation', 'word_problem', 'proof'], true)) {
            return 'answer';
        }

        if (in_array($type, ['CHOICE', 'SINGLE_CHOICE', 'MULTIPLE_CHOICE'], true)) {
            return 'choice';
        }
        if (in_array($type, ['FILL', 'FILL_IN_THE_BLANK'], true)) {
            return 'fill';
        }
        if (in_array($type, ['CALCULATION', 'WORD_PROBLEM', 'PROOF'], true)) {
            return 'answer';
        }

        if (in_array($type, ['选择题'], true)) {
            return 'choice';
        }
        if (in_array($type, ['填空题'], true)) {
            return 'fill';
        }
        if (in_array($type, ['解答题', '计算题'], true)) {
            return 'answer';
        }

        return $lower ?: 'answer';
    }

    /**
     * 检查数据完整性 - 发现没有题目的试卷
     */
    public function checkDataIntegrity(): array
    {
        try {
            // 使用Laravel模型查找显示有题目但实际没有题目的试卷
            $inconsistentPapers = \App\Models\Paper::where('question_count', '>', 0)
                ->whereDoesntHave('questions')
                ->get();

            Log::warning('发现数据不一致的试卷', [
                'count' => $inconsistentPapers->count(),
                'papers' => $inconsistentPapers->map(function ($paper) {
                    return [
                        'paper_id' => $paper->paper_id,
                        'paper_name' => $paper->paper_name,
                        'expected_questions' => $paper->question_count,
                        'student_id' => $paper->student_id,
                        'created_at' => $paper->created_at,
                    ];
                })->toArray(),
            ]);

            return [
                'inconsistent_count' => $inconsistentPapers->count(),
                'papers' => $inconsistentPapers->toArray(),
            ];
        } catch (\Exception $e) {
            Log::error('检查数据完整性失败', ['error' => $e->getMessage()]);

            return ['inconsistent_count' => 0, 'papers' => []];
        }
    }

    /**
     * 清理没有题目的试卷记录
     */
    public function cleanupInconsistentPapers(): int
    {
        try {
            return \Illuminate\Support\Facades\DB::transaction(function () {
                // 使用Laravel模型查找显示有题目但实际没有题目的试卷
                $inconsistentPapers = \App\Models\Paper::where('question_count', '>', 0)
                    ->whereDoesntHave('questions')
                    ->get();

                if ($inconsistentPapers->isEmpty()) {
                    return 0;
                }

                // 获取要删除的试卷ID列表
                $deletedPaperIds = $inconsistentPapers->pluck('paper_id')->toArray();

                // 使用Laravel模型删除这些不一致的试卷记录
                $deletedCount = \App\Models\Paper::whereIn('paper_id', $deletedPaperIds)->delete();

                Log::info('清理不一致的试卷记录', [
                    'deleted_count' => $deletedCount,
                    'deleted_paper_ids' => $deletedPaperIds,
                ]);

                return $deletedCount;
            });
        } catch (\Exception $e) {
            Log::error('清理不一致试卷失败', ['error' => $e->getMessage()]);

            return 0;
        }
    }

    /**
     * 修复试卷的题目数量统计
     */
    public function fixPaperQuestionCounts(): int
    {
        try {
            $fixedCount = 0;

            // 使用Laravel模型获取所有试卷
            $papers = \App\Models\Paper::all();

            foreach ($papers as $paper) {
                // 计算实际的题目数量，使用关联关系
                $actualQuestionCount = $paper->questions()->count();

                // 如果题目数量不匹配，更新试卷
                if ($paper->question_count !== $actualQuestionCount) {
                    $paper->update([
                        'question_count' => $actualQuestionCount,
                        'updated_at' => now(),
                    ]);

                    $fixedCount++;
                    Log::info('修复试卷题目数量', [
                        'paper_id' => $paper->paper_id,
                        'old_count' => $paper->getOriginal('question_count'),
                        'new_count' => $actualQuestionCount,
                    ]);
                }
            }

            Log::info('试卷题目数量修复完成', ['fixed_count' => $fixedCount]);

            return $fixedCount;

        } catch (\Exception $e) {
            Log::error('修复试卷题目数量失败', ['error' => $e->getMessage()]);

            return 0;
        }
    }

    /**
     * 获取试卷列表
     */
    public function listExams(int $page = 1, int $perPage = 20): array
    {
        $query = Paper::query()->whereHas('questions');
        $paginator = $query->orderByDesc('id')->paginate($perPage, ['*'], 'page', $page);

        $data = $paginator->getCollection()->map(function (Paper $paper) {
            return [
                'paper_id' => $paper->paper_id,
                'paper_name' => $paper->paper_name,
                'student_id' => $paper->student_id,
                'teacher_id' => $paper->teacher_id,
                'total_questions' => $paper->question_count ?? $paper->questions()->count(),
                'total_score' => $paper->total_score,
                'difficulty_category' => $paper->difficulty_category,
                'status' => $paper->status,
                'created_at' => $paper->created_at,
                'updated_at' => $paper->updated_at,
            ];
        })->toArray();

        return [
            'data' => $data,
            'meta' => [
                'page' => $paginator->currentPage(),
                'per_page' => $paginator->perPage(),
                'total' => $paginator->total(),
                'total_pages' => $paginator->lastPage(),
            ],
        ];
    }

    /**
     * 获取试卷详情
     */
    public function getExamById(string $paperId): ?array
    {
        $paper = Paper::where('paper_id', $paperId)->first();
        if (! $paper) {
            return null;
        }

        return app(PaperPayloadService::class)->buildPaperApiPayload($paper);
    }

    /**
     * 导出试卷为PDF
     */
    public function exportExamToPdf(string $paperId): ?string
    {
        return app(ExamPdfExportService::class)->generateExamPdf($paperId);
    }

    /**
     * 检查服务健康状态
     */
    public function checkHealth(): bool
    {
        return true;
    }

    /**
     * 根据OCR识别的题目生成完整题目并保存到题库（异步模拟版本）
     *
     * @param  array  $questions  OCR识别的题目列表
     * @param  string  $gradeLevel  年级
     * @param  string  $subject  科目
     * @param  int  $ocrRecordId  OCR记录ID，用于关联
     * @param  string|null  $callbackUrl  回调URL（可选，如果不提供则自动生成）
     * @param  string|null  $callbackRouteName  回调路由名称（用于动态生成URL）
     * @return array 任务ID和状态
     */
    public function generateQuestionsFromOcrAsync(
        array $questions,
        string $gradeLevel = '高一',
        string $subject = '数学',
        ?int $ocrRecordId = null,
        ?string $callbackUrl = null,
        string $callbackRouteName = 'api.ocr.callback'
    ): array {
        try {
            // 如果没有提供回调URL，但提供了OCR记录ID，则动态生成回调URL
            if (! $callbackUrl && $ocrRecordId) {
                $callbackUrl = $this->generateCallbackUrl($callbackRouteName);
                Log::info('动态生成回调URL', [
                    'route_name' => $callbackRouteName,
                    'generated_url' => $callbackUrl,
                ]);
            }

            // 生成唯一的任务ID
            $taskId = 'ocr_'.$ocrRecordId.'_'.time().'_'.substr(md5(uniqid()), 0, 8);

            // 更新OCR记录状态为生成中
            if ($ocrRecordId) {
                \DB::table('ocr_question_results')
                    ->where('ocr_record_id', $ocrRecordId)
                    ->where('question_bank_id', null) // 只更新未关联的题目
                    ->update([
                        'generation_status' => 'generating',
                        'generation_task_id' => $taskId,
                        'generation_error' => null,
                    ]);
            }

            // 启动后台任务（使用Laravel的队列）
            if ($ocrRecordId && $callbackUrl) {
                // 使用Laravel队列异步处理
                $this->dispatchOcrGenerationJob($ocrRecordId, $questions, $gradeLevel, $subject, $callbackUrl, $taskId);
            } else {
                // 如果没有回调URL，使用同步方式
                $response = $this->generateQuestionsFromOcr($questions, $gradeLevel, $subject);

                return $response;
            }

            Log::info('OCR题目生成任务已提交到队列', [
                'task_id' => $taskId,
                'ocr_record_id' => $ocrRecordId,
                'questions_count' => count($questions),
                'callback_url' => $callbackUrl,
            ]);

            return [
                'status' => 'processing',
                'task_id' => $taskId,
                'ocr_record_id' => $ocrRecordId,
                'message' => '题目生成任务已启动，完成后将通过回调通知',
                'estimated_time' => '约'.(count($questions) * 2).'秒',
                'callback_info' => [
                    'will_callback' => ! empty($callbackUrl),
                    'callback_url' => $callbackUrl,
                ],
            ];

        } catch (\Exception $e) {
            Log::error('OCR题目生成任务提交异常', [
                'error' => $e->getMessage(),
                'ocr_record_id' => $ocrRecordId,
            ]);

            return [
                'status' => 'error',
                'message' => '任务提交失败: '.$e->getMessage(),
            ];
        }
    }

    /**
     * 分发OCR生成任务到队列
     */
    private function dispatchOcrGenerationJob(
        int $ocrRecordId,
        array $questions,
        string $gradeLevel,
        string $subject,
        string $callbackUrl,
        string $taskId
    ): void {
        try {
            // 转换题目数据格式
            $formattedQuestions = [];
            foreach ($questions as $q) {
                $formattedQuestions[] = [
                    'id' => $q['id'] ?? uniqid(),
                    'content' => $q['content'] ?? '',
                ];
            }

            // 直接调用QuestionBank API的异步端点,提供回调URL
            // 注意: baseUrl 已经包含 /api,所以这里只需要 /ocr/questions/generate-from-ocr
            $response = Http::timeout(60)
                ->post($this->baseUrl.'/ocr/questions/generate-from-ocr', [
                    'ocr_record_id' => $ocrRecordId,
                    'questions' => $formattedQuestions,
                    'grade_level' => $gradeLevel,
                    'subject' => $subject,
                    'callback_url' => $callbackUrl,
                ]);

            if (! $response->successful()) {
                Log::error('提交OCR题目生成任务失败', [
                    'status' => $response->status(),
                    'body' => $response->body(),
                    'task_id' => $taskId,
                ]);

                // 发送失败回调
                $callbackData = [
                    'task_id' => $taskId,
                    'ocr_record_id' => $ocrRecordId,
                    'status' => 'failed',
                    'error' => 'API调用失败: '.$response->status(),
                    'timestamp' => now()->toISOString(),
                ];

                Http::timeout(10)
                    ->post($callbackUrl, $callbackData);

                return;
            }

            $result = $response->json();
            Log::info('OCR题目生成任务已提交到QuestionBank', [
                'task_id' => $taskId,
                'questionbank_task_id' => $result['task_id'] ?? 'unknown',
                'status' => $result['status'] ?? 'unknown',
                'callback_url' => $callbackUrl,
            ]);

            // QuestionBank API会异步处理并通过回调通知，这里不需要立即触发回调
            // 回调会在题目生成完成后由QuestionBank API主动发送

        } catch (\Exception $e) {
            Log::error('OCR生成任务处理失败', [
                'task_id' => $taskId,
                'ocr_record_id' => $ocrRecordId,
                'error' => $e->getMessage(),
            ]);

            // 发送异常回调
            try {
                $callbackData = [
                    'task_id' => $taskId,
                    'ocr_record_id' => $ocrRecordId,
                    'status' => 'failed',
                    'error' => $e->getMessage(),
                    'timestamp' => now()->toISOString(),
                ];

                Http::timeout(10)
                    ->post($callbackUrl, $callbackData);
            } catch (\Exception $callbackException) {
                Log::error('发送异常回调失败', [
                    'error' => $callbackException->getMessage(),
                ]);
            }
        }
    }

    /**
     * 动态生成回调URL
     *
     * @param  string  $routeName  路由名称
     * @return string 完整的回调URL
     */
    private function generateCallbackUrl(string $routeName): string
    {
        try {
            // 获取当前请求的域名
            $appUrl = config('app.url', 'http://localhost');

            // 如果是在命令行环境中运行，使用配置的域名
            if (app()->runningInConsole()) {
                $domain = $appUrl;
            } else {
                $domain = request()->getSchemeAndHttpHost();
            }

            // 确保domain不为null
            $domain = $domain ?? $appUrl;

            // 移除末尾的斜杠
            $domain = rtrim($domain, '/');

            // 生成完整的URL
            $callbackUrl = $domain.route($routeName, [], false);

            Log::info('生成回调URL', [
                'route_name' => $routeName,
                'domain' => $domain,
                'app_url' => $appUrl,
                'callback_url' => $callbackUrl,
            ]);

            return $callbackUrl;
        } catch (\Exception $e) {
            // 如果路由生成失败，使用默认URL
            Log::warning('路由生成失败，使用默认URL', [
                'route_name' => $routeName,
                'error' => $e->getMessage(),
            ]);

            $fallbackUrl = config('app.url', 'http://localhost');
            if ($routeName === 'api.ocr.callback') {
                return $fallbackUrl.'/api/ocr-question-callback';
            }

            return $fallbackUrl;
        }
    }

    /**
     * 根据OCR识别的题目生成题库题目（同步版本，向后兼容）
     *
     * @param  array  $questions  OCR题目数组 [['question_number' => 1, 'question_text' => '...']]
     * @param  string  $gradeLevel  年级
     * @param  string  $subject  科目
     * @return array 生成结果
     */
    public function generateQuestionsFromOcr(array $questions, string $gradeLevel = '高一', string $subject = '数学'): array
    {
        return $this->generateQuestionsFromOcrAsync($questions, $gradeLevel, $subject);
    }

    /**
     * 检查题目生成任务状态
     */
    public function checkGenerationTaskStatus(string $taskId): array
    {
        return $this->getTaskStatus($taskId) ?? ['status' => 'unknown'];
    }

    /**
     * 获取知识点题目统计信息
     * 根据知识点代码，统计该知识点及其子知识点和技能点的题目数量
     */
    public function getKnowledgePointStatistics(?string $kpCode = null): array
    {
        try {
            // 获取知识图谱数据和题目统计数据
            $knowledgeGraph = $this->getKnowledgeGraph();
            $nodes = $knowledgeGraph['nodes'] ?? [];
            $edges = $knowledgeGraph['edges'] ?? [];
            $questionStats = $this->getQuestionsStatisticsFromApi();

            // 构建知识点索引
            $nodeMap = [];
            foreach ($nodes as $node) {
                if (! empty($node['kp_code'])) {
                    $nodeMap[$node['kp_code']] = $node;
                }
            }

            // 构建子知识点关系（从edges中提取）
            $childrenMap = [];
            $parentMap = [];
            foreach ($edges as $edge) {
                $source = $edge['source'] ?? '';
                $target = $edge['target'] ?? '';
                $direction = $edge['relation_direction'] ?? '';

                if (! empty($source) && ! empty($target)) {
                    if ($direction === 'DOWNSTREAM') {
                        $childrenMap[$source][] = $target;
                        $parentMap[$target] = $source;
                    }
                }
            }

            // 构建技能点统计
            $skillStats = [];
            foreach ($questionStats as $stat) {
                $code = $stat['kp_code'] ?? '';
                $skills = $stat['skills_list'] ?? [];

                if (! empty($code)) {
                    foreach ($skills as $skillCode) {
                        if (! empty($skillCode)) {
                            if (! isset($skillStats[$code])) {
                                $skillStats[$code] = [];
                            }
                            if (! isset($skillStats[$code][$skillCode])) {
                                $skillStats[$code][$skillCode] = 0;
                            }
                            $skillStats[$code][$skillCode]++;
                        }
                    }
                }
            }

            // 如果指定了特定知识点，只返回该知识点的统计
            if ($kpCode && isset($nodeMap[$kpCode])) {
                return $this->buildKnowledgePointStats($kpCode, $nodeMap, $childrenMap, $questionStats, $skillStats);
            }

            // 否则返回所有顶级知识点的统计
            $result = [];
            $rootNodes = [];

            // 找出根节点（没有父节点的节点）
            foreach ($nodes as $node) {
                $code = $node['kp_code'] ?? '';
                if (! empty($code) && ! isset($parentMap[$code])) {
                    $rootNodes[] = $code;
                }
            }

            foreach ($rootNodes as $rootCode) {
                $result[] = $this->buildKnowledgePointStats($rootCode, $nodeMap, $childrenMap, $questionStats, $skillStats);
            }

            // 按题目总数排序
            usort($result, function ($a, $b) {
                return ($b['total_questions'] ?? 0) <=> ($a['total_questions'] ?? 0);
            });

            return $result;

        } catch (\Exception $e) {
            Log::error('获取知识点统计失败', [
                'kp_code' => $kpCode,
                'error' => $e->getMessage(),
            ]);

            return [];
        }
    }

    /**
     * 获取知识图谱数据
     */
    private function getKnowledgeGraph(): array
    {
        try {
            $knowledgeApiBase = config('services.knowledge_api.base_url', 'http://localhost:5011');
            $response = Http::timeout(10)
                ->get($knowledgeApiBase.'/graph/export');

            if ($response->successful()) {
                return $response->json();
            }
        } catch (\Exception $e) {
            Log::error('获取知识图谱失败', ['error' => $e->getMessage()]);
        }

        return ['nodes' => [], 'edges' => []];
    }

    /**
     * 从 API 获取题目统计
     */
    private function getQuestionsStatisticsFromApi(): array
    {
        try {
            // 调用题库 API 获取统计数据
            $response = Http::timeout(30)
                ->get($this->baseUrl.'/questions/statistics');

            if ($response->successful()) {
                $data = $response->json();

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

            Log::warning('获取题目统计API失败', [
                'status' => $response->status(),
                'url' => $this->baseUrl.'/questions/statistics',
            ]);
        } catch (\Exception $e) {
            Log::error('获取题目统计异常', [
                'error' => $e->getMessage(),
                'url' => $this->baseUrl.'/questions/statistics',
            ]);
        }

        return [];
    }

    /**
     * 构建单个知识点的统计信息
     */
    private function buildKnowledgePointStats(
        string $kpCode,
        array $nodeMap,
        array $childrenMap,
        array $questionStats,
        array $skillStats
    ): array {
        $node = $nodeMap[$kpCode] ?? null;
        if (! $node) {
            return [];
        }

        // 获取直接子知识点
        $children = $childrenMap[$kpCode] ?? [];
        $directQuestionCount = 0;

        // 查找当前知识点的题目数
        foreach ($questionStats as $stat) {
            if ($stat['kp_code'] === $kpCode) {
                $directQuestionCount = $stat['question_count'] ?? 0;
                break;
            }
        }

        // 计算子知识点统计
        $childrenStats = [];
        foreach ($children as $childCode) {
            $childStats = $this->buildKnowledgePointStats($childCode, $nodeMap, $childrenMap, $questionStats, $skillStats);
            if (! empty($childStats)) {
                $childrenStats[] = $childStats;
            }
        }

        // 计算子知识点题目总数
        $childrenQuestionCount = 0;
        foreach ($childrenStats as $child) {
            $childrenQuestionCount += $child['total_questions'] ?? 0;
        }

        // 获取当前知识点的技能点统计
        $skillsCount = 0;
        if (isset($skillStats[$kpCode])) {
            $skillsCount = array_sum($skillStats[$kpCode]);
        }

        return [
            'kp_code' => $kpCode,
            'cn_name' => $node['cn_name'] ?? $kpCode,
            'en_name' => $node['en_name'] ?? '',
            'total_questions' => $directQuestionCount + $childrenQuestionCount,
            'direct_questions' => $directQuestionCount,
            'children_questions' => $childrenQuestionCount,
            'children' => $childrenStats,
            'skills_count' => count($skillStats[$kpCode] ?? []),
            'skills_total_questions' => $skillsCount,
            'skills' => array_map(function ($skillCode, $count) use ($kpCode) {
                return [
                    'kp_code' => $kpCode,
                    'skill_code' => $skillCode,
                    'question_count' => $count,
                ];
            }, array_keys($skillStats[$kpCode] ?? []), array_values($skillStats[$kpCode] ?? [])),
        ];
    }

    /**
     * 获取所有试卷列表
     */
    public function getAllPapers(): array
    {
        try {
            $response = Http::timeout(10)
                ->get($this->baseUrl.'/papers');

            if ($response->successful()) {
                return $response->json('data', []);
            }

            Log::warning('获取试卷列表失败', [
                'status' => $response->status(),
                'response' => $response->body(),
            ]);

            return [];
        } catch (\Exception $e) {
            Log::error('获取试卷列表异常', [
                'error' => $e->getMessage(),
            ]);

            return [];
        }
    }

    /**
     * 获取指定试卷的题目
     */
    public function getPaperQuestions(string $paperId): array
    {
        try {
            $response = Http::timeout(10)
                ->get($this->baseUrl.'/papers/'.$paperId.'/questions');

            if ($response->successful()) {
                return $response->json('data', []);
            }

            Log::warning('获取试卷题目失败', [
                'paper_id' => $paperId,
                'status' => $response->status(),
                'response' => $response->body(),
            ]);

            return [];
        } catch (\Exception $e) {
            Log::error('获取试卷题目异常', [
                'paper_id' => $paperId,
                'error' => $e->getMessage(),
            ]);

            return [];
        }
    }

    /**
     * 【通用方法】获取题目的知识点信息
     * 直接从MySQL的questions表查询
     */
    public function getQuestionKnowledgePoint(int $questionBankId): array
    {
        try {
            // 直接从MySQL questions表查询题目
            $question = \App\Models\Question::where('id', $questionBankId)->first();

            if (! $question) {
                Log::warning('QuestionBankService: MySQL中未找到题目', ['question_bank_id' => $questionBankId]);

                return [
                    'kp_code' => null,
                    'kp_name' => null,
                    'question_content' => '',
                    'question_answer' => '',
                    'question_type' => 'unknown',
                ];
            }

            return [
                'kp_code' => $question->kp_code,
                'kp_name' => $question->kp_name ?? $question->kp_code,
                'question_content' => $question->stem ?? '',
                'question_answer' => $question->answer ?? '',
                'question_type' => $question->question_type ?? 'unknown',
            ];

        } catch (\Exception $e) {
            Log::error('QuestionBankService: 获取题目知识点失败', [
                'question_bank_id' => $questionBankId,
                'error' => $e->getMessage(),
            ]);

            return [
                'kp_code' => null,
                'kp_name' => null,
                'question_content' => '',
                'question_answer' => '',
                'question_type' => 'unknown',
                'error' => $e->getMessage(),
            ];
        }
    }
}
