<?php
/**
 * AI模板生成辅助函数
 * - 模板完整性检测
 * - 自动续写（当AI输出被截断时）
 * - DeepSeek-R1 推理内容剥离
 */

/**
 * 剥离 AI 输出中的 <think>...</think> 推理内容（DeepSeek-R1 等模型）
 * 支持完整闭合的 <think>...</think> 和未闭合的 <think>...（截断场景）
 */
function strip_ai_thinking_tags($text)
{
    // 先处理完整闭合的 <think>...</think>（含换行）
    $text = preg_replace('/<think>[\s\S]*?<\/think>\s*/i', '', $text);
    // 再处理未闭合的 <think>...（截断场景，删除到末尾）
    $text = preg_replace('/<think>[\s\S]*$/i', '', $text);
    return trim($text);
}

/**
 * 检测AI生成的模板是否完整
 *
 * @param string $content  生成的内容
 * @param string $fileKey  文件类型：header|footer|homepage|article|archive|css|js
 * @return array ['complete' => bool, 'reason' => string]
 */
function check_template_completeness($content, $fileKey)
{
    $content = trim($content);
    if ($content === '') {
        return array('complete' => false, 'reason' => '内容为空');
    }

    switch ($fileKey) {
        case 'homepage':
        case 'article':
        case 'archive':
            // 完整HTML页面必须有 </html>
            if (stripos($content, '</html>') === false) {
                return array('complete' => false, 'reason' => '缺少 </html> 闭合标签');
            }
            if (stripos($content, '</body>') === false) {
                return array('complete' => false, 'reason' => '缺少 </body> 闭合标签');
            }
            // 检查 <style> 是否闭合
            $styleOpen = substr_count(strtolower($content), '<style');
            $styleClose = substr_count(strtolower($content), '</style>');
            if ($styleOpen > $styleClose) {
                return array('complete' => false, 'reason' => '<style> 标签未闭合');
            }
            // 检查 <head> 是否闭合
            if (stripos($content, '</head>') === false && stripos($content, '<head') !== false) {
                return array('complete' => false, 'reason' => '<head> 标签未闭合');
            }
            break;

        case 'header':
            if (stripos($content, '</header>') === false) {
                return array('complete' => false, 'reason' => '缺少 </header> 闭合标签');
            }
            $styleOpen = substr_count(strtolower($content), '<style');
            $styleClose = substr_count(strtolower($content), '</style>');
            if ($styleOpen > $styleClose) {
                return array('complete' => false, 'reason' => '<style> 标签未闭合');
            }
            // header.html 可能包含内联 <script>（如汉堡菜单JS），也需检查闭合
            $scriptOpen = substr_count(strtolower($content), '<script');
            $scriptClose = substr_count(strtolower($content), '</script>');
            if ($scriptOpen > $scriptClose) {
                return array('complete' => false, 'reason' => '<script> 标签未闭合');
            }
            break;

        case 'footer':
            if (stripos($content, '</footer>') === false) {
                return array('complete' => false, 'reason' => '缺少 </footer> 闭合标签');
            }
            $styleOpen = substr_count(strtolower($content), '<style');
            $styleClose = substr_count(strtolower($content), '</style>');
            if ($styleOpen > $styleClose) {
                return array('complete' => false, 'reason' => '<style> 标签未闭合');
            }
            $scriptOpen = substr_count(strtolower($content), '<script');
            $scriptClose = substr_count(strtolower($content), '</script>');
            if ($scriptOpen > $scriptClose) {
                return array('complete' => false, 'reason' => '<script> 标签未闭合');
            }
            break;

        case 'css':
            // CSS: 大括号必须配对
            $opens = substr_count($content, '{');
            $closes = substr_count($content, '}');
            if ($opens > $closes) {
                return array('complete' => false, 'reason' => 'CSS大括号未闭合 (' . $opens . ' 个 { vs ' . $closes . ' 个 })');
            }
            break;

        case 'js':
            // JS: 圆括号/大括号必须配对
            $opens = substr_count($content, '{');
            $closes = substr_count($content, '}');
            if ($opens > $closes) {
                return array('complete' => false, 'reason' => 'JS大括号未闭合');
            }
            $parensOpen = substr_count($content, '(');
            $parensClose = substr_count($content, ')');
            if ($parensOpen > $parensClose) {
                return array('complete' => false, 'reason' => 'JS圆括号未闭合');
            }
            break;
    }

    return array('complete' => true, 'reason' => '');
}

/**
 * 获取文件类型对应的 max_tokens
 *
 * @param string $fileKey
 * @return int
 */
function get_file_max_tokens($fileKey)
{
    $limits = array(
        'header'   => 4096,
        'footer'   => 4096,
        'homepage' => 16384,
        'article'  => 16384,
        'archive'  => 12288,
        'css'      => 8192,
        'js'       => 4096
    );
    return isset($limits[$fileKey]) ? $limits[$fileKey] : 8192;
}

/**
 * 调用AI API（支持自动续写）
 *
 * @param string $apiUrl      API地址
 * @param string $apiKey      API密钥
 * @param array  $headers     额外请求头
 * @param string $modelName   模型名
 * @param string $systemPrompt 系统提示
 * @param string $userMessage  用户消息
 * @param string $fileKey      文件类型
 * @param int    $maxTokens    单次最大token
 * @param float  $temperature  温度
 * @return array ['success' => bool, 'content' => string, 'error' => string, 'continuations' => int]
 */
