using CashLineERP.Application.Documents;
using CashLineERP.Application.IslamicFinance.Murabaha;
using CashLineERP.SharedKernel.Documents;
using CashLineERP.SharedKernel.IslamicFinance;
using Microsoft.EntityFrameworkCore;

namespace CashLineERP.Infrastructure.Persistence.Repositories.IslamicFinance;

public sealed class IslamicFinanceMurabahaContractRepository : IIslamicFinanceMurabahaContractRepository
{
    private readonly CashLineErpDbContext _dbContext;
    private readonly IDocumentStorageRepository _documentStorageRepository;

    public IslamicFinanceMurabahaContractRepository(
        CashLineErpDbContext dbContext,
        IDocumentStorageRepository documentStorageRepository)
    {
        _dbContext = dbContext;
        _documentStorageRepository = documentStorageRepository;
    }

    public IReadOnlyCollection<DocumentAttachmentDetailView> GetContracts(long murabahaCaseId)
    {
        EnsureCaseExists(murabahaCaseId);

        return _documentStorageRepository.GetDocuments(
            IslamicFinanceDocumentCatalog.ModuleCode,
            IslamicFinanceDocumentCatalog.MurabahaCaseEntityName,
            murabahaCaseId,
            attachmentCategoryCode: IslamicFinanceDocumentCatalog.GeneratedContractAttachmentCategoryCode);
    }

    public DocumentAttachmentDetailView? GetContract(long murabahaCaseId, long documentLinkId)
    {
        EnsureCaseExists(murabahaCaseId);
        var document = _documentStorageRepository.GetDocument(documentLinkId);
        if (document is null)
        {
            return null;
        }

        return IsMurabahaContract(document, murabahaCaseId) ? document : null;
    }

    public DocumentAttachmentDetailView GenerateContract(long murabahaCaseId, long actorUserId, GenerateIslamicFinanceMurabahaContractCommand command)
    {
        var murabahaCase = _dbContext.IslamicFinanceMurabahaCases
            .AsNoTracking()
            .SingleOrDefault(entry => entry.Id == murabahaCaseId);

        if (murabahaCase is null)
        {
            throw new InvalidOperationException("Islamic Finance Murabaha contract generation requires a valid Murabaha case.");
        }

        if (!string.Equals(murabahaCase.StatusCode, IslamicFinanceWorkflowCatalog.Approved, StringComparison.OrdinalIgnoreCase)
            && !string.Equals(murabahaCase.StatusCode, IslamicFinanceWorkflowCatalog.Active, StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException("Islamic Finance Murabaha contract generation requires an approved or active Murabaha case.");
        }

        if (!murabahaCase.ContractTemplateId.HasValue)
        {
            throw new InvalidOperationException("Islamic Finance Murabaha contract generation requires an assigned contract template.");
        }

        var template = _dbContext.IslamicFinanceContractTemplates
            .AsNoTracking()
            .SingleOrDefault(entry => entry.Id == murabahaCase.ContractTemplateId.Value);

        if (template is null)
        {
            throw new InvalidOperationException("Islamic Finance Murabaha contract generation requires a valid contract template.");
        }

        if (!template.IsActive
            || !string.Equals(template.StatusCode, IslamicFinanceWorkflowCatalog.Active, StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException("Islamic Finance Murabaha contract generation requires an active contract template.");
        }

        if (template.ProductProfileId != murabahaCase.ProductProfileId)
        {
            throw new InvalidOperationException("Islamic Finance Murabaha contract generation requires a contract template that matches the Murabaha product profile.");
        }

        var allContracts = _documentStorageRepository.GetDocuments(
            IslamicFinanceDocumentCatalog.ModuleCode,
            IslamicFinanceDocumentCatalog.MurabahaCaseEntityName,
            murabahaCaseId,
            attachmentCategoryCode: IslamicFinanceDocumentCatalog.GeneratedContractAttachmentCategoryCode);

        var latestVersion = allContracts.Any()
            ? allContracts.Max(entry => entry.VersionNumber)
            : 0;
        var nextVersion = latestVersion + 1;

        var fileName = $"{murabahaCase.CaseNumber}-{template.TemplateCode}-{template.LanguageCode}-contract-v{nextVersion}.txt";
        var storageReference = $"generated/islamic-finance/murabaha-contracts/{murabahaCase.Id}/{template.TemplateCode.ToLowerInvariant()}-{template.LanguageCode.ToLowerInvariant()}/v{nextVersion}.txt";
        var checksumText = $"case:{murabahaCase.Id};template:{template.Id};version:{nextVersion}";

        var activeContract = allContracts.FirstOrDefault(entry =>
            string.Equals(entry.LifecycleStatusCode, DocumentLifecycleStatusCode.Active, StringComparison.OrdinalIgnoreCase));

        if (activeContract is not null)
        {
            return _documentStorageRepository.SupersedeDocument(activeContract.DocumentLinkId, actorUserId, new SupersedeDocumentAttachmentCommand(
                fileName,
                storageReference,
                IslamicFinanceDocumentCatalog.GeneratedStorageProviderCode,
                "text/plain",
                null,
                checksumText,
                null,
                string.IsNullOrWhiteSpace(command.ReasonText)
                    ? "Murabaha contract regenerated from the active governed template baseline."
                    : command.ReasonText.Trim()));
        }

        return _documentStorageRepository.CreateDocument(actorUserId, new CreateDocumentAttachmentCommand(
            IslamicFinanceDocumentCatalog.ModuleCode,
            IslamicFinanceDocumentCatalog.MurabahaCaseEntityName,
            murabahaCaseId,
            IslamicFinanceDocumentCatalog.MurabahaContractDocumentType,
            IslamicFinanceDocumentCatalog.GeneratedContractAttachmentCategoryCode,
            fileName,
            storageReference,
            IslamicFinanceDocumentCatalog.GeneratedStorageProviderCode,
            "text/plain",
            null,
            checksumText,
            null));
    }

    private void EnsureCaseExists(long murabahaCaseId)
    {
        if (!_dbContext.IslamicFinanceMurabahaCases.AsNoTracking().Any(entry => entry.Id == murabahaCaseId))
        {
            throw new InvalidOperationException("Islamic Finance Murabaha contract read requires a valid Murabaha case.");
        }
    }

    private static bool IsMurabahaContract(DocumentAttachmentDetailView document, long murabahaCaseId) =>
        string.Equals(document.ModuleCode, IslamicFinanceDocumentCatalog.ModuleCode, StringComparison.OrdinalIgnoreCase)
        && string.Equals(document.EntityName, IslamicFinanceDocumentCatalog.MurabahaCaseEntityName, StringComparison.OrdinalIgnoreCase)
        && string.Equals(document.DocumentType, IslamicFinanceDocumentCatalog.MurabahaContractDocumentType, StringComparison.OrdinalIgnoreCase)
        && document.EntityId == murabahaCaseId;
}
