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
{
    // ─── Claude Function Calling ───────────────────────────────────────

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

        var body = BuildClaudeToolBody(messages, tools);
        var json = JsonSerializer.Serialize(body);

        using var req = new HttpRequestMessage(HttpMethod.Post, "https://api.anthropic.com/v1/messages");
        req.Content = new StringContent(json, Encoding.UTF8, "application/json");
        req.Headers.Add("x-api-key", apiKey);
        req.Headers.Add("anthropic-version", "2023-06-01");

        using var resp = await _http.SendAsync(req, ct);
        if (!resp.IsSuccessStatusCode)
        {
            var errBody = await resp.Content.ReadAsStringAsync(ct);
            throw new HttpRequestException(ClassifyHttpError(resp, errBody));
        }

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

        // 토큰 사용량
        if (root.TryGetProperty("usage", out var usage))
            TryParseClaudeUsageFromElement(usage);

        // 컨텐츠 블록 파싱
        var blocks = new List<ContentBlock>();
        if (root.TryGetProperty("content", out var content))
        {
            foreach (var block in content.EnumerateArray())
            {
                var type = block.TryGetProperty("type", out var tp) ? tp.GetString() : "";
                if (type == "text")
                {
                    blocks.Add(new ContentBlock
                    {
                        Type = "text",
                        Text = block.TryGetProperty("text", out var txt) ? txt.GetString() ?? "" : ""
                    });
                }
                else if (type == "tool_use")
                {
                    blocks.Add(new ContentBlock
                    {
                        Type = "tool_use",
                        ToolName = block.TryGetProperty("name", out var nm) ? nm.GetString() ?? "" : "",
                        ToolId = block.TryGetProperty("id", out var bid) ? bid.GetString() ?? "" : "",
                        ToolInput = block.TryGetProperty("input", out var inp) ? inp.Clone() : null
                    });
                }
            }
        }

        return blocks;
    }

    private object BuildClaudeToolBody(List<ChatMessage> messages, IReadOnlyCollection<IAgentTool> tools)
    {
        var llm = _settings.Settings.Llm;
        var msgs = new List<object>();

        foreach (var m in messages)
        {
            if (m.Role == "system") continue;

            // tool_result 메시지인지 확인
            if (m.Role == "user" && m.Content.StartsWith("{\"type\":\"tool_result\""))
            {
                try
                {
                    using var doc = JsonDocument.Parse(m.Content);
                    var root = doc.RootElement;
                    msgs.Add(new
                    {
                        role = "user",
                        content = new object[]
                        {
                            new
                            {
                                type = "tool_result",
                                tool_use_id = root.TryGetProperty("tool_use_id", out var tuid) ? tuid.GetString() : "",
                                content = root.TryGetProperty("content", out var tcont) ? tcont.GetString() : ""
                            }
                        }
                    });
                    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)) throw new Exception();
                    var contentList = new List<object>();
                    foreach (var b in blocksArr.EnumerateArray())
                    {
                        var bType = b.TryGetProperty("type", out var bt) ? bt.GetString() : "";
                        if (bType == "text")
                            contentList.Add(new { type = "text", text = b.TryGetProperty("text", out var tx) ? tx.GetString() ?? "" : "" });
                        else if (bType == "tool_use")
                            contentList.Add(new
                            {
                                type = "tool_use",
                                id = b.TryGetProperty("id", out var bid) ? bid.GetString() ?? "" : "",
                                name = b.TryGetProperty("name", out var nm) ? nm.GetString() ?? "" : "",
                                input = b.TryGetProperty("input", out var inp) ? (object)inp.Clone() : new { }
                            });
                    }
                    msgs.Add(new { role = "assistant", content = contentList });
                    continue;
                }
                catch (Exception) { /* 파싱 실패시 일반 메시지로 처리 */ }
            }

            // Claude Vision: 이미지가 있으면 content를 배열로 변환
            if (m.Images?.Count > 0 && m.Role == "user")
            {
                var contentParts = new List<object>();
                foreach (var img in m.Images)
                    contentParts.Add(new { type = "image", source = new { type = "base64", media_type = img.MimeType, data = img.Base64 } });
                contentParts.Add(new { type = "text", text = m.Content });
                msgs.Add(new { role = m.Role, content = contentParts });
            }
            else
            {
                msgs.Add(new { role = m.Role, content = m.Content });
            }
        }

        // 도구 정의
        var toolDefs = tools.Select(t => new
        {
            name = t.Name,
            description = t.Description,
            input_schema = new
            {
                type = "object",
                properties = t.Parameters.Properties.ToDictionary(
                    kv => kv.Key,
                    kv => BuildPropertySchema(kv.Value, false)),
                required = t.Parameters.Required
            }
        }).ToArray();

        // 시스템 프롬프트
        var systemPrompt = messages.FirstOrDefault(m => m.Role == "system")?.Content ?? _systemPrompt;
        var activeModel = ResolveModel();

        if (!string.IsNullOrEmpty(systemPrompt))
        {
            return new
            {
                model = activeModel,
                max_tokens = Math.Max(llm.MaxContextTokens, 4096),
                temperature = llm.Temperature,
                system = systemPrompt,
                messages = msgs,
                tools = toolDefs,
                stream = false
            };
        }

        return new
        {
            model = activeModel,
            max_tokens = Math.Max(llm.MaxContextTokens, 4096),
            temperature = llm.Temperature,
            messages = msgs,
            tools = toolDefs,
            stream = false
        };
    }
}
