using System.Transactions;
using SIGCM2.Application.Abstractions;
using SIGCM2.Application.Abstractions.Persistence;
using SIGCM2.Application.Audit;

namespace SIGCM2.Application.Pricing.ChargeableChars.SchedulePrice;

/// <summary>
/// PRC-001 — Handler for SchedulePriceChangeCommand.
/// Flow: load existing → validate forward-only via entity → open TX → InsertWithCloseAsync → audit → tx.Complete().
/// </summary>
public sealed class SchedulePriceChangeCommandHandler
    : ICommandHandler<SchedulePriceChangeCommand, SchedulePriceChangeResponse>
{
    private readonly IChargeableCharConfigRepository _repo;
    private readonly IAuditLogger _audit;
    private readonly TimeProvider _timeProvider;

    public SchedulePriceChangeCommandHandler(
        IChargeableCharConfigRepository repo,
        IAuditLogger audit,
        TimeProvider timeProvider)
    {
        _repo = repo;
        _audit = audit;
        _timeProvider = timeProvider;
    }

    public async Task<SchedulePriceChangeResponse> Handle(SchedulePriceChangeCommand command)
    {
        // 1. Load existing row — validates it exists and exposes ProductTypeId/Symbol/Category.
        var existing = await _repo.GetByIdAsync(command.Id)
            ?? throw new KeyNotFoundException($"ChargeableCharConfig con Id={command.Id} no existe.");

        // 2. Domain entity validates forward-only rule and builds the new entity value.
        //    ScheduleNewPrice throws ChargeableCharConfigForwardOnlyException if not strictly forward.
        var newEntity = existing.ScheduleNewPrice(command.PricePerUnit, command.ValidFrom, _timeProvider);

        // 3. TX + SP + audit (fail-closed).
        long newId;
        using (var tx = new TransactionScope(
            TransactionScopeOption.Required,
            new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted },
            TransactionScopeAsyncFlowOption.Enabled))
        {
            newId = await _repo.InsertWithCloseAsync(
                newEntity.ProductTypeId,
                newEntity.Symbol,
                newEntity.Category,
                newEntity.PricePerUnit,
                newEntity.ValidFrom);

            await _audit.LogAsync(
                action: "tasacion.chargeable_char.price_change",
                targetType: "ChargeableCharConfig",
                targetId: newId.ToString(),
                metadata: new
                {
                    before = new
                    {
                        id = existing.Id,
                        pricePerUnit = existing.PricePerUnit,
                        validFrom = existing.ValidFrom.ToString("yyyy-MM-dd"),
                    },
                    after = new
                    {
                        pricePerUnit = newEntity.PricePerUnit,
                        validFrom = newEntity.ValidFrom.ToString("yyyy-MM-dd"),
                    }
                });

            tx.Complete();
        }

        return new SchedulePriceChangeResponse(
            NewId: newId,
            PreviousValidFrom: existing.ValidFrom,
            NewValidFrom: newEntity.ValidFrom);
    }
}
