using System.Transactions;
using SIGCM2.Application.Abstractions;
using SIGCM2.Application.Abstractions.Persistence;
using SIGCM2.Application.Audit;
using SIGCM2.Application.Roles.Dtos;
using SIGCM2.Domain.Exceptions;

namespace SIGCM2.Application.Roles.Update;

public sealed class UpdateRolCommandHandler : ICommandHandler<UpdateRolCommand, RolDto>
{
    private readonly IRolRepository _repository;
    private readonly IAuditLogger _audit;

    public UpdateRolCommandHandler(IRolRepository repository, IAuditLogger audit)
    {
        _repository = repository;
        _audit = audit;
    }

    public async Task<RolDto> Handle(UpdateRolCommand command)
    {
        var before = await _repository.GetByCodigoAsync(command.Codigo)
            ?? throw new RolNotFoundException(command.Codigo);

        using (var tx = new TransactionScope(
            TransactionScopeOption.Required,
            new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted },
            TransactionScopeAsyncFlowOption.Enabled))
        {
            var updated = await _repository.UpdateAsync(
                command.Codigo, command.Nombre, command.Descripcion, command.Activo);

            if (!updated)
                throw new RolNotFoundException(command.Codigo);

            await _audit.LogAsync(
                action: "rol.update",
                targetType: "Rol",
                targetId: before.Id.ToString(),
                metadata: new
                {
                    before = new { before.Nombre, before.Descripcion, before.Activo },
                    after = new { command.Nombre, command.Descripcion, command.Activo },
                });

            tx.Complete();
        }

        var rol = await _repository.GetByCodigoAsync(command.Codigo)
            ?? throw new RolNotFoundException(command.Codigo);

        return new RolDto(rol.Id, rol.Codigo, rol.Nombre, rol.Descripcion, rol.Activo, rol.FechaCreacion, rol.FechaModificacion);
    }
}
