<?php

namespace App\Http\Controllers\Api;

use App\Models\KnowledgePoint;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Cache;

class KnowledgePointTreeController
{
    /**
     * 获取知识点树形结构
     * 从 MySQL 数据库读取数据，构建层级结构
     *
     * @param Request $request
     * @return JsonResponse
     */
    public function index(Request $request): JsonResponse
    {
        try {
            // 使用缓存避免重复查询
            $cacheKey = 'knowledge-point-tree-' . md5($request->getQueryString() ?? '');
            $treeData = Cache::remember($cacheKey, 3600, function () {
                return $this->buildTreeFromDatabase();
            });

            return response()->json([
                'success' => true,
                'data' => $treeData,
            ]);
        } catch (\Exception $e) {
            Log::error('获取知识点树形结构失败', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);

            return response()->json([
                'success' => false,
                'message' => '获取知识点数据失败：' . $e->getMessage(),
                'data' => [],
            ], 500);
        }
    }

    /**
     * 从数据库构建树形结构
     *
     * @return array
     */
    private function buildTreeFromDatabase(): array
    {
        // 从数据库获取所有知识点
        $knowledgePoints = KnowledgePoint::query()
            ->orderBy('kp_code')
            ->get()
            ->toArray();

        if (empty($knowledgePoints)) {
            Log::warning('数据库中没有找到知识点数据');
            return [];
        }

        // 构建节点映射（以 kp_code 为键）
        $nodesMap = [];
        foreach ($knowledgePoints as $point) {
            $kpCode = $point['kp_code'];
            $nodesMap[$kpCode] = [
                'id' => $kpCode,
                'label' => $point['name'] ?? $kpCode,
                'children' => [],
                // 可选字段：如果数据库中有相关数据则添加
                'skills' => $this->extractSkills($point),
                'direct_score' => $this->extractDirectScore($point),
                'related_score' => $this->extractRelatedScore($point),
                // 保留原始数据用于调试
                '_raw' => $point,
            ];
        }

        // 构建树形结构
        $rootNodes = [];
        foreach ($nodesMap as $kpCode => &$node) {
            $parentKpCode = $this->getParentKpCode($node['_raw']);

            // 如果没有父节点，则为根节点
            if (empty($parentKpCode) || !isset($nodesMap[$parentKpCode])) {
                $rootNodes[] = &$node;
            } else {
                // 添加到父节点的 children 中
                $nodesMap[$parentKpCode]['children'][] = &$node;
            }
        }

        // 清理临时数据
        foreach ($nodesMap as &$node) {
            unset($node['_raw']);
        }

        Log::info('成功构建知识点树形结构', [
            'total_nodes' => count($knowledgePoints),
            'root_nodes' => count($rootNodes),
        ]);

        return $rootNodes;
    }

    /**
     * 提取技能点信息
     *
     * @param array $point
     * @return array
     */
    private function extractSkills(array $point): array
    {
        // 如果数据库中有 skills 字段，直接返回
        if (isset($point['skills']) && is_array($point['skills'])) {
            return $point['skills'];
        }

        // 否则返回空数组
        return [];
    }

    /**
     * 提取直接得分范围
     *
     * @param array $point
     * @return array
     */
    private function extractDirectScore(array $point): array
    {
        // 如果数据库中有 direct_score 字段，直接返回
        if (isset($point['direct_score']) && is_array($point['direct_score'])) {
            return $point['direct_score'];
        }

        // 从 stats 字段提取（如果存在）
        if (isset($point['stats']) && is_array($point['stats'])) {
            if (isset($point['stats']['direct_score'])) {
                return (array) $point['stats']['direct_score'];
            }
        }

        // 默认值
        return [1, 3];
    }

    /**
     * 提取相关得分范围
     *
     * @param array $point
     * @return array
     */
    private function extractRelatedScore(array $point): array
    {
        // 如果数据库中有 related_score 字段，直接返回
        if (isset($point['related_score']) && is_array($point['related_score'])) {
            return $point['related_score'];
        }

        // 从 stats 字段提取（如果存在）
        if (isset($point['stats']) && is_array($point['stats'])) {
            if (isset($point['stats']['related_score'])) {
                return (array) $point['stats']['related_score'];
            }
        }

        // 默认值
        return [2, 5];
    }

    /**
     * 获取父知识点代码
     *
     * @param array $point
     * @return string|null
     */
    private function getParentKpCode(array $point): ?string
    {
        // 直接从 parent_kp_code 字段获取
        if (!empty($point['parent_kp_code'])) {
            return $point['parent_kp_code'];
        }

        // 如果没有 parent_kp_code，尝试从 kp_code 推断
        // 例如：R01 的父节点可能是 S01，M01 的父节点可能是 M00
        $kpCode = $point['kp_code'] ?? '';

        if (empty($kpCode)) {
            return null;
        }

        // 尝试从编码规则推断父节点
        // M01 -> M00, S01 -> M01, R01 -> S01 等
        if (preg_match('/^([A-Z]+)\d+$/', $kpCode, $matches)) {
            $prefix = $matches[1];
            $number = (int) substr($kpCode, strlen($prefix));

            if ($number > 0) {
                // 降级：R01 -> S01 (去掉一位数字)
                $parentNumber = (int) (substr($kpCode, strlen($prefix), -1));
                if ($parentNumber > 0) {
                    return $prefix . str_pad($parentNumber, strlen($kpCode) - strlen($prefix), '0', STR_PAD_LEFT);
                }
            }
        }

        return null;
    }
}
