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

namespace CashLineERP.Domain.IslamicFinance.Shariah;

public sealed class IslamicFinanceShariahReviewCase : Entity
{
    public long Id { get; private set; }
    public string ReviewCaseNumber { get; private set; } = string.Empty;
    public long ProductProfileId { get; private set; }
    public long? FinancingRequestId { get; private set; }
    public string ReviewReasonCode { get; private set; } = string.Empty;
    public string? ReviewOutcomeCode { get; private set; }
    public string? ReviewNotes { 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? ReviewedAtUtc { get; private set; }
    public long? ReviewedByUserId { get; private set; }
    public DateTime? ApprovedAtUtc { get; private set; }
    public long? ApprovedByUserId { get; private set; }
    [NotMapped]
    public IslamicFinanceGovernanceReasonCode ReviewReason => IslamicFinanceGovernanceCatalog.ParseReasonCode(ReviewReasonCode);
    [NotMapped]
    public IslamicFinanceLifecycleState LifecycleState => IslamicFinanceWorkflowCatalog.ParseStatusCode(StatusCode);
    [NotMapped]
    public IslamicFinanceShariahOutcomeCode? ReviewOutcome => string.IsNullOrWhiteSpace(ReviewOutcomeCode)
        ? null
        : IslamicFinanceShariahOutcomeCatalog.ParseOutcomeCode(ReviewOutcomeCode);
    [NotMapped]
    public IslamicFinanceShariahReviewRequirement Requirement => new(ProductProfileId, FinancingRequestId, ReviewReason);
    [NotMapped]
    public IslamicFinanceShariahReviewRecommendation? Recommendation => ReviewOutcome is null || !ReviewedAtUtc.HasValue || !ReviewedByUserId.HasValue
        ? null
        : new IslamicFinanceShariahReviewRecommendation(
            ReviewOutcome.Value,
            ReviewNotes,
            ReviewedAtUtc.Value,
            ReviewedByUserId.Value);

    public IslamicFinanceShariahReviewCase(
        string reviewCaseNumber,
        long productProfileId,
        long? financingRequestId,
        IslamicFinanceGovernanceReasonCode reviewReason)
    {
        if (string.IsNullOrWhiteSpace(reviewCaseNumber))
        {
            throw new InvalidOperationException("Islamic Finance Shariah review case number is required.");
        }

        ReviewCaseNumber = reviewCaseNumber.Trim().ToUpperInvariant();
        ProductProfileId = productProfileId;
        FinancingRequestId = financingRequestId;
        ReviewReasonCode = IslamicFinanceGovernanceCatalog.ToCode(reviewReason);

        _ = Requirement;
    }

    private IslamicFinanceShariahReviewCase()
    {
    }

    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 Shariah review cases can be submitted.");
        }

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

    public void RecommendOutcome(IslamicFinanceShariahOutcomeCode outcome, string? notes, long reviewerUserId)
    {
        if (!string.Equals(StatusCode, IslamicFinanceWorkflowCatalog.Submitted, StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException("Only submitted Islamic Finance Shariah review cases can record a recommendation.");
        }

        if (reviewerUserId <= 0)
        {
            throw new InvalidOperationException("Islamic Finance Shariah review recommendation requires a valid reviewer identifier.");
        }

        ReviewOutcomeCode = IslamicFinanceShariahOutcomeCatalog.ToCode(outcome);
        ReviewNotes = string.IsNullOrWhiteSpace(notes) ? null : notes.Trim();
        ReviewedAtUtc = DateTime.UtcNow;
        ReviewedByUserId = reviewerUserId;
        Touch(reviewerUserId);
    }

    public void ApproveOutcome(long actorUserId)
    {
        if (!string.Equals(StatusCode, IslamicFinanceWorkflowCatalog.Submitted, StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException("Only submitted Islamic Finance Shariah review cases can approve an outcome.");
        }

        if (!ReviewedByUserId.HasValue || !ReviewedAtUtc.HasValue || string.IsNullOrWhiteSpace(ReviewOutcomeCode))
        {
            throw new InvalidOperationException("Islamic Finance Shariah review outcome must be recommended before approval.");
        }

        if (ReviewedByUserId == actorUserId)
        {
            throw new InvalidOperationException("Islamic Finance Shariah review maker-checker control prohibits self-approval of the review outcome.");
        }

        var outcome = IslamicFinanceShariahOutcomeCatalog.ParseOutcomeCode(ReviewOutcomeCode);
        StatusCode = outcome switch
        {
            IslamicFinanceShariahOutcomeCode.Approved => IslamicFinanceWorkflowCatalog.Approved,
            IslamicFinanceShariahOutcomeCode.Rejected => IslamicFinanceWorkflowCatalog.Rejected,
            IslamicFinanceShariahOutcomeCode.Returned => IslamicFinanceWorkflowCatalog.Returned,
            _ => throw new InvalidOperationException("Islamic Finance Shariah review outcome is not supported for approval.")
        };

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