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

namespace SIGCM2.Application.Roles.Create;

public sealed class CreateRolCommandHandler : ICommandHandler<CreateRolCommand, RolCreatedDto>
{
    private readonly IRolRepository _repository;
    private readonly IAuditLogger _audit;

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

    public async Task<RolCreatedDto> Handle(CreateRolCommand command)
    {
        // Check-then-insert: explicit check produces a clear 409 message.
        // SqlException 2627 (UQ violation) acts as race-condition fallback — caught in ExceptionFilter.
        var existing = await _repository.GetByCodigoAsync(command.Codigo);
        if (existing is not null)
            throw new RolAlreadyExistsException(command.Codigo);

        var rol = Rol.ForCreation(command.Codigo, command.Nombre, command.Descripcion);

        int newId;
        using (var tx = new TransactionScope(
            TransactionScopeOption.Required,
            new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted },
            TransactionScopeAsyncFlowOption.Enabled))
        {
            newId = await _repository.AddAsync(rol);

            await _audit.LogAsync(
                action: "rol.create",
                targetType: "Rol",
                targetId: newId.ToString(),
                metadata: new { after = new { rol.Codigo, rol.Nombre, rol.Descripcion } });

            tx.Complete();
        }

        return new RolCreatedDto(
            Id: newId,
            Codigo: rol.Codigo,
            Nombre: rol.Nombre,
            Descripcion: rol.Descripcion,
            Activo: rol.Activo);
    }
}
