using Microsoft.Extensions.Logging;
using RealCV.Application.Interfaces;
using RealCV.Application.Models;
using RealCV.Infrastructure.Clients;

namespace RealCV.Infrastructure.Services;

public sealed class ProfessionalVerifierService : IProfessionalVerifierService
{
    private readonly FcaRegisterClient _fcaClient;
    private readonly ILogger<ProfessionalVerifierService> _logger;

    public ProfessionalVerifierService(
        FcaRegisterClient fcaClient,
        ILogger<ProfessionalVerifierService> logger)
    {
        _fcaClient = fcaClient;
        _logger = logger;
    }

    public async Task<ProfessionalVerificationResult> VerifyFcaRegistrationAsync(
        string name,
        string? firmName = null,
        string? referenceNumber = null)
    {
        try
        {
            _logger.LogInformation("Verifying FCA registration for: {Name}", name);

            // If we have a reference number, try to get directly
            if (!string.IsNullOrEmpty(referenceNumber))
            {
                var details = await _fcaClient.GetIndividualAsync(referenceNumber);
                if (details != null)
                {
                    var isNameMatch = IsNameMatch(name, details.Name);
                    return new ProfessionalVerificationResult
                    {
                        ClaimedName = name,
                        ProfessionalBody = "FCA",
                        IsVerified = isNameMatch,
                        RegistrationNumber = details.IndividualReferenceNumber,
                        MatchedName = details.Name,
                        Status = details.Status,
                        RegistrationDate = ParseDate(details.EffectiveDate),
                        ControlledFunctions = details.ControlledFunctions?
                            .Where(cf => cf.Status?.Equals("Active", StringComparison.OrdinalIgnoreCase) == true)
                            .Select(cf => cf.ControlledFunction ?? "Unknown")
                            .ToList(),
                        VerificationNotes = isNameMatch
                            ? $"FCA Individual Reference Number: {details.IndividualReferenceNumber}"
                            : "Reference number found but name does not match"
                    };
                }
            }

            // Search by name
            var searchResponse = await _fcaClient.SearchIndividualsAsync(name);

            if (searchResponse?.Data == null || searchResponse.Data.Count == 0)
            {
                return new ProfessionalVerificationResult
                {
                    ClaimedName = name,
                    ProfessionalBody = "FCA",
                    IsVerified = false,
                    VerificationNotes = "No matching FCA registered individuals found"
                };
            }

            // Find best match
            var matches = searchResponse.Data
                .Where(i => IsNameMatch(name, i.Name))
                .ToList();

            if (matches.Count == 0)
            {
                return new ProfessionalVerificationResult
                {
                    ClaimedName = name,
                    ProfessionalBody = "FCA",
                    IsVerified = false,
                    VerificationNotes = $"Found {searchResponse.Data.Count} results but no close name matches"
                };
            }

            // If firm specified, try to match on that too
            FcaIndividualSearchItem? bestMatch = null;
            if (!string.IsNullOrEmpty(firmName))
            {
                bestMatch = matches.FirstOrDefault(m =>
                    m.CurrentEmployers?.Contains(firmName, StringComparison.OrdinalIgnoreCase) == true);
            }

            bestMatch ??= matches.First();

            // Get detailed information
            if (!string.IsNullOrEmpty(bestMatch.IndividualReferenceNumber))
            {
                var details = await _fcaClient.GetIndividualAsync(bestMatch.IndividualReferenceNumber);
                if (details != null)
                {
                    return new ProfessionalVerificationResult
                    {
                        ClaimedName = name,
                        ProfessionalBody = "FCA",
                        IsVerified = true,
                        RegistrationNumber = details.IndividualReferenceNumber,
                        MatchedName = details.Name,
                        Status = details.Status,
                        RegistrationDate = ParseDate(details.EffectiveDate),
                        CurrentEmployer = bestMatch.CurrentEmployers,
                        ControlledFunctions = details.ControlledFunctions?
                            .Where(cf => cf.Status?.Equals("Active", StringComparison.OrdinalIgnoreCase) == true)
                            .Select(cf => cf.ControlledFunction ?? "Unknown")
                            .ToList(),
                        VerificationNotes = $"FCA Individual Reference Number: {details.IndividualReferenceNumber}"
                    };
                }
            }

            // Basic verification without details
            return new ProfessionalVerificationResult
            {
                ClaimedName = name,
                ProfessionalBody = "FCA",
                IsVerified = true,
                RegistrationNumber = bestMatch.IndividualReferenceNumber,
                MatchedName = bestMatch.Name,
                Status = bestMatch.Status,
                CurrentEmployer = bestMatch.CurrentEmployers,
                VerificationNotes = "Verified via FCA Register search"
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error verifying FCA registration for: {Name}", name);
            return new ProfessionalVerificationResult
            {
                ClaimedName = name,
                ProfessionalBody = "FCA",
                IsVerified = false,
                VerificationNotes = $"Error during verification: {ex.Message}"
            };
        }
    }

    public async Task<List<FcaIndividualSearchResult>> SearchFcaIndividualsAsync(string name)
    {
        try
        {
            var searchResponse = await _fcaClient.SearchIndividualsAsync(name);

            if (searchResponse?.Data == null)
            {
                return [];
            }

            return searchResponse.Data
                .Select(i => new FcaIndividualSearchResult
                {
                    Name = i.Name ?? "Unknown",
                    IndividualReferenceNumber = i.IndividualReferenceNumber ?? "Unknown",
                    Status = i.Status,
                    CurrentFirms = i.CurrentEmployers?.Split(',')
                        .Select(f => f.Trim())
                        .Where(f => !string.IsNullOrEmpty(f))
                        .ToList()
                })
                .ToList();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error searching FCA for: {Name}", name);
            return [];
        }
    }

    private static bool IsNameMatch(string searchName, string? foundName)
    {
        if (string.IsNullOrEmpty(foundName))
            return false;

        var searchNormalized = NormalizeName(searchName);
        var foundNormalized = NormalizeName(foundName);

        // Exact match
        if (searchNormalized.Equals(foundNormalized, StringComparison.OrdinalIgnoreCase))
            return true;

        // Check if all parts of search name are in found name
        var searchParts = searchNormalized.Split(' ', StringSplitOptions.RemoveEmptyEntries);
        var foundParts = foundNormalized.Split(' ', StringSplitOptions.RemoveEmptyEntries);

        // All search parts must be found
        return searchParts.All(sp =>
            foundParts.Any(fp => fp.Equals(sp, StringComparison.OrdinalIgnoreCase)));
    }

    private static string NormalizeName(string name)
    {
        return name
            .Replace(",", " ")
            .Replace(".", " ")
            .Replace("-", " ")
            .Trim();
    }

    private static DateOnly? ParseDate(string? dateString)
    {
        if (string.IsNullOrEmpty(dateString))
            return null;

        if (DateOnly.TryParse(dateString, out var date))
            return date;

        return null;
    }
}
