"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); }
};
var ClusterDeletionService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClusterDeletionService = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("@nestjs/typeorm");
const typeorm_2 = require("typeorm");
const bull_1 = require("@nestjs/bull");
const cluster_entity_1 = require("../entities/cluster.entity");
const infrastructure_operations_entity_1 = require("../../servers/entities/infrastructure-operations.entity");
const cluster_firewall_integration_service_1 = require("./cluster-firewall-integration.service");
const grafana_datasource_service_1 = require("../../../../modules/grafana/services/grafana-datasource.service");
const cluster_dns_cleanup_service_1 = require("../../../../modules/dns/services/cluster-dns-cleanup.service");
/**
 * Service responsible for cluster deletion logic
 */
let ClusterDeletionService = ClusterDeletionService_1 = class ClusterDeletionService {
    constructor(clusterRepository, operationRepository, infrastructureQueue, clusterFirewallIntegrationService, grafanaDatasourceService, clusterDnsCleanupService) {
        this.clusterRepository = clusterRepository;
        this.operationRepository = operationRepository;
        this.infrastructureQueue = infrastructureQueue;
        this.clusterFirewallIntegrationService = clusterFirewallIntegrationService;
        this.grafanaDatasourceService = grafanaDatasourceService;
        this.clusterDnsCleanupService = clusterDnsCleanupService;
        this.logger = new common_1.Logger(ClusterDeletionService_1.name);
    }
    /**
     * Delete a cluster
     */
    async deleteCluster(clusterId, force = false) {
        this.logger.log(`Deleting cluster: ${clusterId} (force: ${force})`);
        // Check if cluster exists
        const cluster = await this.clusterRepository.findOne({
            where: { id: clusterId },
            relations: ['nodes'],
        });
        if (!cluster) {
            throw new common_1.NotFoundException(`Cluster ${clusterId} not found`);
        }
        // Check if cluster is already being deleted or deleted (allow retry from DELETION_FAILED)
        if (cluster.status === cluster_entity_1.ClusterStatus.DELETING) {
            throw new common_1.BadRequestException(`Cluster ${clusterId} is currently being deleted. Please wait for the operation to complete.`);
        }
        if (cluster.status === cluster_entity_1.ClusterStatus.DELETED) {
            throw new common_1.BadRequestException(`Cluster ${clusterId} has already been deleted`);
        }
        // Log retry attempt if status is DELETION_FAILED
        if (cluster.status === cluster_entity_1.ClusterStatus.DELETION_FAILED) {
            this.logger.log(`Retrying deletion for cluster ${clusterId} (previous attempt failed: ${cluster.metadata?.deletionError || 'unknown error'})`);
        }
        // Pre-deletion hook: Remove Grafana datasources if this is a workload cluster
        await this.removeClusterFromGrafana(cluster);
        // Update cluster status to DELETING
        cluster.status = cluster_entity_1.ClusterStatus.DELETING;
        await this.clusterRepository.save(cluster);
        // Create operation record
        const operation = this.operationRepository.create({
            operationType: infrastructure_operations_entity_1.OperationType.DELETE_CLUSTER,
            status: infrastructure_operations_entity_1.OperationStatus.PENDING,
            resourceType: 'cluster',
            resourceName: cluster.name,
            resourceId: cluster.id,
            metadata: {
                clusterId: cluster.id,
                clusterName: cluster.name,
                nodeCount: cluster.nodes.length,
                force,
                estimatedDurationInSeconds: 80,
            },
        });
        const savedOperation = await this.operationRepository.save(operation);
        // Queue delete cluster job
        const jobData = {
            operationId: savedOperation.id,
            clusterId: cluster.id,
            force,
        };
        await this.infrastructureQueue.add('delete-cluster', jobData, {
            attempts: 3,
            backoff: {
                type: 'exponential',
                delay: 2000,
            },
            timeout: 600000, // 10 minutes
        });
        this.logger.log(`Cluster deletion job queued for cluster ${clusterId} with operation ${savedOperation.id}`);
        return savedOperation;
    }
    /**
     * Cleanup cluster firewall during deletion
     * Called from the queue processor after nodes are deleted
     */
    async cleanupClusterFirewall(clusterId, provider) {
        this.logger.log(`Cleaning up firewall for cluster ${clusterId}`);
        try {
            await this.clusterFirewallIntegrationService.deleteClusterFirewall(clusterId, provider);
            this.logger.log(`Firewall cleanup completed for cluster ${clusterId}`);
        }
        catch (error) {
            // Log error but don't fail cluster deletion
            this.logger.error(`Failed to cleanup firewall for cluster ${clusterId}: ${error.message}`, error.stack);
        }
    }
    async cleanupClusterDnsRecords(clusterId) {
        this.logger.log(`Cleaning up DNS records for cluster ${clusterId}`);
        try {
            const deleted = await this.clusterDnsCleanupService.deleteRecordsByClusterId(clusterId);
            this.logger.log(`DNS cleanup completed for cluster ${clusterId} (${deleted} record(s) removed)`);
        }
        catch (error) {
            this.logger.error(`Failed to cleanup DNS records for cluster ${clusterId}: ${error.message}`, error.stack);
        }
    }
    /**
     * Remove workload cluster datasources from Grafana observability cluster
     * Called automatically before cluster deletion
     */
    async removeClusterFromGrafana(cluster) {
        // Only remove datasources for WORKLOAD clusters (not OBSERVABILITY clusters)
        if (cluster.clusterType !== cluster_entity_1.ClusterType.WORKLOAD) {
            this.logger.debug(`Skipping Grafana datasource removal for ${cluster.clusterType} cluster ${cluster.name}`);
            return;
        }
        try {
            this.logger.log(`Removing cluster ${cluster.name} datasources from Grafana`);
            // Remove datasources from Grafana
            await this.grafanaDatasourceService.removeClusterDatasources(cluster.id);
            this.logger.log(`✅ Cluster ${cluster.name} datasources removed from Grafana`);
        }
        catch (error) {
            // Log error but don't fail cluster deletion
            this.logger.warn(`Failed to remove cluster ${cluster.name} from Grafana: ${error.message}`);
            this.logger.warn('Cluster deletion will proceed - Grafana datasources may need manual cleanup');
        }
    }
};
exports.ClusterDeletionService = ClusterDeletionService;
exports.ClusterDeletionService = ClusterDeletionService = ClusterDeletionService_1 = __decorate([
    (0, common_1.Injectable)(),
    __param(0, (0, typeorm_1.InjectRepository)(cluster_entity_1.ClusterEntity)),
    __param(1, (0, typeorm_1.InjectRepository)(infrastructure_operations_entity_1.InfrastructureOperationEntity)),
    __param(2, (0, bull_1.InjectQueue)('infrastructure')),
    __metadata("design:paramtypes", [typeorm_2.Repository,
        typeorm_2.Repository, Object, cluster_firewall_integration_service_1.ClusterFirewallIntegrationService,
        grafana_datasource_service_1.GrafanaDatasourceService,
        cluster_dns_cleanup_service_1.ClusterDnsCleanupService])
], ClusterDeletionService);
