using System.Text.Json;
using CashLineERP.Contracts.Tax;

namespace CashLineERP.Application.Tax;

public sealed class EtaAuthorityIntegrationService : IEtaAuthorityIntegrationService
{
    private readonly IEtaComplianceService _etaComplianceService;
    private readonly IEtaAuthorityAuthService _etaAuthorityAuthService;
    private readonly IEtaAuthorityClient _etaAuthorityClient;

    public EtaAuthorityIntegrationService(
        IEtaComplianceService etaComplianceService,
        IEtaAuthorityAuthService etaAuthorityAuthService,
        IEtaAuthorityClient etaAuthorityClient)
    {
        _etaComplianceService = etaComplianceService;
        _etaAuthorityAuthService = etaAuthorityAuthService;
        _etaAuthorityClient = etaAuthorityClient;
    }

    public EtaAuthorityAuthHealthResponse GetAuthHealth() =>
        _etaAuthorityAuthService.GetHealth();

    public async Task<EtaAuthoritySubmissionStatusResponse> GetAuthoritySubmissionStatusAsync(
        long accountsReceivableInvoiceId,
        long etaSubmissionLogId,
        CancellationToken cancellationToken = default)
    {
        var submission = _etaComplianceService
            .GetSubmissionLogs(accountsReceivableInvoiceId)
            .SingleOrDefault(entry => entry.EtaSubmissionLogId == etaSubmissionLogId);

        if (submission is null)
        {
            throw new InvalidOperationException("ETA submission log was not found for the requested invoice.");
        }

        var submissionReference = submission.SubmissionReference ?? $"ETA-SUB-{etaSubmissionLogId:D6}";
        var authoritySubmissionUuid = TryExtractAuthoritySubmissionUuid(submission.ResponseText)
            ?? submission.EtaUuid;
        if (string.IsNullOrWhiteSpace(authoritySubmissionUuid))
        {
            return new EtaAuthoritySubmissionStatusResponse(
                accountsReceivableInvoiceId,
                etaSubmissionLogId,
                submissionReference,
                "NOT_LINKED",
                "NOT_LINKED",
                "The ETA submission log does not yet carry an authority submission UUID.",
                null,
                null,
                null,
                null,
                null,
                []);
        }

        var statusEndpoint = _etaAuthorityAuthService.GetSubmissionStatusEndpoint();
        if (statusEndpoint is null)
        {
            return new EtaAuthoritySubmissionStatusResponse(
                accountsReceivableInvoiceId,
                etaSubmissionLogId,
                submissionReference,
                "ENDPOINT_NOT_CONFIGURED",
                "ENDPOINT_NOT_CONFIGURED",
                "ETA submission-status endpoint is not configured.",
                authoritySubmissionUuid,
                null,
                null,
                null,
                null,
                []);
        }

        EtaAuthoritySubmissionStatus authorityStatus;
        try
        {
            var accessToken = await _etaAuthorityAuthService.AcquireAccessTokenAsync(cancellationToken);
            authorityStatus = await _etaAuthorityClient.GetSubmissionStatusAsync(
                statusEndpoint,
                accessToken,
                authoritySubmissionUuid,
                cancellationToken);
        }
        catch (Exception ex) when (ex is InvalidOperationException or HttpRequestException or TaskCanceledException)
        {
            return new EtaAuthoritySubmissionStatusResponse(
                accountsReceivableInvoiceId,
                etaSubmissionLogId,
                submissionReference,
                "LINKED",
                "AUTHORITY_CONNECTIVITY_FAILED",
                $"ETA authority status retrieval failed: {ex.Message}",
                authoritySubmissionUuid,
                null,
                null,
                null,
                ex.Message,
                []);
        }

        return new EtaAuthoritySubmissionStatusResponse(
            accountsReceivableInvoiceId,
            etaSubmissionLogId,
            submissionReference,
            "LINKED",
            authorityStatus.OverallStatus ?? "UNKNOWN",
            "ETA authority submission status retrieved successfully.",
            authorityStatus.SubmissionUuid,
            authorityStatus.OverallStatus,
            authorityStatus.DateTimeReceivedUtc,
            authorityStatus.AuthorityErrorCode,
            authorityStatus.AuthorityErrorMessage,
            authorityStatus.Documents.Select(document => new EtaAuthoritySubmissionDocumentSummaryResponse(
                document.Uuid,
                document.InternalId,
                document.TypeName,
                document.ReceiverId,
                document.ReceiverName,
                document.Total,
                document.Status,
                document.ErrorCode,
                document.ErrorMessage)).ToArray());
    }

    public EtaAuthorityPingResponse VerifyPing(string? suppliedSecret, string? echoText)
    {
        var configuredEndpoint = _etaAuthorityAuthService.GetCallbackPingEndpoint();
        if (configuredEndpoint is null)
        {
            return new EtaAuthorityPingResponse(
                false,
                "ENDPOINT_NOT_CONFIGURED",
                "ETA callback ping endpoint is not configured in the integration registry.",
                echoText,
                DateTime.UtcNow);
        }

        var expectedSecret = _etaAuthorityAuthService.ResolveCallbackPingSharedSecret();
        if (string.IsNullOrWhiteSpace(expectedSecret))
        {
            return new EtaAuthorityPingResponse(
                false,
                "SECRET_NOT_RESOLVED",
                "ETA callback ping shared secret is not resolvable by the current runtime.",
                echoText,
                DateTime.UtcNow);
        }

        var normalizedSuppliedSecret = NormalizeAuthorizationSecret(suppliedSecret);
        if (!string.Equals(expectedSecret, normalizedSuppliedSecret, StringComparison.Ordinal))
        {
            return new EtaAuthorityPingResponse(
                false,
                "PING_VERIFICATION_FAILED",
                "ETA callback ping secret did not match the configured endpoint secret.",
                echoText,
                DateTime.UtcNow);
        }

        return new EtaAuthorityPingResponse(
            true,
            "VERIFIED",
            $"ETA callback ping verified against endpoint {configuredEndpoint.EndpointCode}.",
            echoText,
            DateTime.UtcNow);
    }

    private static string? TryExtractAuthoritySubmissionUuid(string? responseText)
    {
        if (string.IsNullOrWhiteSpace(responseText))
        {
            return null;
        }

        try
        {
            using var document = JsonDocument.Parse(responseText);
            return ReadString(document.RootElement, "authoritySubmissionUuid")
                ?? ReadString(document.RootElement, "submissionUUID")
                ?? ReadString(document.RootElement, "submissionUuid")
                ?? ReadString(document.RootElement, "submissionId")
                ?? ReadString(document.RootElement, "uuid");
        }
        catch (JsonException)
        {
            return null;
        }
    }

    private static string? ReadString(JsonElement element, string propertyName) =>
        element.TryGetProperty(propertyName, out var property)
            ? property.GetString()
            : null;

    private static string? NormalizeAuthorizationSecret(string? suppliedSecret)
    {
        if (string.IsNullOrWhiteSpace(suppliedSecret))
        {
            return null;
        }

        var normalized = suppliedSecret.Trim();
        const string prefix = "ApiKey ";
        return normalized.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)
            ? normalized[prefix.Length..].Trim()
            : normalized;
    }
}
