using System.Net.Http.Json;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace RealCV.Infrastructure.Clients;

public sealed class FcaRegisterClient
{
    private readonly HttpClient _httpClient;
    private readonly ILogger<FcaRegisterClient> _logger;
    private readonly string _apiKey;

    public FcaRegisterClient(
        HttpClient httpClient,
        IOptions<FcaOptions> options,
        ILogger<FcaRegisterClient> logger)
    {
        _httpClient = httpClient;
        _logger = logger;
        _apiKey = options.Value.ApiKey;

        _httpClient.BaseAddress = new Uri("https://register.fca.org.uk/services/V0.1/");
        _httpClient.DefaultRequestHeaders.Add("X-Auth-Email", options.Value.Email);
        _httpClient.DefaultRequestHeaders.Add("X-Auth-Key", _apiKey);
    }

    public async Task<FcaIndividualResponse?> SearchIndividualsAsync(string name, int page = 1)
    {
        try
        {
            var encodedName = Uri.EscapeDataString(name);
            var url = $"Individuals?q={encodedName}&page={page}";

            _logger.LogDebug("Searching FCA for individual: {Name}", name);

            var response = await _httpClient.GetAsync(url);

            if (!response.IsSuccessStatusCode)
            {
                _logger.LogWarning("FCA API returned {StatusCode} for search: {Name}",
                    response.StatusCode, name);
                return null;
            }

            return await response.Content.ReadFromJsonAsync<FcaIndividualResponse>(JsonOptions);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error searching FCA for individual: {Name}", name);
            return null;
        }
    }

    public async Task<FcaIndividualDetails?> GetIndividualAsync(string individualReferenceNumber)
    {
        try
        {
            var url = $"Individuals/{individualReferenceNumber}";

            _logger.LogDebug("Getting FCA individual: {IRN}", individualReferenceNumber);

            var response = await _httpClient.GetAsync(url);

            if (!response.IsSuccessStatusCode)
            {
                _logger.LogWarning("FCA API returned {StatusCode} for IRN: {IRN}",
                    response.StatusCode, individualReferenceNumber);
                return null;
            }

            var wrapper = await response.Content.ReadFromJsonAsync<FcaIndividualDetailsWrapper>(JsonOptions);
            return wrapper?.Data?.FirstOrDefault();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error getting FCA individual: {IRN}", individualReferenceNumber);
            return null;
        }
    }

    public async Task<FcaFirmResponse?> SearchFirmsAsync(string name, int page = 1)
    {
        try
        {
            var encodedName = Uri.EscapeDataString(name);
            var url = $"Firms?q={encodedName}&page={page}";

            var response = await _httpClient.GetAsync(url);

            if (!response.IsSuccessStatusCode)
            {
                return null;
            }

            return await response.Content.ReadFromJsonAsync<FcaFirmResponse>(JsonOptions);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error searching FCA for firm: {Name}", name);
            return null;
        }
    }

    private static readonly JsonSerializerOptions JsonOptions = new()
    {
        PropertyNameCaseInsensitive = true,
        DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
    };
}

public class FcaOptions
{
    public string ApiKey { get; set; } = string.Empty;
    public string Email { get; set; } = string.Empty;
}

// Response models
public class FcaIndividualResponse
{
    public List<FcaIndividualSearchItem>? Data { get; set; }
    public FcaPagination? Pagination { get; set; }
}

public class FcaIndividualSearchItem
{
    [JsonPropertyName("Individual Reference Number")]
    public string? IndividualReferenceNumber { get; set; }

    public string? Name { get; set; }
    public string? Status { get; set; }

    [JsonPropertyName("Current Employer(s)")]
    public string? CurrentEmployers { get; set; }
}

public class FcaIndividualDetailsWrapper
{
    public List<FcaIndividualDetails>? Data { get; set; }
}

public class FcaIndividualDetails
{
    [JsonPropertyName("Individual Reference Number")]
    public string? IndividualReferenceNumber { get; set; }

    public string? Name { get; set; }
    public string? Status { get; set; }

    [JsonPropertyName("Effective Date")]
    public string? EffectiveDate { get; set; }

    [JsonPropertyName("Controlled Functions")]
    public List<FcaControlledFunction>? ControlledFunctions { get; set; }

    [JsonPropertyName("Previous Employments")]
    public List<FcaPreviousEmployment>? PreviousEmployments { get; set; }
}

public class FcaControlledFunction
{
    [JsonPropertyName("Controlled Function")]
    public string? ControlledFunction { get; set; }

    [JsonPropertyName("Firm Name")]
    public string? FirmName { get; set; }

    [JsonPropertyName("Firm Reference Number")]
    public string? FirmReferenceNumber { get; set; }

    [JsonPropertyName("Status")]
    public string? Status { get; set; }

    [JsonPropertyName("Effective From")]
    public string? EffectiveFrom { get; set; }
}

public class FcaPreviousEmployment
{
    [JsonPropertyName("Firm Name")]
    public string? FirmName { get; set; }

    [JsonPropertyName("Firm Reference Number")]
    public string? FirmReferenceNumber { get; set; }

    [JsonPropertyName("Start Date")]
    public string? StartDate { get; set; }

    [JsonPropertyName("End Date")]
    public string? EndDate { get; set; }
}

public class FcaFirmResponse
{
    public List<FcaFirmSearchItem>? Data { get; set; }
    public FcaPagination? Pagination { get; set; }
}

public class FcaFirmSearchItem
{
    [JsonPropertyName("Firm Reference Number")]
    public string? FirmReferenceNumber { get; set; }

    [JsonPropertyName("Firm Name")]
    public string? FirmName { get; set; }

    public string? Status { get; set; }
}

public class FcaPagination
{
    public int Page { get; set; }
    public int TotalPages { get; set; }
    public int TotalItems { get; set; }
}
