"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 ClustersService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClustersService = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("@nestjs/typeorm");
const typeorm_2 = require("typeorm");
const kubernetes_service_1 = require("../shared/services/kubernetes.service");
const build_job_service_1 = require("../../app-builds/services/build-job.service");
const cluster_entity_1 = require("./entities/cluster.entity");
// Import new modular services
const cluster_validation_service_1 = require("./services/cluster-validation.service");
const cluster_creation_service_1 = require("./services/cluster-creation.service");
const cluster_deletion_service_1 = require("./services/cluster-deletion.service");
const cluster_mapper_service_1 = require("./services/cluster-mapper.service");
const cluster_operations_service_1 = require("./services/cluster-operations.service");
const cluster_power_management_service_1 = require("./services/cluster-power-management.service");
const encryption_service_1 = require("../../shared/encryption/services/encryption.service");
/**
 * Main orchestrator service for cluster operations
 * Delegates to specialized services for better separation of concerns
 */
let ClustersService = ClustersService_1 = class ClustersService {
    constructor(clusterRepository, clusterValidationService, clusterCreationService, clusterDeletionService, clusterMapperService, clusterOperationsService, clusterPowerManagementService, encryptionService, kubernetesService) {
        this.clusterRepository = clusterRepository;
        this.clusterValidationService = clusterValidationService;
        this.clusterCreationService = clusterCreationService;
        this.clusterDeletionService = clusterDeletionService;
        this.clusterMapperService = clusterMapperService;
        this.clusterOperationsService = clusterOperationsService;
        this.clusterPowerManagementService = clusterPowerManagementService;
        this.encryptionService = encryptionService;
        this.kubernetesService = kubernetesService;
        this.logger = new common_1.Logger(ClustersService_1.name);
    }
    /**
     * Create a new K3s cluster
     */
    async createCluster(dto) {
        // Validate request
        await this.clusterValidationService.validateCreateClusterRequest(dto);
        // Delegate to creation service
        return await this.clusterCreationService.createCluster(dto);
    }
    /**
     * Delete a cluster
     */
    async deleteCluster(clusterId, force = false) {
        // Delegate to deletion service
        return await this.clusterDeletionService.deleteCluster(clusterId, force);
    }
    /**
     * Get cluster by ID
     */
    async getCluster(clusterId, includeRealStatus = false) {
        const cluster = await this.clusterRepository.findOne({
            where: { id: clusterId },
            relations: ['nodes'],
        });
        if (!cluster) {
            throw new common_1.NotFoundException(`Cluster ${clusterId} not found`);
        }
        // If real-time status is requested, enrich with provider data
        if (includeRealStatus) {
            return this.clusterPowerManagementService.enrichClusterWithRealStatus(cluster);
        }
        return this.clusterMapperService.mapToDto(cluster);
    }
    /**
     * List all clusters (excluding deleted)
     */
    async listClusters() {
        const clusters = await this.clusterRepository.find({
            where: {
                status: (0, typeorm_2.Not)(cluster_entity_1.ClusterStatus.DELETED),
            },
            relations: ['nodes'],
            order: {
                createdAt: 'DESC',
            },
        });
        return this.clusterMapperService.mapToDtos(clusters);
    }
    /**
     * Register an existing externally-managed cluster
     */
    async registerCluster(dto) {
        return await this.clusterOperationsService.registerCluster(dto);
    }
    /**
     * Get cluster entity by ID (for internal use)
     */
    async getClusterEntity(clusterId) {
        const cluster = await this.clusterRepository.findOne({
            where: { id: clusterId },
            relations: ['nodes'],
        });
        if (!cluster) {
            throw new common_1.NotFoundException(`Cluster ${clusterId} not found`);
        }
        return cluster;
    }
    /**
     * Get kubeconfig for cluster
     */
    async getKubeconfig(clusterId) {
        return await this.clusterOperationsService.getKubeconfig(clusterId);
    }
    /**
     * Get cluster nodes
     */
    async getClusterNodes(clusterId) {
        return await this.clusterOperationsService.getClusterNodes(clusterId);
    }
    /**
     * Update cluster metadata
     */
    async updateClusterMetadata(clusterId, metadata) {
        return await this.clusterOperationsService.updateClusterMetadata(clusterId, metadata);
    }
    /**
     * Update node metadata
     */
    async updateNodeMetadata(clusterId, nodeId, metadata) {
        return await this.clusterOperationsService.updateNodeMetadata(clusterId, nodeId, metadata);
    }
    /**
     * Reconcile cluster tags (deprecated - stub implementation)
     */
    async reconcileClusterTags(clusterId, force, includeFirewalls) {
        return await this.clusterOperationsService.reconcileClusterTags(clusterId, force, includeFirewalls);
    }
    /**
     * Reconcile cluster firewalls (deprecated - use new desired-state API)
     */
    async reconcileClusterFirewalls(clusterId, options) {
        return await this.clusterOperationsService.reconcileClusterFirewalls(clusterId, options);
    }
    /**
     * Stop all servers in a cluster (async operation)
     */
    async stopCluster(clusterId) {
        return await this.clusterPowerManagementService.stopClusterAsync(clusterId);
    }
    /**
     * Start all servers in a cluster (async operation)
     */
    async startCluster(clusterId) {
        return await this.clusterPowerManagementService.startClusterAsync(clusterId);
    }
    /**
     * Reconcile cluster status with real provider state
     */
    async reconcileClusterStatus(clusterId, autoFix = false) {
        return await this.clusterPowerManagementService.reconcileClusterStatus(clusterId, autoFix);
    }
    /**
     * Check whether a cluster has sufficient resources for a new deployment.
     *
     * @param clusterId      - Target cluster UUID
     * @param cpuRequest     - CPU request in millicores (e.g. 250 for "250m")
     * @param memoryRequest  - Memory request in mebibytes (e.g. 256 for "256Mi")
     * @param replicas       - Number of replicas (default 1)
     * @param profileName    - Human-readable profile name for the response (optional)
     */
    async checkResourceAvailability(clusterId, cpuRequest, memoryRequest, replicas = 1, profileName = null) {
        const cluster = await this.clusterRepository.findOne({
            where: { id: clusterId },
        });
        if (!cluster) {
            throw new common_1.NotFoundException(`Cluster ${clusterId} not found`);
        }
        const kubeconfig = await this.getKubeconfig(clusterId);
        const [total, used] = await Promise.all([
            this.kubernetesService.getNodeAllocatable(kubeconfig),
            this.kubernetesService.getPodResourceRequests(kubeconfig),
        ]);
        // Apply 10% safety margin
        const availableCpu = Math.floor(total.cpu * 0.9) - used.cpu;
        const availableMemory = Math.floor(total.memory * 0.9) - used.memory;
        const requiredCpu = cpuRequest * replicas;
        const requiredMemory = memoryRequest * replicas;
        const hasEnoughCpu = availableCpu >= requiredCpu;
        const hasEnoughMemory = availableMemory >= requiredMemory;
        const autoscalingEnabled = cluster.autoscalingEnabled ?? false;
        let canDeploy;
        let reason = null;
        if (hasEnoughCpu && hasEnoughMemory) {
            canDeploy = true;
        }
        else if (autoscalingEnabled) {
            canDeploy = true;
            reason = 'autoscaling_pending';
        }
        else {
            canDeploy = false;
            reason = 'insufficient_resources';
        }
        const formatCpu = (mc) => `${mc}m`;
        const formatMem = (mi) => mi >= 1024 ? `${(mi / 1024).toFixed(1).replace('.0', '')}Gi` : `${mi}Mi`;
        return {
            canDeploy,
            reason,
            profile: profileName,
            required: {
                cpu: formatCpu(requiredCpu),
                memory: formatMem(requiredMemory),
            },
            available: {
                cpu: formatCpu(Math.max(availableCpu, 0)),
                memory: formatMem(Math.max(availableMemory, 0)),
            },
            total: { cpu: formatCpu(total.cpu), memory: formatMem(total.memory) },
            used: { cpu: formatCpu(used.cpu), memory: formatMem(used.memory) },
            autoscalingEnabled,
        };
    }
    async getBuildResources(clusterId) {
        const check = await this.checkResourceAvailability(clusterId, build_job_service_1.BUILD_JOB_CPU_REQUEST, build_job_service_1.BUILD_JOB_MEMORY_REQUEST);
        let status;
        if (check.canDeploy && check.reason === null) {
            status = 'ok';
        }
        else if (check.autoscalingEnabled) {
            status = 'autoscaling_required';
        }
        else {
            status = 'insufficient';
        }
        return {
            status,
            required: check.required,
            available: check.available,
            total: check.total,
            used: check.used,
            autoscalingEnabled: check.autoscalingEnabled,
        };
    }
};
exports.ClustersService = ClustersService;
exports.ClustersService = ClustersService = ClustersService_1 = __decorate([
    (0, common_1.Injectable)(),
    __param(0, (0, typeorm_1.InjectRepository)(cluster_entity_1.ClusterEntity)),
    __metadata("design:paramtypes", [typeorm_2.Repository,
        cluster_validation_service_1.ClusterValidationService,
        cluster_creation_service_1.ClusterCreationService,
        cluster_deletion_service_1.ClusterDeletionService,
        cluster_mapper_service_1.ClusterMapperService,
        cluster_operations_service_1.ClusterOperationsService,
        cluster_power_management_service_1.ClusterPowerManagementService,
        encryption_service_1.EncryptionService,
        kubernetes_service_1.KubernetesService])
], ClustersService);
