using System.Net.Http.Headers;

namespace Health.Infrastructure.AI;

/// <summary>
/// OpenAI 兼容协议 HTTP 客户端，统一调用 DeepSeek / 千问 VL
/// </summary>
public sealed class OpenAiCompatibleClient(string baseUrl, string apiKey, string model)
{
    private readonly HttpClient _http = CreateHttpClient(baseUrl, apiKey);
    private readonly string _model = model;
    private readonly JsonSerializerOptions _jsonOptions = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
        PropertyNameCaseInsensitive = true
    };

    private static HttpClient CreateHttpClient(string baseUrl, string apiKey)
    {
        var client = new HttpClient
        {
            BaseAddress = new Uri(baseUrl.TrimEnd('/') + "/"),
            Timeout = TimeSpan.FromSeconds(60)
        };
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        return client;
    }

    /// <summary>
    /// 流式 Chat Completions（SSE）
    /// </summary>
    public async IAsyncEnumerable<string> ChatStreamAsync(
        List<ChatMessage> messages,
        List<ToolDefinition>? tools = null,
        int maxTokens = 2048,
        float temperature = 0.7f)
    {
        var request = new ChatCompletionRequest
        {
            Model = _model,
            Messages = messages,
            Stream = true,
            MaxTokens = maxTokens,
            Temperature = temperature,
            Tools = tools,
        };

        if (tools?.Count > 0)
            request.ToolChoice = "auto";

        var json = JsonSerializer.Serialize(request, _jsonOptions);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

        var httpRequest = new HttpRequestMessage(HttpMethod.Post, "chat/completions")
        {
            Content = content
        };
        httpRequest.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/event-stream"));

        var response = await _http.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead);
        response.EnsureSuccessStatusCode();

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

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

            var data = line["data: ".Length..];
            if (data == "[DONE]") break;

            yield return data;
        }
    }

    /// <summary>
    /// 非流式 Chat Completions
    /// </summary>
    public async Task<ChatCompletionResponse> ChatAsync(
        List<ChatMessage> messages,
        List<ToolDefinition>? tools = null,
        int maxTokens = 2048,
        float temperature = 0.7f)
    {
        var request = new ChatCompletionRequest
        {
            Model = _model,
            Messages = messages,
            Stream = false,
            MaxTokens = maxTokens,
            Temperature = temperature,
            Tools = tools,
        };

        if (tools?.Count > 0)
            request.ToolChoice = "auto";

        var json = JsonSerializer.Serialize(request, _jsonOptions);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

        var response = await _http.PostAsync("chat/completions", content);
        response.EnsureSuccessStatusCode();

        var body = await response.Content.ReadAsStringAsync();
        return JsonSerializer.Deserialize<ChatCompletionResponse>(body, _jsonOptions)!;
    }

    /// <summary>
    /// Vision 图片理解（非流式）
    /// </summary>
    public async Task<ChatCompletionResponse> VisionAsync(
        string systemPrompt,
        List<string> imageUrls,
        string? userText = null,
        int maxTokens = 2048)
    {
        var messages = new List<ChatMessage>();

        if (!string.IsNullOrEmpty(systemPrompt))
            messages.Add(new ChatMessage { Role = "system", Content = systemPrompt });

        // 构建多模态消息内容
        var contentParts = new List<object>();
        foreach (var url in imageUrls)
            contentParts.Add(new { type = "image_url", image_url = new { url } });
        if (!string.IsNullOrEmpty(userText))
            contentParts.Add(new { type = "text", text = userText });

        var userMessage = new ChatMessage
        {
            Role = "user",
            Content = JsonSerializer.Serialize(contentParts, _jsonOptions)
        };

        messages.Add(userMessage);

        var request = new ChatCompletionRequest
        {
            Model = _model,
            Messages = messages,
            MaxTokens = maxTokens,
            Stream = false,
        };

        var json = JsonSerializer.Serialize(request, _jsonOptions);
        var content = new StringContent(json, Encoding.UTF8, "application/json");
        var response = await _http.PostAsync("chat/completions", content);
        response.EnsureSuccessStatusCode();
        var body = await response.Content.ReadAsStringAsync();
        return JsonSerializer.Deserialize<ChatCompletionResponse>(body, _jsonOptions)!;
    }
}

#region 请求/响应模型

public sealed class ChatCompletionRequest
{
    public string Model { get; set; } = string.Empty;
    public List<ChatMessage> Messages { get; set; } = [];
    public bool Stream { get; set; }
    public int MaxTokens { get; set; } = 2048;
    public float Temperature { get; set; } = 0.7f;
    public float? TopP { get; set; }
    public List<ToolDefinition>? Tools { get; set; }
    public string? ToolChoice { get; set; }
    [System.Text.Json.Serialization.JsonPropertyName("vl_high_resolution_images")]
    public bool VlHighResolutionImages { get; set; }
}

public sealed class ChatMessage
{
    public string Role { get; set; } = string.Empty;
    public object? Content { get; set; } = string.Empty;
    [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)]
    public string? ToolCallId { get; set; }
    [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)]
    public List<ToolCall>? ToolCalls { get; set; }
}

public sealed class ToolDefinition
{
    public string Type { get; set; } = "function";
    public ToolFunction Function { get; set; } = new();
}

public sealed class ToolFunction
{
    public string Name { get; set; } = string.Empty;
    public string Description { get; set; } = string.Empty;
    public object Parameters { get; set; } = new();
}

public sealed class ToolCall
{
    public string Id { get; set; } = string.Empty;
    public string Type { get; set; } = "function";
    public ToolCallFunction Function { get; set; } = new();
}

public sealed class ToolCallFunction
{
    public string Name { get; set; } = string.Empty;
    public string Arguments { get; set; } = string.Empty;
}

public sealed class ChatCompletionResponse
{
    public string Id { get; set; } = string.Empty;
    public List<Choice> Choices { get; set; } = [];
}

public sealed class Choice
{
    public int Index { get; set; }
    public ResponseMessage? Message { get; set; }
    public ResponseDelta? Delta { get; set; }
    public string? FinishReason { get; set; }
}

public sealed class ResponseMessage
{
    public string Role { get; set; } = string.Empty;
    public string? Content { get; set; }
    public List<ToolCall>? ToolCalls { get; set; }
}

public sealed class ResponseDelta
{
    public string? Content { get; set; }
    public string? Role { get; set; }
}

#endregion
