using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;

namespace Mindforge.API.Providers
{
    public class GeminiApiProvider : ILlmApiProvider
    {
        private readonly HttpClient _httpClient;
        private readonly IConfiguration _configuration;
        private readonly ILogger<GeminiApiProvider> _logger;

        public GeminiApiProvider(HttpClient httpClient, IConfiguration configuration, ILogger<GeminiApiProvider> logger)
        {
            _httpClient = httpClient;
            _httpClient.Timeout = TimeSpan.FromMinutes(5);
            _configuration = configuration;
            _logger = logger;
        }

        public async Task<string> SendRequestAsync(string systemPrompt, string userPrompt, string model)
        {
            var apiKey = _configuration["GEMINI_API_KEY"];
            if (string.IsNullOrEmpty(apiKey))
            {
                throw new Exception("GEMINI_API_KEY not found in configuration.");
            }

            var apiBase = "https://generativelanguage.googleapis.com/v1beta";
            var url = $"{apiBase.TrimEnd('/')}/models/{model}:generateContent?key={apiKey}";

            var reqBody = new
            {
                system_instruction = string.IsNullOrEmpty(systemPrompt) ? null : new
                {
                    parts = new[] { new { text = systemPrompt } }
                },
                contents = new[]
                {
                    new
                    {
                        role = "user",
                        parts = new[] { new { text = userPrompt } }
                    }
                }
            };

            var jsonBody = JsonSerializer.Serialize(reqBody, new JsonSerializerOptions { DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull });

            using var request = new HttpRequestMessage(HttpMethod.Post, url);
            request.Content = new StringContent(jsonBody, Encoding.UTF8, "application/json");

            var response = await _httpClient.SendAsync(request);
            var responseBody = await response.Content.ReadAsStringAsync();

            if (!response.IsSuccessStatusCode)
            {
                throw new Exception($"Gemini API error status {(int)response.StatusCode}: {responseBody}");
            }

            var result = JsonSerializer.Deserialize<JsonElement>(responseBody);
            if (result.TryGetProperty("candidates", out var candidates) && candidates.GetArrayLength() > 0)
            {
                var content = candidates[0].GetProperty("content");
                if (content.TryGetProperty("parts", out var parts) && parts.GetArrayLength() > 0)
                {
                    return parts[0].GetProperty("text").GetString() ?? string.Empty;
                }
            }

            throw new Exception("empty response from Gemini API");
        }

        public async Task<string> SendRequestBatchAsync(string systemPrompt, string userPrompt, string model)
        {
            var apiKey = _configuration["GEMINI_API_KEY"];
            if (string.IsNullOrEmpty(apiKey))
                throw new Exception("GEMINI_API_KEY not found in configuration.");

            var apiBase = "https://generativelanguage.googleapis.com/v1beta";
            var jsonOptions = new JsonSerializerOptions { DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull };

            // Build single inline request
            var batchBody = new
            {
                batch = new
                {
                    display_name = "mindforge-batch",
                    input_config = new
                    {
                        requests = new
                        {
                            requests = new[]
                            {
                                new
                                {
                                    request = new
                                    {
                                        system_instruction = string.IsNullOrEmpty(systemPrompt) ? null : new
                                        {
                                            parts = new[] { new { text = systemPrompt } }
                                        },
                                        contents = new[]
                                        {
                                            new
                                            {
                                                role = "user",
                                                parts = new[] { new { text = userPrompt } }
                                            }
                                        }
                                    },
                                    metadata = new { key = "request-1" }
                                }
                            }
                        }
                    }
                }
            };

            // Submit batch job
            var createUrl = $"{apiBase}/models/{model}:batchGenerateContent?key={apiKey}";
            using var createReq = new HttpRequestMessage(HttpMethod.Post, createUrl);
            createReq.Content = new StringContent(JsonSerializer.Serialize(batchBody, jsonOptions), Encoding.UTF8, "application/json");

            var createResp = await _httpClient.SendAsync(createReq);
            var createBody = await createResp.Content.ReadAsStringAsync();
            if (!createResp.IsSuccessStatusCode)
                throw new Exception($"Gemini Batch API error creating job {(int)createResp.StatusCode}: {createBody}");

            _logger.LogInformation("Gemini Batch API job created");

            var createResult = JsonSerializer.Deserialize<JsonElement>(createBody);
            if (!createResult.TryGetProperty("name", out var nameEl))
                throw new Exception("Gemini Batch API did not return a job name.");

            var batchName = nameEl.GetString()!;
            var pollUrl = $"{apiBase}/{batchName}?key={apiKey}";

            _logger.LogInformation("Gemini Batch API job name: {BatchName}", batchName);

            // Poll until terminal state
            while (true)
            {
                await Task.Delay(TimeSpan.FromSeconds(10));

                using var pollReq = new HttpRequestMessage(HttpMethod.Get, pollUrl);
                var pollResp = await _httpClient.SendAsync(pollReq);
                var pollBody = await pollResp.Content.ReadAsStringAsync();

                if (!pollResp.IsSuccessStatusCode)
                    throw new Exception($"Gemini Batch API error polling status {(int)pollResp.StatusCode}: {pollBody}");

                var pollResult = JsonSerializer.Deserialize<JsonElement>(pollBody);
                var metadata = pollResult.GetProperty("metadata");
                var state = metadata.GetProperty("state");

                _logger.LogInformation("Gemini Batch API job state: {State}", state.GetString());

                switch (state.GetString())
                {
                    case "BATCH_STATE_SUCCEEDED":
                        if (pollResult.TryGetProperty("response", out var batchResponse) &&
                            batchResponse.TryGetProperty("inlinedResponses", out var inlinedResponses) &&
                            inlinedResponses.TryGetProperty("inlinedResponses", out var inlinedResponsesInternal) &&
                            inlinedResponsesInternal.GetArrayLength() > 0)
                        {
                            _logger.LogInformation("Gemini Batch API job succeeded");

                            var first = inlinedResponsesInternal[0];
                            if (first.TryGetProperty("error", out var reqError))
                                throw new Exception($"Gemini Batch request error: {reqError}");

                            if (first.TryGetProperty("response", out var innerResponse) &&
                                innerResponse.TryGetProperty("candidates", out var candidates) &&
                                candidates.GetArrayLength() > 0)
                            {
                                var content = candidates[0].GetProperty("content");
                                if (content.TryGetProperty("parts", out var parts) && parts.GetArrayLength() > 0)
                                    return parts[0].GetProperty("text").GetString() ?? string.Empty;
                            }
                        }
                        throw new Exception("Gemini Batch job succeeded but returned no content.");

                    case "BATCH_STATE_FAILED":
                        throw new Exception($"Gemini Batch job failed: {pollBody}");

                    case "BATCH_STATE_CANCELLED":
                        throw new Exception("Gemini Batch job was cancelled.");

                    case "BATCH_STATE_EXPIRED":
                        throw new Exception("Gemini Batch job expired before completing.");

                    // BATCH_STATE_PENDING / BATCH_STATE_RUNNING — keep polling
                }
            }
        }
    }
}
