using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;

namespace CG.Chat
{
    public sealed class OpenAICompatibleChatProvider : IChatProvider
    {
        private readonly string _baseUrl;
        private readonly string _apiKey;

        public OpenAICompatibleChatProvider(string baseUrl, string apiKey)
        {
            _baseUrl = (baseUrl ?? "").TrimEnd('/');
            _apiKey = apiKey ?? "";
        }

        [Serializable] private class ReqMsg { public string role; public string content; }
        [Serializable] private class ChatReq { public string model; public ReqMsg[] messages; public float temperature = 0.7f; }
        [Serializable] private class RespMsg { public string role; public string content; }
        [Serializable] private class Choice { public RespMsg message; }
        [Serializable] private class ChatResp { public Choice[] choices; }

        public async Task<string> SendChatAsync(IReadOnlyList<ChatMessage> messages, string model, CancellationToken ct)
        {
            var url = $"{_baseUrl}/chat/completions";

            var req = new ChatReq
            {
                model = model,
                messages = Build(messages),
                temperature = 0.7f
            };

            var json = JsonUtility.ToJson(req);
            using var uwr = new UnityWebRequest(url, "POST");
            uwr.uploadHandler = new UploadHandlerRaw(Encoding.UTF8.GetBytes(json));
            uwr.downloadHandler = new DownloadHandlerBuffer();
            uwr.SetRequestHeader("Content-Type", "application/json");
            if (!string.IsNullOrWhiteSpace(_apiKey))
                uwr.SetRequestHeader("Authorization", $"Bearer {_apiKey}");

            var op = uwr.SendWebRequest();
            while (!op.isDone)
            {
                if (ct.IsCancellationRequested)
                {
                    uwr.Abort();
                    ct.ThrowIfCancellationRequested();
                }
                await Task.Yield();
            }

            if (uwr.result != UnityWebRequest.Result.Success)
                throw new Exception($"OpenAI-compatible request failed: {uwr.error}\n{uwr.downloadHandler.text}");

            var text = uwr.downloadHandler.text;
            var resp = JsonUtility.FromJson<ChatResp>(text);
            return resp?.choices != null && resp.choices.Length > 0 ? (resp.choices[0].message?.content ?? "") : "";
        }

        private static ReqMsg[] Build(IReadOnlyList<ChatMessage> messages)
        {
            var arr = new ReqMsg[messages.Count];
            for (int i = 0; i < messages.Count; i++)
                arr[i] = new ReqMsg { role = messages[i].role, content = messages[i].content };
            return arr;
        }
    }
}
