"use strict";
/**
 * UsersService - Gestión de usuarios
 *
 * CRUD de usuarios con soporte multi-tenant y RBAC.
 *
 * @module Users
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.UsersService = void 0;
const typeorm_1 = require("typeorm");
const bcrypt = __importStar(require("bcryptjs"));
class UsersService {
    userRepository;
    roleRepository;
    userRoleRepository;
    constructor(userRepository, roleRepository, userRoleRepository) {
        this.userRepository = userRepository;
        this.roleRepository = roleRepository;
        this.userRoleRepository = userRoleRepository;
    }
    /**
     * Listar usuarios de un tenant
     */
    async findAll(options) {
        const { tenantId, page = 1, limit = 20, search, isActive } = options;
        const query = this.userRepository
            .createQueryBuilder('user')
            .leftJoinAndSelect('user.tenant', 'tenant')
            .where('user.tenant_id = :tenantId', { tenantId })
            .andWhere('user.deleted_at IS NULL');
        if (search) {
            query.andWhere('(user.email ILIKE :search OR user.first_name ILIKE :search OR user.last_name ILIKE :search)', { search: `%${search}%` });
        }
        if (isActive !== undefined) {
            query.andWhere('user.is_active = :isActive', { isActive });
        }
        const total = await query.getCount();
        const users = await query
            .skip((page - 1) * limit)
            .take(limit)
            .orderBy('user.created_at', 'DESC')
            .getMany();
        return { users, total };
    }
    /**
     * Obtener usuario por ID
     */
    async findById(id, tenantId) {
        return this.userRepository.findOne({
            where: { id, tenantId, deletedAt: (0, typeorm_1.IsNull)() },
            relations: ['tenant'],
        });
    }
    /**
     * Obtener usuario por email
     */
    async findByEmail(email, tenantId) {
        return this.userRepository.findOne({
            where: { email, tenantId, deletedAt: (0, typeorm_1.IsNull)() },
        });
    }
    /**
     * Crear usuario
     */
    async create(dto, createdBy) {
        // Verificar email único en tenant
        const existing = await this.findByEmail(dto.email, dto.tenantId);
        if (existing) {
            throw new Error('Email already exists in this tenant');
        }
        const passwordHash = await bcrypt.hash(dto.password, 12);
        const user = await this.userRepository.save(this.userRepository.create({
            email: dto.email,
            passwordHash,
            firstName: dto.firstName,
            lastName: dto.lastName,
            tenantId: dto.tenantId,
            defaultTenantId: dto.tenantId,
            isActive: true,
            roles: dto.roles || ['viewer'],
        }));
        // Asignar roles si se especificaron
        if (dto.roles && dto.roles.length > 0) {
            for (const roleCode of dto.roles) {
                await this.assignRole({ userId: user.id, roleCode, tenantId: dto.tenantId }, createdBy);
            }
        }
        return user;
    }
    /**
     * Actualizar usuario
     */
    async update(id, tenantId, dto) {
        const user = await this.findById(id, tenantId);
        if (!user) {
            throw new Error('User not found');
        }
        await this.userRepository.update(id, {
            ...dto,
            updatedAt: new Date(),
        });
        return this.findById(id, tenantId);
    }
    /**
     * Soft delete de usuario
     */
    async delete(id, tenantId, _deletedBy) {
        const user = await this.findById(id, tenantId);
        if (!user) {
            throw new Error('User not found');
        }
        await this.userRepository.update(id, {
            deletedAt: new Date(),
            isActive: false,
        });
    }
    /**
     * Activar/Desactivar usuario
     */
    async setActive(id, tenantId, isActive) {
        const user = await this.findById(id, tenantId);
        if (!user) {
            throw new Error('User not found');
        }
        await this.userRepository.update(id, { isActive });
        return this.findById(id, tenantId);
    }
    /**
     * Asignar rol a usuario
     */
    async assignRole(dto, assignedBy) {
        const role = await this.roleRepository.findOne({
            where: { code: dto.roleCode, isActive: true },
        });
        if (!role) {
            throw new Error('Role not found');
        }
        // Verificar si ya tiene el rol
        const existing = await this.userRoleRepository.findOne({
            where: { userId: dto.userId, roleId: role.id, tenantId: dto.tenantId },
        });
        if (existing) {
            return existing;
        }
        return this.userRoleRepository.save(this.userRoleRepository.create({
            userId: dto.userId,
            roleId: role.id,
            tenantId: dto.tenantId,
            assignedBy,
        }));
    }
    /**
     * Remover rol de usuario
     */
    async removeRole(userId, roleCode, tenantId) {
        const role = await this.roleRepository.findOne({
            where: { code: roleCode },
        });
        if (!role) {
            throw new Error('Role not found');
        }
        await this.userRoleRepository.delete({
            userId,
            roleId: role.id,
            tenantId,
        });
    }
    /**
     * Obtener roles de usuario
     */
    async getUserRoles(userId, tenantId) {
        const userRoles = await this.userRoleRepository.find({
            where: { userId, tenantId },
            relations: ['role'],
        });
        return userRoles.map((ur) => ur.role);
    }
    /**
     * Listar todos los roles disponibles
     */
    async listRoles() {
        return this.roleRepository.find({
            where: { isActive: true },
            order: { name: 'ASC' },
        });
    }
}
exports.UsersService = UsersService;
//# sourceMappingURL=users.service.js.map