using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using Meezi.Core.Interfaces;
using Meezi.Core.Platform;

namespace Meezi.API.Services;

public interface IOpenAiChatService
{
    Task<bool> IsConfiguredForCoffeeAdvisorAsync(CancellationToken cancellationToken = default);
    Task<string?> CompleteJsonAsync(string systemPrompt, string userPrompt, CancellationToken cancellationToken = default);
}

public class OpenAiChatService : IOpenAiChatService
{
    private static readonly JsonSerializerOptions JsonOpts = new()
    {
        PropertyNameCaseInsensitive = true,
        DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
    };

    private readonly IHttpClientFactory _httpClientFactory;
    private readonly IPlatformRuntimeConfig _platform;
    private readonly IConfiguration _configuration;
    private readonly ILogger<OpenAiChatService> _logger;

    public OpenAiChatService(
        IHttpClientFactory httpClientFactory,
        IPlatformRuntimeConfig platform,
        IConfiguration configuration,
        ILogger<OpenAiChatService> logger)
    {
        _httpClientFactory = httpClientFactory;
        _platform = platform;
        _configuration = configuration;
        _logger = logger;
    }

    public async Task<bool> IsConfiguredForCoffeeAdvisorAsync(CancellationToken cancellationToken = default)
    {
        if (!await IsCoffeeAdvisorEnabledAsync(cancellationToken))
            return false;
        return !string.IsNullOrWhiteSpace(await GetApiKeyAsync(cancellationToken));
    }

    public async Task<string?> CompleteJsonAsync(
        string systemPrompt,
        string userPrompt,
        CancellationToken cancellationToken = default)
    {
        var apiKey = await GetApiKeyAsync(cancellationToken);
        if (string.IsNullOrWhiteSpace(apiKey))
            return null;

        var model = await GetModelAsync(cancellationToken);
        var body = JsonSerializer.Serialize(new
        {
            model,
            temperature = 0.4,
            response_format = new { type = "json_object" },
            messages = new object[]
            {
                new { role = "system", content = systemPrompt },
                new { role = "user", content = userPrompt }
            }
        }, JsonOpts);

        var client = _httpClientFactory.CreateClient("OpenAi");
        using var req = new HttpRequestMessage(HttpMethod.Post, "https://api.openai.com/v1/chat/completions")
        {
            Content = new StringContent(body, Encoding.UTF8, "application/json")
        };
        req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);

        using var res = await client.SendAsync(req, cancellationToken);
        if (!res.IsSuccessStatusCode)
        {
            _logger.LogWarning("OpenAI chat failed with status {Status}", res.StatusCode);
            return null;
        }

        await using var stream = await res.Content.ReadAsStreamAsync(cancellationToken);
        var doc = await JsonDocument.ParseAsync(stream, cancellationToken: cancellationToken);
        return doc.RootElement
            .GetProperty("choices")[0]
            .GetProperty("message")
            .GetProperty("content")
            .GetString();
    }

    private async Task<bool> IsCoffeeAdvisorEnabledAsync(CancellationToken cancellationToken)
    {
        var enabled = await _platform.GetAsync(PlatformIntegrationKeys.OpenAiEnabled, cancellationToken);
        if (enabled is "false")
            return false;
        var feature = await _platform.GetAsync(PlatformIntegrationKeys.OpenAiCoffeeAdvisorEnabled, cancellationToken);
        return feature is not "false";
    }

    private async Task<string?> GetApiKeyAsync(CancellationToken cancellationToken)
    {
        var fromDb = await _platform.GetAsync(PlatformIntegrationKeys.OpenAiApiKey, cancellationToken);
        if (!string.IsNullOrWhiteSpace(fromDb))
            return fromDb.Trim();
        return _configuration["OpenAI:ApiKey"]?.Trim();
    }

    private async Task<string> GetModelAsync(CancellationToken cancellationToken)
    {
        var fromDb = await _platform.GetAsync(PlatformIntegrationKeys.OpenAiModel, cancellationToken);
        if (!string.IsNullOrWhiteSpace(fromDb))
            return fromDb.Trim();
        return _configuration["OpenAI:Model"]?.Trim() ?? "gpt-4o-mini";
    }
}
