using System.Net.Http.Headers;

namespace Service;

public interface IOpenAiService
{
    Task<string?> ChatAsync(string systemPrompt, string userPrompt);
    Task<string?> ChatAsync(string prompt);
    IAsyncEnumerable<string> ChatStreamAsync(string systemPrompt, string userPrompt);
    IAsyncEnumerable<string> ChatStreamAsync(string prompt);
}

public class OpenAiService(
    IOptions<AISettings> aiSettings,
    ILogger<OpenAiService> logger
) : IOpenAiService
{
    public async Task<string?> ChatAsync(string systemPrompt, string userPrompt)
    {
        var cfg = aiSettings.Value;
        if (string.IsNullOrWhiteSpace(cfg.Endpoint) || 
            string.IsNullOrWhiteSpace(cfg.Key) || 
            string.IsNullOrWhiteSpace(cfg.Model))
        {
            logger.LogWarning("未配置 OpenAI/DeepSeek 接口，无法调用 AI");
            return null;
        }

        using var http = new HttpClient();
        http.Timeout = TimeSpan.FromSeconds(15);
        http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", cfg.Key);

        var payload = new
        {
            model = cfg.Model,
            temperature = 0,
            messages = new object[]
            {
                new { role = "system", content = systemPrompt },
                new { role = "user", content = userPrompt }
            }
        };

        var url = cfg.Endpoint.TrimEnd('/') + "/chat/completions";
        var json = JsonSerializer.Serialize(payload);
        using var content = new StringContent(json, Encoding.UTF8, "application/json");
    
        try
        {
            using var resp = await http.PostAsync(url, content);
            if (!resp.IsSuccessStatusCode)
            {
                var err = await resp.Content.ReadAsStringAsync();
                throw new InvalidOperationException($"AI接口调用失败: {(int)resp.StatusCode} {resp.ReasonPhrase}, {err}");
            }

            var respText = await resp.Content.ReadAsStringAsync();

            using var doc = JsonDocument.Parse(respText);
            var root = doc.RootElement;
            var contentText = root.GetProperty("choices")[0]
                .GetProperty("message")
                .GetProperty("content")
                .GetString();

            return contentText;
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "AI 调用失败");
            throw;
        }
    }

    public async Task<string?> ChatAsync(string prompt)
    {
        var cfg = aiSettings.Value;
        if (string.IsNullOrWhiteSpace(cfg.Endpoint) || 
            string.IsNullOrWhiteSpace(cfg.Key) || 
            string.IsNullOrWhiteSpace(cfg.Model))
        {
            logger.LogWarning("未配置 OpenAI/DeepSeek 接口，无法调用 AI");
            return null;
        }

        using var http = new HttpClient();
        http.Timeout = TimeSpan.FromSeconds(30);
        http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", cfg.Key);

        var payload = new
        {
            model = cfg.Model,
            temperature = 0,
            messages = new object[]
            {
                new { role = "user", content = prompt }
            }
        };

        var url = cfg.Endpoint.TrimEnd('/') + "/chat/completions";
        var json = JsonSerializer.Serialize(payload);
        using var content = new StringContent(json, Encoding.UTF8, "application/json");
    
        try
        {
            using var resp = await http.PostAsync(url, content);
            if (!resp.IsSuccessStatusCode)
            {
                var err = await resp.Content.ReadAsStringAsync();
                throw new InvalidOperationException($"AI接口调用失败: {(int)resp.StatusCode} {resp.ReasonPhrase}, {err}");
            }

            var respText = await resp.Content.ReadAsStringAsync();

            using var doc = JsonDocument.Parse(respText);
            var root = doc.RootElement;
            var contentText = root.GetProperty("choices")[0]
                .GetProperty("message")
                .GetProperty("content")
                .GetString();

            return contentText;
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "AI 调用失败");
            throw;
        }
    }

    public async IAsyncEnumerable<string> ChatStreamAsync(string prompt)
    {
        var cfg = aiSettings.Value;
        if (string.IsNullOrWhiteSpace(cfg.Endpoint) || 
            string.IsNullOrWhiteSpace(cfg.Key) || 
            string.IsNullOrWhiteSpace(cfg.Model))
        {
            logger.LogWarning("未配置 OpenAI/DeepSeek 接口，无法调用 AI");
            yield break;
        }

        using var http = new HttpClient();
        http.Timeout = TimeSpan.FromMinutes(5);
        http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", cfg.Key);

        var payload = new
        {
            model = cfg.Model,
            temperature = 0,
            stream = true,
            messages = new object[]
            {
                new { role = "user", content = prompt }
            }
        };

        var url = cfg.Endpoint.TrimEnd('/') + "/chat/completions";
        var json = JsonSerializer.Serialize(payload);
        using var content = new StringContent(json, Encoding.UTF8, "application/json");
    
        using var request = new HttpRequestMessage(HttpMethod.Post, url)
        {
            Content = content
        };
        using var resp = await http.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
    
        if (!resp.IsSuccessStatusCode)
        {
            var err = await resp.Content.ReadAsStringAsync();
            throw new InvalidOperationException($"AI接口调用失败: {(int)resp.StatusCode} {resp.ReasonPhrase}, {err}");
        }

        using var stream = await resp.Content.ReadAsStreamAsync();
        using var reader = new StreamReader(stream);

        string? line;
        while ((line = await reader.ReadLineAsync()) != null)
        {
            if (string.IsNullOrWhiteSpace(line) || !line.StartsWith("data: "))
                continue;

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

            using var doc = JsonDocument.Parse(data);
            var root = doc.RootElement;
            if (root.TryGetProperty("choices", out var choices) && choices.GetArrayLength() > 0)
            {
                var delta = choices[0].GetProperty("delta");
                if (delta.TryGetProperty("content", out var contentProp))
                {
                    var contentText = contentProp.GetString();
                    if (!string.IsNullOrEmpty(contentText))
                    {
                        yield return contentText;
                    }
                }
            }
        }
    }

    public async IAsyncEnumerable<string> ChatStreamAsync(string systemPrompt, string userPrompt)
    {
        var cfg = aiSettings.Value;
        if (string.IsNullOrWhiteSpace(cfg.Endpoint) || 
            string.IsNullOrWhiteSpace(cfg.Key) || 
            string.IsNullOrWhiteSpace(cfg.Model))
        {
            logger.LogWarning("未配置 OpenAI/DeepSeek 接口，无法调用 AI");
            yield break;
        }

        using var http = new HttpClient();
        http.Timeout = TimeSpan.FromMinutes(5);
        http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", cfg.Key);

        var payload = new
        {
            model = cfg.Model,
            temperature = 0,
            stream = true,
            messages = new object[]
            {
                new { role = "system", content = systemPrompt },
                new { role = "user", content = userPrompt }
            }
        };

        var url = cfg.Endpoint.TrimEnd('/') + "/chat/completions";
        var json = JsonSerializer.Serialize(payload);
        using var content = new StringContent(json, Encoding.UTF8, "application/json");
    
        // 使用 SendAsync 来支持 HttpCompletionOption
        using var request = new HttpRequestMessage(HttpMethod.Post, url)
        {
            Content = content
        };
        using var resp = await http.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
    
        if (!resp.IsSuccessStatusCode)
        {
            var err = await resp.Content.ReadAsStringAsync();
            throw new InvalidOperationException($"AI接口调用失败: {(int)resp.StatusCode} {resp.ReasonPhrase}, {err}");
        }

        using var stream = await resp.Content.ReadAsStreamAsync();
        using var reader = new StreamReader(stream);

        string? line;
        while ((line = await reader.ReadLineAsync()) != null)
        {
            if (string.IsNullOrWhiteSpace(line) || !line.StartsWith("data: "))
                continue;

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

            // 解析JSON时不使用try-catch，因为在async iterator中不能使用
            using var doc = JsonDocument.Parse(data);
            var root = doc.RootElement;
            if (root.TryGetProperty("choices", out var choices) && choices.GetArrayLength() > 0)
            {
                var delta = choices[0].GetProperty("delta");
                if (delta.TryGetProperty("content", out var contentProp))
                {
                    var contentText = contentProp.GetString();
                    if (!string.IsNullOrEmpty(contentText))
                    {
                        yield return contentText;
                    }
                }
            }
        }
    }
}
