using System.Net.Http.Json;
using System.Text.Json;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace FacebookService.Infrastructure.ExternalServices;

/// <summary>
/// EN: OpenAI API client implementation.
/// VI: Triển khai client cho OpenAI API.
/// </summary>
public class OpenAIClient : IAIClient
{
    private readonly HttpClient _httpClient;
    private readonly ILogger<OpenAIClient> _logger;
    private readonly string _apiKey;

    public OpenAIClient(
        HttpClient httpClient,
        IConfiguration configuration,
        ILogger<OpenAIClient> logger)
    {
        _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));

        _apiKey = configuration["OpenAI:ApiKey"] 
            ?? configuration["OPENAI_API_KEY"]
            ?? throw new InvalidOperationException("OpenAI API Key not configured");

        _httpClient.BaseAddress = new Uri("https://api.openai.com/v1/");
        _httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_apiKey}");
    }

    /// <inheritdoc/>
    public async Task<AICompletionResult> GenerateChatCompletionAsync(
        string systemPrompt,
        IEnumerable<ChatMessage> conversationHistory,
        AICompletionOptions options,
        CancellationToken cancellationToken = default)
    {
        try
        {
            var messages = new List<object>
            {
                new { role = "system", content = systemPrompt }
            };

            messages.AddRange(conversationHistory.Select(m => new
            {
                role = m.Role,
                content = m.Content
            }));

            var payload = new
            {
                model = options.Model,
                messages = messages,
                temperature = options.Temperature,
                max_tokens = options.MaxTokens,
                top_p = options.TopP,
                frequency_penalty = options.FrequencyPenalty,
                presence_penalty = options.PresencePenalty
            };

            var response = await _httpClient.PostAsJsonAsync(
                "chat/completions", payload, cancellationToken);

            var content = await response.Content.ReadAsStringAsync(cancellationToken);

            if (!response.IsSuccessStatusCode)
            {
                _logger.LogWarning("OpenAI API error: {Response}", content);
                return new AICompletionResult(Success: false, Error: content);
            }

            var data = JsonSerializer.Deserialize<JsonElement>(content);
            var choice = data.GetProperty("choices")[0];
            var message = choice.GetProperty("message");
            var usage = data.GetProperty("usage");

            return new AICompletionResult(
                Success: true,
                Content: message.GetProperty("content").GetString(),
                PromptTokens: usage.GetProperty("prompt_tokens").GetInt32(),
                CompletionTokens: usage.GetProperty("completion_tokens").GetInt32(),
                FinishReason: choice.GetProperty("finish_reason").GetString()
            );
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error calling OpenAI API");
            return new AICompletionResult(Success: false, Error: ex.Message);
        }
    }

    /// <inheritdoc/>
    public async Task<bool> IsAvailableAsync(CancellationToken cancellationToken = default)
    {
        try
        {
            var response = await _httpClient.GetAsync("models", cancellationToken);
            return response.IsSuccessStatusCode;
        }
        catch
        {
            return false;
        }
    }
}

/// <summary>
/// EN: Azure OpenAI API client implementation.
/// VI: Triển khai client cho Azure OpenAI API.
/// </summary>
public class AzureOpenAIClient : IAIClient
{
    private readonly HttpClient _httpClient;
    private readonly ILogger<AzureOpenAIClient> _logger;
    private readonly string _deploymentName;
    private readonly string _apiVersion;

    public AzureOpenAIClient(
        HttpClient httpClient,
        IConfiguration configuration,
        ILogger<AzureOpenAIClient> logger)
    {
        _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));

        var endpoint = configuration["AzureOpenAI:Endpoint"] 
            ?? configuration["AZURE_OPENAI_ENDPOINT"]
            ?? throw new InvalidOperationException("Azure OpenAI Endpoint not configured");

        var apiKey = configuration["AzureOpenAI:ApiKey"] 
            ?? configuration["AZURE_OPENAI_KEY"]
            ?? throw new InvalidOperationException("Azure OpenAI API Key not configured");

        _deploymentName = configuration["AzureOpenAI:DeploymentName"] 
            ?? configuration["AZURE_OPENAI_DEPLOYMENT_NAME"]
            ?? "gpt-4";

        _apiVersion = configuration["AzureOpenAI:ApiVersion"] 
            ?? "2024-02-01";

        _httpClient.BaseAddress = new Uri(endpoint.TrimEnd('/') + "/");
        _httpClient.DefaultRequestHeaders.Add("api-key", apiKey);
    }

    /// <inheritdoc/>
    public async Task<AICompletionResult> GenerateChatCompletionAsync(
        string systemPrompt,
        IEnumerable<ChatMessage> conversationHistory,
        AICompletionOptions options,
        CancellationToken cancellationToken = default)
    {
        try
        {
            var messages = new List<object>
            {
                new { role = "system", content = systemPrompt }
            };

            messages.AddRange(conversationHistory.Select(m => new
            {
                role = m.Role,
                content = m.Content
            }));

            var payload = new
            {
                messages = messages,
                temperature = options.Temperature,
                max_tokens = options.MaxTokens,
                top_p = options.TopP,
                frequency_penalty = options.FrequencyPenalty,
                presence_penalty = options.PresencePenalty
            };

            var url = $"openai/deployments/{_deploymentName}/chat/completions?api-version={_apiVersion}";
            var response = await _httpClient.PostAsJsonAsync(url, payload, cancellationToken);
            var content = await response.Content.ReadAsStringAsync(cancellationToken);

            if (!response.IsSuccessStatusCode)
            {
                _logger.LogWarning("Azure OpenAI API error: {Response}", content);
                return new AICompletionResult(Success: false, Error: content);
            }

            var data = JsonSerializer.Deserialize<JsonElement>(content);
            var choice = data.GetProperty("choices")[0];
            var message = choice.GetProperty("message");
            var usage = data.GetProperty("usage");

            return new AICompletionResult(
                Success: true,
                Content: message.GetProperty("content").GetString(),
                PromptTokens: usage.GetProperty("prompt_tokens").GetInt32(),
                CompletionTokens: usage.GetProperty("completion_tokens").GetInt32(),
                FinishReason: choice.GetProperty("finish_reason").GetString()
            );
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error calling Azure OpenAI API");
            return new AICompletionResult(Success: false, Error: ex.Message);
        }
    }

    /// <inheritdoc/>
    public async Task<bool> IsAvailableAsync(CancellationToken cancellationToken = default)
    {
        try
        {
            var url = $"openai/deployments/{_deploymentName}?api-version={_apiVersion}";
            var response = await _httpClient.GetAsync(url, cancellationToken);
            return response.IsSuccessStatusCode;
        }
        catch
        {
            return false;
        }
    }
}
