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

namespace CashLineERP.Domain.IslamicFinance.PartnerLenders;

public sealed class IslamicFinancePartnerLender : Entity
{
    public long Id { get; private set; }
    public long PartnerLenderPartyId { get; private set; }
    public string StatusCode { get; private set; } = IslamicFinanceWorkflowCatalog.Draft;
    public string DefaultCurrencyCode { get; private set; } = string.Empty;
    public bool SupportsMurabaha { get; private set; }
    public bool SupportsReceivablesFinance { get; private set; }
    public bool SupportsTawarruq { get; private set; }
    public bool IsActive { get; private set; }
    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? ActivatedAtUtc { get; private set; }
    public long? ActivatedByUserId { get; private set; }
    [NotMapped]
    public IslamicFinanceLifecycleState LifecycleState => IslamicFinanceWorkflowCatalog.ParseStatusCode(StatusCode);
    [NotMapped]
    public IslamicFinancePartnerLenderFundingProfile FundingProfile => new(
        supportsPartnerFunding: true,
        supportsCashLineFunding: false,
        supportsHybridFunding: false);

    [NotMapped]
    public IReadOnlyList<IslamicFinancePartnerLenderProductSupport> ProductSupports =>
    [
        new IslamicFinancePartnerLenderProductSupport(IslamicFinanceProductType.Murabaha, SupportsMurabaha),
        new IslamicFinancePartnerLenderProductSupport(IslamicFinanceProductType.ReceivablesFinance, SupportsReceivablesFinance),
        new IslamicFinancePartnerLenderProductSupport(IslamicFinanceProductType.Tawarruq, SupportsTawarruq)
    ];

    public IslamicFinancePartnerLender(
        long partnerLenderPartyId,
        string defaultCurrencyCode,
        bool supportsMurabaha,
        bool supportsReceivablesFinance,
        bool supportsTawarruq)
    {
        if (partnerLenderPartyId <= 0)
        {
            throw new InvalidOperationException("Partner lender party must be a valid positive identifier.");
        }

        if (!supportsMurabaha && !supportsReceivablesFinance && !supportsTawarruq)
        {
            throw new InvalidOperationException("Partner lender must support at least one Islamic Finance product.");
        }

        PartnerLenderPartyId = partnerLenderPartyId;
        DefaultCurrencyCode = NormalizeCurrencyCode(defaultCurrencyCode);
        SupportsMurabaha = supportsMurabaha;
        SupportsReceivablesFinance = supportsReceivablesFinance;
        SupportsTawarruq = supportsTawarruq;
    }

    private IslamicFinancePartnerLender()
    {
    }

    public bool SupportsProduct(IslamicFinanceProductType productType) => productType switch
    {
        IslamicFinanceProductType.Murabaha => SupportsMurabaha,
        IslamicFinanceProductType.ReceivablesFinance => SupportsReceivablesFinance,
        IslamicFinanceProductType.Tawarruq => SupportsTawarruq,
        _ => false
    };

    public bool SupportsFundingSource(IslamicFinanceFundingSourceMode fundingSourceMode) =>
        FundingProfile.SupportsMode(fundingSourceMode);

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

        StatusCode = IslamicFinanceWorkflowCatalog.Submitted;
        SubmittedAtUtc = DateTime.UtcNow;
        SubmittedByUserId = actorUserId;
        ApprovedAtUtc = null;
        ApprovedByUserId = null;
        ActivatedAtUtc = null;
        ActivatedByUserId = 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 partner lenders can be approved.");
        }

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

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

    public void Activate(long actorUserId)
    {
        if (!string.Equals(StatusCode, IslamicFinanceWorkflowCatalog.Approved, StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException("Only approved Islamic Finance partner lenders can be activated.");
        }

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

    private static string NormalizeCurrencyCode(string currencyCode)
    {
        var normalized = currencyCode?.Trim().ToUpperInvariant();
        if (string.IsNullOrWhiteSpace(normalized))
        {
            throw new InvalidOperationException("Partner lender default currency code is required.");
        }

        return normalized;
    }
}