function call_ai_with_continuation($apiUrl, $apiKey, $headers, $modelName, $systemPrompt, $userMessage, $fileKey, $maxTokens = 0, $temperature = 0.7)
{
    if ($maxTokens <= 0) {
        $maxTokens = get_file_max_tokens($fileKey);
    }

    $maxContinuations = 3;
    $continuations = 0;
    $fullContent = '';

    // 初始消息列表
    $messages = array(
        array('role' => 'system', 'content' => $systemPrompt),
        array('role' => 'user', 'content' => $userMessage)
    );

    for ($attempt = 0; $attempt <= $maxContinuations; $attempt++) {

        $payload = array(
            'model' => $modelName,
            'messages' => $messages,
            'max_tokens' => $maxTokens,
            'temperature' => $temperature
        );

        $payloadJson = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

        $allHeaders = array(
            'Content-Type: application/json',
            'Accept: application/json',
            'Authorization: Bearer ' . $apiKey
        );
        foreach ($headers as $h) {
            $allHeaders[] = $h;
        }

        $ch = curl_init($apiUrl);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $payloadJson);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $allHeaders);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 240);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);

        $responseBody = curl_exec($ch);
        $curlError    = curl_error($ch);
        $httpCode     = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($responseBody === false) {
            return array('success' => false, 'content' => $fullContent, 'error' => 'AI接口调用失败：' . $curlError, 'continuations' => $continuations);
        }

        $decoded = json_decode($responseBody, true);
        $assistantText = '';
        $finishReason = '';
        $errorMessage = '';

        if (is_array($decoded)) {
            if (isset($decoded['choices'][0]['message']['content'])) {
                $assistantText = (string)$decoded['choices'][0]['message']['content'];
            }
            if (isset($decoded['choices'][0]['finish_reason'])) {
                $finishReason = (string)$decoded['choices'][0]['finish_reason'];
            }
            if (isset($decoded['error']['message'])) {
                $errorMessage = (string)$decoded['error']['message'];
            }
        }

        if ($errorMessage !== '') {
            return array('success' => false, 'content' => $fullContent, 'error' => 'AI返回错误：' . $errorMessage, 'continuations' => $continuations);
        }

        if (trim($assistantText) === '' && $fullContent === '') {
            return array('success' => false, 'content' => '', 'error' => 'AI未返回有效内容（HTTP ' . $httpCode . '）。', 'continuations' => $continuations);
        }

        // 剥离 DeepSeek-R1 等模型的 <think> 推理内容
        $assistantText = strip_ai_thinking_tags($assistantText);

        // 如果剥离后为空（模型只输出了推理没有实际代码），视为截断需续写
        if (trim($assistantText) === '' && $fullContent === '') {
            if ($attempt >= $maxContinuations) {
                return array('success' => false, 'content' => '', 'error' => 'AI仅输出了推理过程，未生成有效模板代码。请更换模型或重试。', 'continuations' => $continuations);
            }
            $continuations++;
            $messages[] = array('role' => 'assistant', 'content' => '(thinking...)');
            $messages[] = array('role' => 'user', 'content' => "请直接输出代码，不要输出推理过程或解释文字。立即开始输出纯HTML/CSS/JS代码。");
            continue;
        }

        // 拼接内容
        $fullContent .= $assistantText;

        // 清理 markdown code block 标记（只在首次和末尾处理）
        $cleaned = trim($fullContent);
        $cleaned = preg_replace('/^```(?:html|htm|css|javascript|js)?\s*\n?/i', '', $cleaned);
        $cleaned = preg_replace('/\n?```\s*$/', '', $cleaned);
        $cleaned = trim($cleaned);

        // 检查是否因为 length 被截断
        $truncatedByLength = ($finishReason === 'length');

        // 检查模板完整性
        $check = check_template_completeness($cleaned, $fileKey);

        if ($check['complete'] && !$truncatedByLength) {
            // 完整了，返回
            return array('success' => true, 'content' => $cleaned, 'error' => '', 'continuations' => $continuations);
        }

        // 还没完整 - 如果已用尽续写次数，返回当前内容并警告
        if ($attempt >= $maxContinuations) {
            return array(
                'success' => true,
                'content' => $cleaned,
                'error' => '',
                'continuations' => $continuations,
                'warning' => '模板可能不完整（续写' . $continuations . '次后仍未闭合：' . $check['reason'] . '）'
            );
        }

        // 准备续写：将已生成的部分作为assistant消息，追加续写指令
        $continuations++;

        $messages[] = array('role' => 'assistant', 'content' => $assistantText);
        $messages[] = array('role' => 'user', 'content' =>
            "你的输出在此处被截断了（" . $check['reason'] . "），请从断点处继续输出剩余代码。\n" .
            "注意：\n" .
            "1. 直接从断点续写，不要重复已输出的内容\n" .
            "2. 不要添加任何解释文字\n" .
            "3. 不要重新输出开头的代码\n" .
            "4. 确保最终HTML/CSS/JS标签全部正确闭合"
        );
    }

    // Should not reach here
    return array('success' => true, 'content' => $fullContent, 'error' => '', 'continuations' => $continuations);
}
