using CashLineERP.Domain.Common;
using CashLineERP.SharedKernel.IslamicFinance;
using System.ComponentModel.DataAnnotations.Schema;

namespace CashLineERP.Domain.IslamicFinance.Settlements;

public sealed class IslamicFinanceSettlementHeader : Entity
{
    public long Id { get; private set; }
    public string SettlementNumber { get; private set; } = string.Empty;
    public long MurabahaCaseId { get; private set; }
    public long FinancingRequestId { get; private set; }
    public long PartnerLenderId { get; private set; }
    public string FundingSourceMode { get; private set; } = IslamicFinanceProductCatalog.ToCode(IslamicFinanceFundingSourceMode.Partner);
    public DateOnly SettlementDate { get; private set; }
    public string SettlementCurrencyCode { get; private set; } = string.Empty;
    public decimal TotalSettledAmount { get; private set; }
    public string StatusCode { get; private set; } = IslamicFinanceWorkflowCatalog.Draft;
    public long? WorkflowInstanceId { 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? ClosedAtUtc { get; private set; }
    public long? ClosedByUserId { get; private set; }

    [NotMapped]
    public IslamicFinanceLifecycleState LifecycleState => IslamicFinanceWorkflowCatalog.ParseStatusCode(StatusCode);

    [NotMapped]
    public IslamicFinanceFundingSourceMode FundingSourceModeValue => IslamicFinanceProductCatalog.ParseFundingSourceMode(FundingSourceMode);

    public IslamicFinanceSettlementHeader(
        string settlementNumber,
        long murabahaCaseId,
        long financingRequestId,
        long partnerLenderId,
        IslamicFinanceFundingSourceMode fundingSourceMode,
        DateOnly settlementDate,
        string settlementCurrencyCode,
        decimal totalSettledAmount)
    {
        if (string.IsNullOrWhiteSpace(settlementNumber))
        {
            throw new InvalidOperationException("Islamic Finance settlement number is required.");
        }

        if (murabahaCaseId <= 0 || financingRequestId <= 0 || partnerLenderId <= 0)
        {
            throw new InvalidOperationException("Islamic Finance settlement requires valid Murabaha case, financing request, and partner-lender identifiers.");
        }

        if (string.IsNullOrWhiteSpace(settlementCurrencyCode))
        {
            throw new InvalidOperationException("Islamic Finance settlement currency code is required.");
        }

        if (totalSettledAmount <= 0m)
        {
            throw new InvalidOperationException("Islamic Finance settlement requires a positive settled amount.");
        }

        if (fundingSourceMode != IslamicFinanceFundingSourceMode.Partner)
        {
            throw new InvalidOperationException("Islamic Finance settlement currently supports partner-funded operation only.");
        }

        SettlementNumber = settlementNumber.Trim().ToUpperInvariant();
        MurabahaCaseId = murabahaCaseId;
        FinancingRequestId = financingRequestId;
        PartnerLenderId = partnerLenderId;
        FundingSourceMode = IslamicFinanceProductCatalog.ToCode(fundingSourceMode);
        SettlementDate = settlementDate;
        SettlementCurrencyCode = settlementCurrencyCode.Trim().ToUpperInvariant();
        TotalSettledAmount = totalSettledAmount;
    }

    private IslamicFinanceSettlementHeader()
    {
    }

    public void Submit(long actorUserId, long? workflowInstanceId = null)
    {
        if (!string.Equals(StatusCode, IslamicFinanceWorkflowCatalog.Draft, StringComparison.OrdinalIgnoreCase)
            && !string.Equals(StatusCode, IslamicFinanceWorkflowCatalog.Returned, StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException("Only draft or returned Islamic Finance settlements can be submitted.");
        }

        if (workflowInstanceId.HasValue && workflowInstanceId.Value <= 0)
        {
            throw new InvalidOperationException("Islamic Finance settlement workflow instance identifier must be positive when provided.");
        }

        StatusCode = IslamicFinanceWorkflowCatalog.Submitted;
        WorkflowInstanceId = workflowInstanceId ?? WorkflowInstanceId;
        SubmittedAtUtc = DateTime.UtcNow;
        SubmittedByUserId = actorUserId;
        ApprovedAtUtc = null;
        ApprovedByUserId = null;
        ClosedAtUtc = null;
        ClosedByUserId = null;
        Touch(actorUserId);
    }

    public void Approve(long actorUserId)
    {
        if (string.Equals(StatusCode, IslamicFinanceWorkflowCatalog.Approved, StringComparison.OrdinalIgnoreCase))
        {
            return;
        }

        if (!string.Equals(StatusCode, IslamicFinanceWorkflowCatalog.Submitted, StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException("Only submitted Islamic Finance settlements can be approved.");
        }

        if (SubmittedByUserId == actorUserId)
        {
            throw new InvalidOperationException("Islamic Finance maker-checker control prohibits self-approval of settlements.");
        }

        StatusCode = IslamicFinanceWorkflowCatalog.Approved;
        ApprovedAtUtc = DateTime.UtcNow;
        ApprovedByUserId = actorUserId;
        Touch(actorUserId);
    }

    public void Close(long actorUserId)
    {
        if (string.Equals(StatusCode, IslamicFinanceWorkflowCatalog.Closed, StringComparison.OrdinalIgnoreCase))
        {
            return;
        }

        if (!string.Equals(StatusCode, IslamicFinanceWorkflowCatalog.Approved, StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException("Only approved Islamic Finance settlements can be closed.");
        }

        StatusCode = IslamicFinanceWorkflowCatalog.Closed;
        ClosedAtUtc = DateTime.UtcNow;
        ClosedByUserId = actorUserId;
        Touch(actorUserId);
    }
}
