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

namespace CashLineERP.Infrastructure.Persistence.Repositories.IslamicFinance;

public sealed class IslamicFinanceProductRepository : IIslamicFinanceProductRepository
{
    private readonly CashLineErpDbContext _dbContext;

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

    public IReadOnlyCollection<IslamicFinanceProductProfileDetailView> GetProductProfiles(bool activeOnly = false, string? productType = null)
    {
        var normalizedProductType = string.IsNullOrWhiteSpace(productType)
            ? null
            : IslamicFinanceProductCatalog.NormalizeProductType(productType);

        return _dbContext.IslamicFinanceProductProfiles
            .AsNoTracking()
            .Where(entry => !activeOnly || entry.IsActive)
            .Where(entry => normalizedProductType == null || entry.ProductType == normalizedProductType)
            .OrderBy(entry => entry.ProductCode)
            .Select(Map)
            .ToArray();
    }

    public IslamicFinanceProductProfileDetailView? GetProductProfile(long productProfileId)
    {
        var entry = _dbContext.IslamicFinanceProductProfiles
            .AsNoTracking()
            .SingleOrDefault(profile => profile.Id == productProfileId);

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

    public IslamicFinanceProductProfileDetailView Create(CreateIslamicFinanceProductProfileCommand command)
    {
        var normalizedProductType = IslamicFinanceProductCatalog.NormalizeProductType(command.ProductType);
        var normalizedProductCode = command.ProductCode.Trim().ToUpperInvariant();

        var duplicateExists = _dbContext.IslamicFinanceProductProfiles
            .AsNoTracking()
            .Any(entry => entry.ProductCode == normalizedProductCode);
        if (duplicateExists)
        {
            throw new InvalidOperationException("Islamic Finance product profile code already exists.");
        }

        var entry = new IslamicFinanceProductProfile(
            IslamicFinanceProductCatalog.ParseProductType(normalizedProductType),
            normalizedProductCode,
            command.ProductName,
            command.RequiresShariahReview,
            command.AllowsPartnerFunding,
            command.AllowsCashLineFunding);

        _dbContext.IslamicFinanceProductProfiles.Add(entry);
        _dbContext.SaveChanges();
        return GetProductProfile(entry.Id)!;
    }

    public IslamicFinanceProductProfileDetailView Submit(long productProfileId, long actorUserId)
    {
        var entry = _dbContext.IslamicFinanceProductProfiles.Single(profile => profile.Id == productProfileId);
        entry.Submit(actorUserId);
        _dbContext.SaveChanges();
        return GetProductProfile(entry.Id)!;
    }

    public IslamicFinanceProductProfileDetailView Approve(long productProfileId, long actorUserId)
    {
        var entry = _dbContext.IslamicFinanceProductProfiles.Single(profile => profile.Id == productProfileId);
        entry.Approve(actorUserId);
        _dbContext.SaveChanges();
        return GetProductProfile(entry.Id)!;
    }

    public IslamicFinanceProductProfileDetailView Activate(long productProfileId, long actorUserId)
    {
        var entry = _dbContext.IslamicFinanceProductProfiles.Single(profile => profile.Id == productProfileId);
        entry.Activate(actorUserId);
        _dbContext.SaveChanges();
        return GetProductProfile(entry.Id)!;
    }

    private static IslamicFinanceProductProfileDetailView Map(IslamicFinanceProductProfile entry) =>
        new(
            entry.Id,
            entry.ProductType,
            entry.ProductCode,
            entry.ProductName,
            IslamicFinanceWorkflowCatalog.NormalizeStatusCode(entry.StatusCode),
            entry.IsActive,
            entry.RequiresShariahReview,
            entry.AllowsPartnerFunding,
            entry.AllowsCashLineFunding,
            entry.SubmittedAtUtc,
            entry.SubmittedByUserId,
            entry.ApprovedAtUtc,
            entry.ApprovedByUserId,
            entry.ActivatedAtUtc,
            entry.ActivatedByUserId);
}
