"use strict";
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 __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); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TenantService = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("@nestjs/typeorm");
const typeorm_2 = require("typeorm");
const tenant_entity_1 = require("../entities/tenant.entity");
const event_emitter_1 = require("@nestjs/event-emitter");
const tenant_created_event_1 = require("../events/tenant-created.event");
const tenant_updated_event_1 = require("../events/tenant-updated.event");
const tenant_deleted_event_1 = require("../events/tenant-deleted.event");
const auth_constants_1 = require("../../auth.constants");
const auth_config_service_1 = require("../../core/services/auth-config.service");
const debug_logger_service_1 = require("../../core/services/debug-logger.service");
const slug_util_1 = require("../../utils/slug.util");
let TenantService = class TenantService {
    tenantRepository;
    eventEmitter;
    authConfig;
    debugLogger;
    defaultTenant = null;
    constructor(tenantRepository, eventEmitter, authConfig, debugLogger) {
        this.tenantRepository = tenantRepository;
        this.eventEmitter = eventEmitter;
        this.authConfig = authConfig;
        this.debugLogger = debugLogger;
    }
    async createTenant(data) {
        const identifier = data.slug;
        this.debugLogger.logTenantOperation('createTenant', undefined, { slug: data.slug, name: data.name });
        if (!data.slug || !(0, slug_util_1.isValidSlug)(data.slug)) {
            throw new common_1.BadRequestException({
                message: `Invalid slug format. Slug must be lowercase with only letters, numbers, hyphens (-) and underscores (_). Got: '${data.slug}'`,
                code: 'INVALID_SLUG_FORMAT'
            });
        }
        this.debugLogger.debug('Checking for existing tenant', 'TenantService', { slug: data.slug });
        const existingTenant = await this.getTenantBySlug(data.slug);
        if (existingTenant) {
            this.debugLogger.warn('Tenant already exists', 'TenantService', { identifier, existingTenantId: existingTenant.id });
            throw new common_1.ConflictException({
                message: `Tenant with slug '${identifier}' already exists`,
                code: 'TENANT_ALREADY_EXISTS'
            });
        }
        const tenant = this.tenantRepository.create(data);
        await this.tenantRepository.save(tenant);
        await this.eventEmitter.emitAsync(auth_constants_1.NestAuthEvents.TENANT_CREATED, new tenant_created_event_1.TenantCreatedEvent({
            tenant
        }));
        return tenant;
    }
    async getTenantById(id, options) {
        if (!id) {
            return null;
        }
        const tenant = await this.tenantRepository.findOne({
            ...(options ? options : {}),
            where: { id }
        });
        if (!tenant) {
            return null;
        }
        return tenant;
    }
    async getTenantBySlug(slug, options) {
        if (!slug) {
            return null;
        }
        const tenant = await this.tenantRepository.findOne({
            ...(options ? options : {}),
            where: { slug }
        });
        return tenant;
    }
    async getTenants(options) {
        return this.tenantRepository.find(options);
    }
    async updateTenant(id, data) {
        const tenant = await this.getTenantById(id);
        if (!tenant) {
            throw new common_1.NotFoundException({
                message: `Tenant with ID ${id} not found`,
                code: 'TENANT_NOT_FOUND'
            });
        }
        if (data.slug && !(0, slug_util_1.isValidSlug)(data.slug)) {
            throw new common_1.BadRequestException({
                message: `Invalid slug format. Slug must be lowercase with only letters, numbers, hyphens (-) and underscores (_). Got: '${data.slug}'`,
                code: 'INVALID_SLUG_FORMAT'
            });
        }
        if (data.slug && data.slug !== tenant.slug) {
            const existingTenant = await this.getTenantBySlug(data.slug);
            if (existingTenant && existingTenant.id !== tenant.id) {
                throw new common_1.ConflictException({
                    message: `Tenant with slug '${data.slug}' already exists`,
                    code: 'TENANT_ALREADY_EXISTS'
                });
            }
        }
        Object.assign(tenant, data);
        const updatedTenant = await this.tenantRepository.save(tenant);
        await this.eventEmitter.emitAsync(auth_constants_1.NestAuthEvents.TENANT_UPDATED, new tenant_updated_event_1.TenantUpdatedEvent({
            tenant: updatedTenant,
            updatedFields: Object.keys(data)
        }));
        return updatedTenant;
    }
    async deleteTenant(id) {
        const tenant = await this.getTenantById(id);
        if (!tenant) {
            throw new common_1.NotFoundException({
                message: `Tenant with ID ${id} not found`,
                code: 'TENANT_NOT_FOUND'
            });
        }
        await this.eventEmitter.emitAsync(auth_constants_1.NestAuthEvents.TENANT_DELETED, new tenant_deleted_event_1.TenantDeletedEvent({
            tenant
        }));
        await this.tenantRepository.remove(tenant);
    }
    async updateTenantStatus(id, isActive) {
        const tenant = await this.getTenantById(id);
        if (!tenant) {
            throw new common_1.NotFoundException({
                message: `Tenant with ID ${id} not found`,
                code: 'TENANT_NOT_FOUND'
            });
        }
        tenant.isActive = isActive;
        const updatedTenant = await this.tenantRepository.save(tenant);
        return updatedTenant;
    }
    async updateTenantMetadata(id, metadata) {
        const tenant = await this.getTenantById(id);
        if (!tenant) {
            throw new common_1.NotFoundException({
                message: `Tenant with ID ${id} not found`,
                code: 'TENANT_NOT_FOUND'
            });
        }
        tenant.metadata = {
            ...tenant.metadata,
            ...metadata
        };
        const updatedTenant = await this.tenantRepository.save(tenant);
        return updatedTenant;
    }
    async initializeDefaultTenant() {
        const config = this.authConfig.getConfig();
        if (!config.defaultTenant) {
            return null;
        }
        const identifier = config.defaultTenant.slug;
        if (!identifier) {
            throw new common_1.BadRequestException({
                message: 'defaultTenant must have "slug" field',
                code: 'MISSING_TENANT_IDENTIFIER'
            });
        }
        if (config.defaultTenant.slug && !(0, slug_util_1.isValidSlug)(config.defaultTenant.slug)) {
            throw new common_1.BadRequestException({
                message: `Invalid slug format in defaultTenant. Slug must be lowercase with only letters, numbers, hyphens (-) and underscores (_). Got: '${config.defaultTenant.slug}'`,
                code: 'INVALID_SLUG_FORMAT'
            });
        }
        let defaultTenant = null;
        if (config.defaultTenant.slug) {
            defaultTenant = await this.getTenantBySlug(config.defaultTenant.slug);
        }
        if (!defaultTenant) {
            try {
                defaultTenant = await this.createTenant({
                    name: config.defaultTenant.name,
                    slug: config.defaultTenant.slug || null,
                    description: config.defaultTenant.description || 'Default tenant',
                    metadata: config.defaultTenant.metadata || {},
                    isActive: true
                });
            }
            catch (error) {
                if (error.code === 'TENANT_ALREADY_EXISTS') {
                    if (config.defaultTenant.slug) {
                        defaultTenant = await this.getTenantBySlug(config.defaultTenant.slug);
                    }
                }
                if (!defaultTenant) {
                    throw error;
                }
            }
        }
        this.defaultTenant = defaultTenant;
        return defaultTenant;
    }
    getDefaultTenant() {
        return this.defaultTenant;
    }
    getDefaultTenantId() {
        return this.defaultTenant?.id || null;
    }
    async getOrCreateDefaultTenant() {
        if (this.defaultTenant) {
            return this.defaultTenant;
        }
        return await this.initializeDefaultTenant();
    }
    async resolveTenantId(providedTenantId) {
        this.debugLogger.logTenantOperation('resolveTenantId', providedTenantId, { providedTenantId });
        if (providedTenantId) {
            this.debugLogger.debug('Using provided tenant ID', 'TenantService', { tenantId: providedTenantId });
            return providedTenantId;
        }
        const defaultTenant = await this.getOrCreateDefaultTenant();
        const resolvedTenantId = defaultTenant?.id || null;
        this.debugLogger.debug('Resolved tenant ID', 'TenantService', { resolvedTenantId, hasDefaultTenant: !!defaultTenant });
        return resolvedTenantId;
    }
};
exports.TenantService = TenantService;
exports.TenantService = TenantService = __decorate([
    (0, common_1.Injectable)(),
    __param(0, (0, typeorm_1.InjectRepository)(tenant_entity_1.NestAuthTenant)),
    __metadata("design:paramtypes", [typeorm_2.Repository,
        event_emitter_1.EventEmitter2,
        auth_config_service_1.AuthConfigService,
        debug_logger_service_1.DebugLoggerService])
], TenantService);
//# sourceMappingURL=tenant.service.js.map