using ColaFlow.Modules.Identity.Domain.Aggregates.Users;
using ColaFlow.Modules.Identity.Domain.Aggregates.Tenants;
using ColaFlow.Modules.Identity.Domain.Repositories;
using MediatR;

namespace ColaFlow.Modules.Identity.Application.Commands.AssignUserRole;

public class AssignUserRoleCommandHandler(
    IUserTenantRoleRepository userTenantRoleRepository,
    IUserRepository userRepository,
    ITenantRepository tenantRepository)
    : IRequestHandler<AssignUserRoleCommand, Unit>
{
    public async Task<Unit> Handle(AssignUserRoleCommand request, CancellationToken cancellationToken)
    {
        // Validate user exists
        var user = await userRepository.GetByIdAsync(request.UserId, cancellationToken);
        if (user == null)
            throw new InvalidOperationException("User not found");

        // Validate tenant exists
        var tenant = await tenantRepository.GetByIdAsync(TenantId.Create(request.TenantId), cancellationToken);
        if (tenant == null)
            throw new InvalidOperationException("Tenant not found");

        // Parse and validate role
        if (!Enum.TryParse<TenantRole>(request.Role, out var role))
            throw new ArgumentException($"Invalid role: {request.Role}");

        // Prevent manual assignment of AIAgent role
        if (role == TenantRole.AIAgent)
            throw new InvalidOperationException("AIAgent role cannot be assigned manually");

        // Check if user already has a role in this tenant
        var existingRole = await userTenantRoleRepository.GetByUserAndTenantAsync(
            request.UserId,
            request.TenantId,
            cancellationToken);

        if (existingRole != null)
        {
            // Update existing role
            existingRole.UpdateRole(role, Guid.Empty); // OperatorUserId can be set from HttpContext in controller
            await userTenantRoleRepository.UpdateAsync(existingRole, cancellationToken);
        }
        else
        {
            // Create new role assignment
            var userTenantRole = UserTenantRole.Create(
                UserId.Create(request.UserId),
                TenantId.Create(request.TenantId),
                role,
                null); // AssignedByUserId can be set from HttpContext in controller

            await userTenantRoleRepository.AddAsync(userTenantRole, cancellationToken);
        }

        return Unit.Value;
    }
}
