using CashLineERP.Contracts.Finance;

namespace CashLineERP.Application.Finance;

public sealed class WalletRuleService : IWalletRuleService
{
    private readonly IWalletRuleRepository _repository;

    public WalletRuleService(IWalletRuleRepository repository)
    {
        _repository = repository;
    }

    public IReadOnlyCollection<WalletRuleResponse> GetWalletRules(bool activeOnly = false, string? integrationProviderCode = null, string? transactionTypeCode = null) =>
        _repository.GetWalletRules(activeOnly, integrationProviderCode, transactionTypeCode)
            .Select(Map)
            .ToArray();

    public WalletRuleResponse? GetWalletRule(long walletRuleId)
    {
        var rule = _repository.GetWalletRule(walletRuleId);
        return rule is null ? null : Map(rule);
    }

    public WalletRuleResponse CreateWalletRule(CreateWalletRuleRequest request) =>
        Map(_repository.Create(new CreateWalletRuleCommand(
            request.RuleName,
            request.BranchId,
            request.PartyTypeCode,
            request.TransactionTypeCode,
            request.WalletSchemeCode,
            request.IntegrationProviderCode,
            request.CurrencyCode,
            request.MinimumAmount,
            request.MaximumAmount,
            request.SettlementLeadDays,
            request.FeePercent,
            request.FlatFeeAmount,
            request.Priority,
            request.EffectiveFromDate,
            request.EffectiveToDate,
            request.Notes)));

    public WalletRuleResponse SubmitWalletRule(long walletRuleId, long actorUserId) =>
        Map(_repository.Submit(walletRuleId, actorUserId));

    public WalletRuleResponse ApproveWalletRule(long walletRuleId, long actorUserId) =>
        Map(_repository.Approve(walletRuleId, actorUserId));

    public WalletRuleResponse ActivateWalletRule(long walletRuleId, long actorUserId) =>
        Map(_repository.Activate(walletRuleId, actorUserId));

    public WalletRuleEvaluationResponse EvaluateWalletRule(WalletRuleEvaluationRequest request) =>
        Map(_repository.Evaluate(new WalletRuleEvaluationCommand(
            request.BranchId,
            request.PartyTypeCode,
            request.TransactionTypeCode,
            request.WalletSchemeCode,
            request.CurrencyCode,
            request.RequestedAmount,
            request.EvaluationDate)));

    private static WalletRuleResponse Map(WalletRuleDetailView rule) =>
        new(
            rule.WalletRuleId,
            rule.RuleCode,
            rule.RuleName,
            rule.BranchId,
            rule.PartyTypeCode,
            rule.TransactionTypeCode,
            rule.WalletSchemeCode,
            rule.IntegrationProviderCode,
            rule.CurrencyCode,
            rule.MinimumAmount,
            rule.MaximumAmount,
            rule.SettlementLeadDays,
            rule.FeePercent,
            rule.FlatFeeAmount,
            rule.Priority,
            rule.EffectiveFromDate,
            rule.EffectiveToDate,
            rule.StatusCode,
            rule.IsActive,
            rule.Notes,
            rule.SubmittedAtUtc,
            rule.SubmittedByUserId,
            rule.ApprovedAtUtc,
            rule.ApprovedByUserId,
            rule.ActivatedAtUtc,
            rule.ActivatedByUserId);

    private static WalletRuleEvaluationResponse Map(WalletRuleEvaluationView evaluation) =>
        new(
            evaluation.BranchId,
            evaluation.PartyTypeCode,
            evaluation.TransactionTypeCode,
            evaluation.WalletSchemeCode,
            evaluation.CurrencyCode,
            evaluation.RequestedAmount,
            evaluation.EvaluationDate,
            evaluation.RecommendedWalletRuleId,
            evaluation.RecommendedRuleCode,
            evaluation.RecommendedIntegrationProviderCode,
            evaluation.Lines.Select(line => new WalletRuleEvaluationLineResponse(
                line.WalletRuleId,
                line.RuleCode,
                line.RuleName,
                line.BranchId,
                line.PartyTypeCode,
                line.TransactionTypeCode,
                line.WalletSchemeCode,
                line.IntegrationProviderCode,
                line.CurrencyCode,
                line.MinimumAmount,
                line.MaximumAmount,
                line.RequestedAmount,
                line.EstimatedFeeAmount,
                line.EstimatedSettlementAmount,
                line.SettlementLeadDays,
                line.Priority,
                line.RecommendationStatusCode,
                line.Notes)).ToArray());
}
