using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using QYZH.InteractiveMagazine.IService;
using QYZH.InteractiveMagazine.Models.Common;
using QYZH.InteractiveMagazine.Models.Dto;
using System.Net.Http.Headers;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace QYZH.InteractiveMagazine.Service;

/// <summary>
/// AI聊天服务实现（OpenAI API规范，流式返回）
/// </summary>
public class AiChatService(
    IHttpClientFactory httpClientFactory,
    IConfiguration configuration,
    ILogger<AiChatService> logger) : IAiChatService
{
    /// <summary>
    /// 预设系统提示词
    /// </summary>
    private const string SystemPrompt = """
        # 提示词：AI 优化"题目评分/报告提示词"

    你是一个专业的提示词优化专家。你的任务是**将用户输入的粗糙、口语化的"题目评分/报告提示词"重构为结构清晰、指令明确、便于 AI 直接执行的标准化提示词**。

    用户（题目制作者）当前输入的内容可能包含：题目描述、作答要求、打分规则、评分维度、报告层级、示例等，但组织混乱、表述模糊。你需要**保留所有原始信息，不增删任何实质性规则**，仅优化其结构、逻辑层次和表达精度。

    ---

    ## 优化原则

    1. **信息完整**：用户原文中的所有要点、示例、层级区分必须全部保留。
    2. **结构清晰**：将内容归入标准模块（如 `任务目标`、`输入格式`、`评分标准`、`报告生成要求`）。
    3. **指令明确**：将模糊表述（如"要写得好一点"）转化为可操作的判定条件（如"必须包含三层结构：解释原因 + 表达情绪 + 提出方案"）。
    4. **语言精练**：去除冗余修饰，保留关键限定词（如"仅""必须""至少"）。
    5. **格式统一**：最终输出为 Markdown 格式，使用标题（`#` `##` `###`）、列表（`-`）、加粗/斜体等提升可读性。

    ---

    ## 优化步骤

    1. **解析原文**：通读用户输入，标注出：
       - 题目背景 / 情境
       - 学生作答要求
       - 评分维度（优秀/一般/薄弱）及其具体判定条件
       - 报告层级及其对应的评语模板或生成逻辑
       - 任何示例答案
    2. **重组结构**：按以下标准模板组织内容（可灵活调整章节名称）：
       - `## 任务概述`（题目 + 要求）
       - `## 输入数据`（学生作答的内容）
       - `## 评分标准`（分档描述，含判定规则）
       - `## 报告生成规范`（层级名称、触发条件、评语示例/生成规则）
       - `## 注意事项`（如有特殊约束）
    3. **润色表达**：
       - 将"可能""大概"等不确定词改为明确的"必须""至少"；
       - 将并列条件用编号列表（1. 2. 3.）拆分；
       - 将示例单独以代码块或引用块呈现，避免与规则混淆。
    4. **保持原意**：不得添加用户未提及的新评分维度或报告层级，也不得删除任何已有规则。

    ---

    ## 输出格式要求

    - 只输出优化后的完整提示词（即 AI 可直接使用的评分/报告 prompt），不要输出分析过程。
    - 使用 Markdown 语法，标题层级从 `#` 开始。
    - 所有原有示例必须原样保留，并标明"示例"或放在引用块中。

    ---

    现在，请对**当前用户输入的原始提示词**执行上述优化过程，仅输出优化后的 Markdown 格式提示词。
    """;

    /// <summary>
    /// 流式AI聊天，逐块返回AI生成的内容
    /// </summary>
    public async IAsyncEnumerable<string> ChatAsync(
        AiChatInput input,
        [EnumeratorCancellation] CancellationToken cancellationToken = default)
    {
        if (string.IsNullOrWhiteSpace(input.Message))
        {
            throw new BusinessException("消息内容不能为空", ResultCode.BAD_REQUEST);
        }

        var apiKey = configuration["AiChat:ApiKey"];
        var baseUrl = configuration["AiChat:BaseUrl"];
        var model = configuration["AiChat:Model"];
        var timeoutSeconds = configuration.GetValue<int>("AiChat:TimeoutSeconds");
        var maxTokens = configuration.GetValue<int>("AiChat:MaxTokens");
        var temperature = configuration.GetValue<double>("AiChat:Temperature");

        if (string.IsNullOrWhiteSpace(apiKey) || string.IsNullOrWhiteSpace(baseUrl) || string.IsNullOrWhiteSpace(model))
        {
            throw new BusinessException("AI聊天服务配置不完整，请检查 AiChat 配置节", ResultCode.GLOBAL_ERROR);
        }

        logger.LogInformation("开始调用AI聊天服务（流式），消息长度：{Length}", input.Message.Length);

        // 构建 OpenAI Chat Completions 请求体（启用流式返回）
        var requestBody = new
        {
            model = model,
            messages = new[]
            {
                new { role = "system", content = SystemPrompt },
                new { role = "user", content = input.Message }
            },
            max_tokens = maxTokens,
            temperature = temperature,
            stream = true
        };

        var jsonContent = JsonSerializer.Serialize(requestBody, new JsonSerializerOptions
        {
            DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
        });

        // 创建 HttpClient 并发起请求（使用 ResponseHeadersRead 提前获取响应头以流式读取）
        var client = httpClientFactory.CreateClient();
        client.Timeout = TimeSpan.FromSeconds(timeoutSeconds > 0 ? timeoutSeconds : 300);
        var request = new HttpRequestMessage(HttpMethod.Post, $"{baseUrl.TrimEnd('/')}/chat/completions");
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
        request.Content = new StringContent(jsonContent, Encoding.UTF8, "application/json");

        using var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);

        if (!response.IsSuccessStatusCode)
        {
            var errorContent = await response.Content.ReadAsStringAsync(cancellationToken);
            logger.LogError("AI聊天服务调用失败，状态码：{StatusCode}，响应：{Response}", response.StatusCode, errorContent);
            throw new BusinessException($"AI服务调用失败：{response.StatusCode}", ResultCode.GLOBAL_ERROR);
        }

        // 流式读取响应体
        using var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken);
        using var reader = new StreamReader(responseStream);

        while (!reader.EndOfStream)
        {
            cancellationToken.ThrowIfCancellationRequested();

            var line = await reader.ReadLineAsync(cancellationToken);
            if (line == null) break;

            // 只处理 data: 开头的行
            if (!line.StartsWith("data: ")) continue;

            var data = line.Substring(6);
            if (data == "[DONE]") break;

            // 解析 SSE chunk，提取 delta.content
            using var chunkDoc = JsonDocument.Parse(data);
            var choicesEl = chunkDoc.RootElement.GetProperty("choices");
            if (choicesEl.GetArrayLength() == 0) continue;

            var delta = choicesEl[0].GetProperty("delta");
            if (delta.TryGetProperty("content", out var contentEl))
            {
                var content = contentEl.GetString();
                if (!string.IsNullOrEmpty(content))
                {
                    yield return content;
                }
            }
        }

        logger.LogInformation("AI聊天服务（流式）调用完成");
    }
}
