using CashLineERP.Domain.Common;
using CashLineERP.SharedKernel.Workflow;

namespace CashLineERP.Domain.Integration;

public sealed class IntegrationEndpointRegistryEntry : Entity
{
    public long Id { get; private set; }
    public string EndpointCode { get; private set; } = string.Empty;
    public string EndpointName { get; private set; } = string.Empty;
    public string IntegrationProviderCode { get; private set; } = string.Empty;
    public string EnvironmentCode { get; private set; } = string.Empty;
    public string DirectionCode { get; private set; } = string.Empty;
    public string TransportCode { get; private set; } = string.Empty;
    public string HttpMethodCode { get; private set; } = string.Empty;
    public string BaseUrl { get; private set; } = string.Empty;
    public string? RelativePath { get; private set; }
    public string AuthenticationModeCode { get; private set; } = string.Empty;
    public string? CredentialReference { get; private set; }
    public int TimeoutSeconds { get; private set; }
    public string RetryPolicyCode { get; private set; } = string.Empty;
    public int MaxRetryCount { get; private set; }
    public bool IsIdempotencyKeyRequired { get; private set; }
    public long StatusId { get; private set; } = WorkflowStatusSeedIds.Draft;
    public bool IsActive { get; private set; }
    public string? Notes { get; private set; }
    public DateTime? SubmittedAtUtc { get; private set; }
    public long? SubmittedByUserId { get; private set; }
    public DateTime? ApprovedAtUtc { get; private set; }
    public long? ApprovedByUserId { get; private set; }
    public DateTime? ActivatedAtUtc { get; private set; }
    public long? ActivatedByUserId { get; private set; }

    public IntegrationEndpointRegistryEntry(
        string endpointCode,
        string endpointName,
        string integrationProviderCode,
        string environmentCode,
        string directionCode,
        string transportCode,
        string httpMethodCode,
        string baseUrl,
        string? relativePath,
        string authenticationModeCode,
        string? credentialReference,
        int timeoutSeconds,
        string retryPolicyCode,
        int maxRetryCount,
        bool isIdempotencyKeyRequired,
        string? notes)
    {
        if (string.IsNullOrWhiteSpace(endpointCode))
        {
            throw new InvalidOperationException("Integration endpoint code is required.");
        }

        if (string.IsNullOrWhiteSpace(endpointName))
        {
            throw new InvalidOperationException("Integration endpoint name is required.");
        }

        if (!Uri.TryCreate(baseUrl, UriKind.Absolute, out _))
        {
            throw new InvalidOperationException("Integration endpoint base URL must be an absolute URI.");
        }

        if (timeoutSeconds <= 0)
        {
            throw new InvalidOperationException("Integration endpoint timeout must be greater than zero seconds.");
        }

        if (maxRetryCount < 0)
        {
            throw new InvalidOperationException("Integration endpoint retry count cannot be negative.");
        }

        EndpointCode = endpointCode;
        EndpointName = endpointName;
        IntegrationProviderCode = integrationProviderCode;
        EnvironmentCode = environmentCode;
        DirectionCode = directionCode;
        TransportCode = transportCode;
        HttpMethodCode = httpMethodCode;
        BaseUrl = baseUrl;
        RelativePath = string.IsNullOrWhiteSpace(relativePath) ? null : relativePath;
        AuthenticationModeCode = authenticationModeCode;
        CredentialReference = string.IsNullOrWhiteSpace(credentialReference) ? null : credentialReference;
        TimeoutSeconds = timeoutSeconds;
        RetryPolicyCode = retryPolicyCode;
        MaxRetryCount = maxRetryCount;
        IsIdempotencyKeyRequired = isIdempotencyKeyRequired;
        Notes = string.IsNullOrWhiteSpace(notes) ? null : notes.Trim();
    }

    private IntegrationEndpointRegistryEntry()
    {
    }

    public void Submit(long actorUserId)
    {
        if (StatusId != WorkflowStatusSeedIds.Draft && StatusId != WorkflowStatusSeedIds.Returned)
        {
            throw new InvalidOperationException("Only draft or returned integration endpoints can be submitted.");
        }

        StatusId = WorkflowStatusSeedIds.Submitted;
        SubmittedAtUtc = DateTime.UtcNow;
        SubmittedByUserId = actorUserId;
        ApprovedAtUtc = null;
        ApprovedByUserId = null;
        Touch(actorUserId);
    }

    public void Approve(long actorUserId)
    {
        if (StatusId == WorkflowStatusSeedIds.Approved)
        {
            return;
        }

        if (StatusId != WorkflowStatusSeedIds.Submitted)
        {
            throw new InvalidOperationException("Only submitted integration endpoints can be approved.");
        }

        if (SubmittedByUserId == actorUserId)
        {
            throw new InvalidOperationException("Integration endpoint maker-checker control prohibits self-approval.");
        }

        StatusId = WorkflowStatusSeedIds.Approved;
        ApprovedAtUtc = DateTime.UtcNow;
        ApprovedByUserId = actorUserId;
        Touch(actorUserId);
    }

    public void Activate(long actorUserId)
    {
        if (StatusId != WorkflowStatusSeedIds.Approved)
        {
            throw new InvalidOperationException("Only approved integration endpoints can be activated.");
        }

        IsActive = true;
        ActivatedAtUtc = DateTime.UtcNow;
        ActivatedByUserId = actorUserId;
        Touch(actorUserId);
    }
}
