using System.Net.Http;
using System.Text;
using System.Text.Json;
using AxCopilot.Models;
using AxCopilot.Services.Agent;

namespace AxCopilot.Services;

public partial class LlmService
{
    // ─── Gemini Function Calling ───────────────────────────────────────

    private async Task<List<ContentBlock>> SendGeminiWithToolsAsync(
        List<ChatMessage> messages, IReadOnlyCollection<IAgentTool> tools, CancellationToken ct)
    {
        var llm = _settings.Settings.Llm;
        var apiKey = ResolveApiKeyForService("gemini");
        if (string.IsNullOrEmpty(apiKey))
            throw new InvalidOperationException("Gemini API 키가 설정되지 않았습니다.");

        var activeModel = ResolveModel();
        var body = BuildGeminiToolBody(messages, tools);
        var url = $"https://generativelanguage.googleapis.com/v1beta/models/{activeModel}:generateContent?key={apiKey}";
        var json = JsonSerializer.Serialize(body);

        using var content = new StringContent(json, Encoding.UTF8, "application/json");
        using var resp = await _http.PostAsync(url, content, ct);
        if (!resp.IsSuccessStatusCode)
        {
            var errBody = await resp.Content.ReadAsStringAsync(ct);
            throw new HttpRequestException($"Gemini API 오류 ({resp.StatusCode}): {errBody}");
        }

        var respJson = await resp.Content.ReadAsStringAsync(ct);
        using var doc = JsonDocument.Parse(respJson);
        var root = doc.RootElement;

        TryParseGeminiUsage(root);

        var blocks = new List<ContentBlock>();
        if (root.TryGetProperty("candidates", out var candidates) && candidates.GetArrayLength() > 0)
        {
            var firstCandidate = candidates[0];
            if (firstCandidate.TryGetProperty("content", out var contentObj) &&
                contentObj.TryGetProperty("parts", out var parts))
            {
                foreach (var part in parts.EnumerateArray())
                {
                    if (part.TryGetProperty("text", out var text))
                    {
                        blocks.Add(new ContentBlock { Type = "text", Text = text.GetString() ?? "" });
                    }
                    else if (part.TryGetProperty("functionCall", out var fc))
                    {
                        blocks.Add(new ContentBlock
                        {
                            Type = "tool_use",
                            ToolName = fc.TryGetProperty("name", out var fcName) ? fcName.GetString() ?? "" : "",
                            ToolId = Guid.NewGuid().ToString("N")[..12],
                            ToolInput = fc.TryGetProperty("args", out var a) ? a.Clone() : null
                        });
                    }
                }
            }
        }

        return blocks;
    }

    private object BuildGeminiToolBody(List<ChatMessage> messages, IReadOnlyCollection<IAgentTool> tools)
    {
        var contents = new List<object>();
        foreach (var m in messages)
        {
            if (m.Role == "system") continue;
            var role = m.Role == "assistant" ? "model" : "user";

            // tool_result 메시지 처리
            if (m.Role == "user" && m.Content.StartsWith("{\"type\":\"tool_result\""))
            {
                try
                {
                    using var doc = JsonDocument.Parse(m.Content);
                    var root = doc.RootElement;
                    var toolName = root.TryGetProperty("tool_name", out var tn) ? tn.GetString() ?? "" : "";
                    var toolContent = root.TryGetProperty("content", out var tc) ? tc.GetString() ?? "" : "";
                    contents.Add(new
                    {
                        role = "function",
                        parts = new object[]
                        {
                            new
                            {
                                functionResponse = new
                                {
                                    name = toolName,
                                    response = new { result = toolContent }
                                }
                            }
                        }
                    });
                    continue;
                }
                catch (Exception) { }
            }

            // assistant 메시지에 tool_use 블록이 포함된 경우 (에이전트 루프)
            if (m.Role == "assistant" && m.Content.StartsWith("{\"_tool_use_blocks\""))
            {
                try
                {
                    using var doc = JsonDocument.Parse(m.Content);
                    if (doc.RootElement.TryGetProperty("_tool_use_blocks", out var blocksArr))
                    {
                        var parts = new List<object>();
                        foreach (var b in blocksArr.EnumerateArray())
                        {
                            var bType = b.TryGetProperty("type", out var bt) ? bt.GetString() : "";
                            if (bType == "text")
                                parts.Add(new { text = b.TryGetProperty("text", out var tx) ? tx.GetString() ?? "" : "" });
                            else if (bType == "tool_use")
                                parts.Add(new
                                {
                                    functionCall = new
                                    {
                                        name = b.TryGetProperty("name", out var nm) ? nm.GetString() ?? "" : "",
                                        args = b.TryGetProperty("input", out var inp) ? (object)inp.Clone() : new { }
                                    }
                                });
                        }
                        contents.Add(new { role = "model", parts });
                        continue;
                    }
                }
                catch (Exception) { }
            }

            // Gemini Vision: 이미지가 있으면 parts에 inlineData 추가
            if (m.Images?.Count > 0 && m.Role == "user")
            {
                var imgParts = new List<object> { new { text = m.Content } };
                foreach (var img in m.Images)
                    imgParts.Add(new { inlineData = new { mimeType = img.MimeType, data = img.Base64 } });
                contents.Add(new { role, parts = imgParts });
            }
            else
            {
                contents.Add(new { role, parts = new[] { new { text = m.Content } } });
            }
        }

        // 도구 정의 (Gemini function_declarations 형식)
        var funcDecls = tools.Select(t => new
        {
            name = t.Name,
            description = t.Description,
            parameters = new
            {
                type = "OBJECT",
                properties = t.Parameters.Properties.ToDictionary(
                    kv => kv.Key,
                    kv => BuildPropertySchema(kv.Value, true)),
                required = t.Parameters.Required
            }
        }).ToArray();

        var systemInstruction = messages.FirstOrDefault(m => m.Role == "system");

        var body = new Dictionary<string, object>
        {
            ["contents"] = contents,
            ["tools"] = new[] { new { function_declarations = funcDecls } },
            ["generationConfig"] = new
            {
                temperature = _settings.Settings.Llm.Temperature,
                maxOutputTokens = _settings.Settings.Llm.MaxContextTokens,
            }
        };

        if (systemInstruction != null)
        {
            body["systemInstruction"] = new
            {
                parts = new[] { new { text = systemInstruction.Content } }
            };
        }

        return body;
    }
}
