"use strict";
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 __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
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;
    };
})();
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
var InvitationService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.InvitationService = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("@nestjs/typeorm");
const typeorm_2 = require("typeorm");
const config_1 = require("@nestjs/config");
const crypto = __importStar(require("crypto"));
const invitation_entity_1 = require("../entities/invitation.entity");
const user_entity_1 = require("../../auth/entities/user.entity");
const tenant_entity_1 = require("../../tenants/entities/tenant.entity");
const email_service_1 = require("../../email/services/email.service");
let InvitationService = InvitationService_1 = class InvitationService {
    constructor(invitationRepository, userRepository, tenantRepository, emailService, configService) {
        this.invitationRepository = invitationRepository;
        this.userRepository = userRepository;
        this.tenantRepository = tenantRepository;
        this.emailService = emailService;
        this.configService = configService;
        this.logger = new common_1.Logger(InvitationService_1.name);
        this.invitationExpirationDays = 7;
    }
    async invite(dto, inviterId, tenantId) {
        const email = dto.email.toLowerCase().trim();
        const existingUser = await this.userRepository.findOne({
            where: { email, tenant_id: tenantId },
        });
        if (existingUser) {
            throw new common_1.ConflictException('Este email ya está registrado en la organización');
        }
        const existingInvitation = await this.invitationRepository.findOne({
            where: {
                email,
                tenant_id: tenantId,
                status: 'pending',
            },
        });
        if (existingInvitation) {
            throw new common_1.ConflictException('Ya existe una invitación pendiente para este email');
        }
        const [inviter, tenant] = await Promise.all([
            this.userRepository.findOne({ where: { id: inviterId } }),
            this.tenantRepository.findOne({ where: { id: tenantId } }),
        ]);
        if (!inviter) {
            throw new common_1.NotFoundException('Usuario invitador no encontrado');
        }
        if (!tenant) {
            throw new common_1.NotFoundException('Organización no encontrada');
        }
        const token = this.generateSecureToken();
        const expiresAt = new Date();
        expiresAt.setDate(expiresAt.getDate() + this.invitationExpirationDays);
        const invitation = this.invitationRepository.create({
            tenant_id: tenantId,
            email,
            token,
            status: 'pending',
            expires_at: expiresAt,
            created_by: inviterId,
            message: dto.message || null,
            metadata: { role: dto.role },
        });
        await this.invitationRepository.save(invitation);
        await this.sendInvitationEmail(invitation, inviter, tenant, dto.role);
        this.logger.log(`Invitation sent to ${email} for tenant ${tenant.name}`);
        return this.toResponseDto(invitation, dto.role);
    }
    async findAllByTenant(tenantId) {
        await this.expireOldInvitations(tenantId);
        const invitations = await this.invitationRepository.find({
            where: { tenant_id: tenantId },
            order: { created_at: 'DESC' },
        });
        return invitations.map((inv) => this.toResponseDto(inv, inv.metadata?.role || 'member'));
    }
    async resend(token, inviterId, tenantId) {
        const invitation = await this.invitationRepository.findOne({
            where: { token, tenant_id: tenantId },
        });
        if (!invitation) {
            throw new common_1.NotFoundException('Invitación no encontrada');
        }
        if (invitation.status !== 'pending') {
            throw new common_1.BadRequestException('Solo se pueden reenviar invitaciones pendientes');
        }
        const [inviter, tenant] = await Promise.all([
            this.userRepository.findOne({ where: { id: inviterId } }),
            this.tenantRepository.findOne({ where: { id: tenantId } }),
        ]);
        if (!inviter || !tenant) {
            throw new common_1.NotFoundException('Usuario o organización no encontrada');
        }
        const newToken = this.generateSecureToken();
        const expiresAt = new Date();
        expiresAt.setDate(expiresAt.getDate() + this.invitationExpirationDays);
        invitation.token = newToken;
        invitation.expires_at = expiresAt;
        await this.invitationRepository.save(invitation);
        const role = invitation.metadata?.role || 'member';
        await this.sendInvitationEmail(invitation, inviter, tenant, role);
        this.logger.log(`Invitation resent to ${invitation.email}`);
        return this.toResponseDto(invitation, role);
    }
    async cancel(id, tenantId) {
        const invitation = await this.invitationRepository.findOne({
            where: { id, tenant_id: tenantId },
        });
        if (!invitation) {
            throw new common_1.NotFoundException('Invitación no encontrada');
        }
        if (invitation.status !== 'pending') {
            throw new common_1.BadRequestException('Solo se pueden cancelar invitaciones pendientes');
        }
        await this.invitationRepository.remove(invitation);
        this.logger.log(`Invitation ${id} cancelled for ${invitation.email}`);
    }
    async findByToken(token) {
        const invitation = await this.invitationRepository.findOne({
            where: { token },
        });
        if (!invitation) {
            return null;
        }
        if (invitation.expires_at < new Date() && invitation.status === 'pending') {
            invitation.status = 'expired';
            await this.invitationRepository.save(invitation);
        }
        return invitation;
    }
    generateSecureToken() {
        return crypto.randomBytes(32).toString('hex');
    }
    async sendInvitationEmail(invitation, inviter, tenant, role) {
        const appUrl = this.configService.get('APP_URL', 'http://localhost:3000');
        const inviteUrl = `${appUrl}/invite/${invitation.token}`;
        const expiresIn = `${this.invitationExpirationDays} días`;
        await this.emailService.sendTemplateEmail({
            to: { email: invitation.email },
            templateKey: 'invitation',
            variables: {
                inviterName: inviter.fullName || inviter.email,
                tenantName: tenant.name,
                role: this.translateRole(role),
                inviteLink: inviteUrl,
                expiresIn,
                appName: this.configService.get('APP_NAME', 'Template SaaS'),
            },
        });
    }
    async expireOldInvitations(tenantId) {
        await this.invitationRepository
            .createQueryBuilder()
            .update(invitation_entity_1.Invitation)
            .set({ status: 'expired' })
            .where('tenant_id = :tenantId', { tenantId })
            .andWhere('status = :status', { status: 'pending' })
            .andWhere('expires_at < NOW()')
            .execute();
    }
    translateRole(role) {
        const translations = {
            admin: 'Administrador',
            member: 'Miembro',
            viewer: 'Visor',
        };
        return translations[role] || role;
    }
    toResponseDto(invitation, role) {
        return {
            id: invitation.id,
            email: invitation.email,
            role,
            status: invitation.status,
            expires_at: invitation.expires_at,
            created_at: invitation.created_at,
        };
    }
};
exports.InvitationService = InvitationService;
exports.InvitationService = InvitationService = InvitationService_1 = __decorate([
    (0, common_1.Injectable)(),
    __param(0, (0, typeorm_1.InjectRepository)(invitation_entity_1.Invitation)),
    __param(1, (0, typeorm_1.InjectRepository)(user_entity_1.User)),
    __param(2, (0, typeorm_1.InjectRepository)(tenant_entity_1.Tenant)),
    __metadata("design:paramtypes", [typeorm_2.Repository,
        typeorm_2.Repository,
        typeorm_2.Repository,
        email_service_1.EmailService,
        config_1.ConfigService])
], InvitationService);
//# sourceMappingURL=invitation.service.js.map