using CashLineERP.Application.IslamicFinance.ContractTemplates;
using CashLineERP.Domain.IslamicFinance.ContractTemplates;
using CashLineERP.SharedKernel.IslamicFinance;
using Microsoft.EntityFrameworkCore;

namespace CashLineERP.Infrastructure.Persistence.Repositories.IslamicFinance;

public sealed class IslamicFinanceContractTemplateRepository : IIslamicFinanceContractTemplateRepository
{
    private readonly CashLineErpDbContext _dbContext;

    public IslamicFinanceContractTemplateRepository(CashLineErpDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public IReadOnlyCollection<IslamicFinanceContractTemplateDetailView> GetContractTemplates(
        bool activeOnly = false,
        long? productProfileId = null,
        string? languageCode = null)
    {
        var normalizedLanguageCode = string.IsNullOrWhiteSpace(languageCode)
            ? null
            : languageCode.Trim().ToUpperInvariant();

        return _dbContext.IslamicFinanceContractTemplates
            .AsNoTracking()
            .Where(entry => !activeOnly || entry.IsActive)
            .Where(entry => !productProfileId.HasValue || entry.ProductProfileId == productProfileId.Value)
            .Where(entry => normalizedLanguageCode == null || entry.LanguageCode == normalizedLanguageCode)
            .OrderBy(entry => entry.TemplateCode)
            .Select(Map)
            .ToArray();
    }

    public IslamicFinanceContractTemplateDetailView? GetContractTemplate(long contractTemplateId)
    {
        var entry = _dbContext.IslamicFinanceContractTemplates
            .AsNoTracking()
            .SingleOrDefault(template => template.Id == contractTemplateId);

        return entry is null ? null : Map(entry);
    }

    public IslamicFinanceContractTemplateDetailView Create(CreateIslamicFinanceContractTemplateCommand command)
    {
        if (!_dbContext.IslamicFinanceProductProfiles.Any(entry => entry.Id == command.ProductProfileId))
        {
            throw new InvalidOperationException("Islamic Finance contract template requires a valid product profile.");
        }

        var normalizedTemplateCode = command.TemplateCode.Trim().ToUpperInvariant();
        if (_dbContext.IslamicFinanceContractTemplates.AsNoTracking().Any(entry => entry.TemplateCode == normalizedTemplateCode))
        {
            throw new InvalidOperationException("Islamic Finance contract template code already exists.");
        }

        var entry = new IslamicFinanceContractTemplate(
            command.ProductProfileId,
            normalizedTemplateCode,
            command.TemplateName,
            command.LanguageCode);

        _dbContext.IslamicFinanceContractTemplates.Add(entry);
        _dbContext.SaveChanges();
        return GetContractTemplate(entry.Id)!;
    }

    public IslamicFinanceContractTemplateDetailView Submit(long contractTemplateId, long actorUserId)
    {
        var entry = _dbContext.IslamicFinanceContractTemplates.Single(template => template.Id == contractTemplateId);
        entry.Submit(actorUserId);
        _dbContext.SaveChanges();
        return GetContractTemplate(entry.Id)!;
    }

    public IslamicFinanceContractTemplateDetailView Approve(long contractTemplateId, long actorUserId)
    {
        var entry = _dbContext.IslamicFinanceContractTemplates.Single(template => template.Id == contractTemplateId);
        entry.Approve(actorUserId);
        _dbContext.SaveChanges();
        return GetContractTemplate(entry.Id)!;
    }

    public IslamicFinanceContractTemplateDetailView Activate(long contractTemplateId, long actorUserId)
    {
        var entry = _dbContext.IslamicFinanceContractTemplates.Single(template => template.Id == contractTemplateId);
        entry.Activate(actorUserId);
        _dbContext.SaveChanges();
        return GetContractTemplate(entry.Id)!;
    }

    private static IslamicFinanceContractTemplateDetailView Map(IslamicFinanceContractTemplate entry) =>
        new(
            entry.Id,
            entry.ProductProfileId,
            entry.TemplateCode,
            entry.TemplateName,
            entry.LanguageCode,
            IslamicFinanceWorkflowCatalog.NormalizeStatusCode(entry.StatusCode),
            entry.IsActive,
            entry.SubmittedAtUtc,
            entry.SubmittedByUserId,
            entry.ApprovedAtUtc,
            entry.ApprovedByUserId,
            entry.ActivatedAtUtc,
            entry.ActivatedByUserId);
}
