"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;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.CliInfrastructureModule = void 0;
const common_1 = require("@nestjs/common");
const config_1 = require("@nestjs/config");
const typeorm_shim_1 = require("../lib/typeorm-shim");
const node_child_process_1 = require("node:child_process");
const path = __importStar(require("node:path"));
// CLI repositories
const repositories_1 = require("../lib/repositories");
// Entities
const cluster_entity_1 = require("../../../src/modules/infrastructure/clusters/entities/cluster.entity");
const cluster_node_entity_1 = require("../../../src/modules/infrastructure/clusters/entities/cluster-node.entity");
const infrastructure_operations_entity_1 = require("../../../src/modules/infrastructure/servers/entities/infrastructure-operations.entity");
// Services
const encryption_module_1 = require("../../../src/modules/shared/encryption/encryption.module");
const kubernetes_service_1 = require("../../../src/modules/infrastructure/shared/services/kubernetes.service");
const label_service_1 = require("../../../src/modules/infrastructure/shared/services/label.service");
const cli_k3s_script_service_1 = require("../services/cli-k3s-script.service");
const cli_cluster_creator_service_1 = require("../services/cli-cluster-creator.service");
const cli_clusters_service_1 = require("../services/cli-clusters.service");
const cli_observability_cluster_service_1 = require("../services/cli-observability-cluster.service");
const cli_ssh_service_1 = require("../services/cli-ssh.service");
const cli_ca_service_1 = require("../services/cli-ca.service");
const cli_logger_service_1 = require("../services/cli-logger.service");
const cli_endpoint_resolver_service_1 = require("../services/cli-endpoint-resolver.service");
const cluster_storage_service_1 = require("../../../src/modules/infrastructure/clusters/services/cluster-storage.service");
const cluster_capacity_service_1 = require("../../../src/modules/infrastructure/clusters/services/cluster-capacity.service");
const cluster_node_scaling_service_1 = require("../../../src/modules/infrastructure/clusters/services/cluster-node-scaling.service");
const billing_intervals_service_1 = require("../../../src/modules/infrastructure/clusters/services/billing-intervals.service");
const node_billable_interval_entity_1 = require("../../../src/modules/infrastructure/clusters/entities/node-billable-interval.entity");
const volume_billable_interval_entity_1 = require("../../../src/modules/infrastructure/clusters/entities/volume-billable-interval.entity");
const application_entity_1 = require("../../../src/modules/applications/entities/application.entity");
const native_ssh_connection_service_1 = require("../../../src/modules/terminal/services/native-ssh-connection.service");
const access_service_1 = require("../../../src/modules/access/services/access.service");
// Modules
const cli_providers_module_1 = require("../cli-providers.module");
const common_module_1 = require("../../../src/modules/common/common.module");
/**
 * CLI Infrastructure Module
 *
 * Provides infrastructure services for CLI commands without requiring database or Redis.
 * Uses file-based repositories that persist data to ~/.flui/*.json files.
 *
 * Key differences from InfrastructureModule:
 * - NO TypeORM database connection required
 * - NO Bull/Redis queue required
 * - File-based persistence in ~/.flui/
 * - Synchronous cluster operations (no background jobs)
 */
let CliInfrastructureModule = class CliInfrastructureModule {
};
exports.CliInfrastructureModule = CliInfrastructureModule;
exports.CliInfrastructureModule = CliInfrastructureModule = __decorate([
    (0, common_1.Module)({
        imports: [config_1.ConfigModule, cli_providers_module_1.CliProvidersModule, common_module_1.CommonModule, encryption_module_1.EncryptionModule],
        providers: [
            // File-based repositories
            repositories_1.CliClusterRepository,
            repositories_1.CliNodeRepository,
            repositories_1.CliOperationRepository,
            repositories_1.CliFirewallRepository,
            // Provide CLI repositories as TypeORM repository tokens
            // This allows ClustersService to inject them without knowing they're file-based
            {
                provide: (0, typeorm_shim_1.getRepositoryToken)(cluster_entity_1.ClusterEntity),
                useExisting: repositories_1.CliClusterRepository,
            },
            {
                provide: (0, typeorm_shim_1.getRepositoryToken)(cluster_node_entity_1.ClusterNodeEntity),
                useExisting: repositories_1.CliNodeRepository,
            },
            {
                provide: (0, typeorm_shim_1.getRepositoryToken)(infrastructure_operations_entity_1.InfrastructureOperationEntity),
                useExisting: repositories_1.CliOperationRepository,
            },
            // CLI mode: BillingIntervalsService is unused at runtime (CLI doesn't track
            // node intervals — that's done by the in-cluster API at the master). Stub
            // the two interval repos so the service can be constructed and methods are
            // safe no-ops if accidentally called.
            {
                provide: (0, typeorm_shim_1.getRepositoryToken)(node_billable_interval_entity_1.NodeBillableIntervalEntity),
                useValue: {
                    find: async () => [],
                    findOne: async () => null,
                    save: async (e) => e,
                    update: async () => undefined,
                    create: (data) => data,
                },
            },
            {
                provide: (0, typeorm_shim_1.getRepositoryToken)(volume_billable_interval_entity_1.VolumeBillableIntervalEntity),
                useValue: {
                    find: async () => [],
                    findOne: async () => null,
                    save: async (e) => e,
                    update: async () => undefined,
                    create: (data) => data,
                },
            },
            billing_intervals_service_1.BillingIntervalsService,
            // CLI-specific services
            cli_k3s_script_service_1.CliK3sScriptService,
            cli_cluster_creator_service_1.CliClusterCreatorService,
            // Provide a Bull Queue that executes operations asynchronously via background worker
            // Instead of queuing to Bull/Redis, we spawn a detached background process
            {
                provide: 'BullQueue_infrastructure',
                useFactory: () => ({
                    add: async (jobName, jobData) => {
                        console.log(`[CLI Mode] Spawning background job: ${jobName}`);
                        // Determine the path to the compiled worker script
                        // In development: cli/lib/cli/src/background/cluster-worker.js
                        // The worker will be compiled by TypeScript to the lib directory
                        const workerScript = path.join(__dirname, '../background/cluster-worker.js');
                        // Spawn background worker as detached process
                        const child = (0, node_child_process_1.spawn)(process.execPath, // Use same Node.js executable
                        [workerScript, jobName, JSON.stringify(jobData)], {
                            detached: true, // Run independently of parent
                            cwd: process.cwd(), // Use current working directory
                            windowsHide: true, // Prevent console window flash on Windows
                            stdio: 'ignore', // Fully detach stdio to prevent Windows console popup
                        });
                        // Detach from parent so CLI can exit immediately
                        child.unref();
                        console.log(`[CLI Mode] Background job spawned (PID: ${child.pid})`);
                        console.log(`[CLI Mode] Job will continue running in background`);
                        // Return immediately with a job ID
                        return { id: `cli-bg-${Date.now()}-${child.pid}` };
                    },
                }),
                inject: [],
            },
            // Infrastructure services
            label_service_1.LabelService,
            kubernetes_service_1.KubernetesService,
            cli_clusters_service_1.CliClustersService,
            cli_observability_cluster_service_1.CliObservabilityClusterService,
            cli_ssh_service_1.CliSshService,
            cli_ca_service_1.CliCaService,
            cli_logger_service_1.CliLoggerService,
            cli_endpoint_resolver_service_1.CliEndpointResolverService,
            cluster_storage_service_1.ClusterStorageService,
            cluster_capacity_service_1.ClusterCapacityService,
            // Stubs for CLI mode (no apps DB, no SSH-cert key registry).
            // ClusterNodeScalingService.scaleNode does not touch ApplicationEntity/SSH at all,
            // so these stubs only matter for expandSharedVolume which is not validatable in CLI mode.
            {
                provide: (0, typeorm_shim_1.getRepositoryToken)(application_entity_1.ApplicationEntity),
                useValue: (() => {
                    const emptyQueryBuilder = {
                        where: () => emptyQueryBuilder,
                        andWhere: () => emptyQueryBuilder,
                        getMany: async () => [],
                    };
                    return {
                        find: async () => [],
                        findOne: async () => null,
                        createQueryBuilder: () => emptyQueryBuilder,
                    };
                })(),
            },
            native_ssh_connection_service_1.NativeSSHConnectionService,
            {
                // CLI-mode AccessService stub: pulls the bootstrap private key from
                // ~/.flui/bootstrap-keys/<keyId> (where the CLI stored it at cluster
                // creation time). Avoids depending on the full AccessService which
                // expects a DB-backed key registry.
                provide: access_service_1.AccessService,
                useFactory: () => {
                    const fs = require('node:fs/promises');
                    const path = require('node:path');
                    const os = require('node:os');
                    return {
                        getPrivateKey: async (_user, keyId) => {
                            const candidates = [
                                path.join(os.homedir(), '.flui', 'bootstrap-keys', keyId),
                                path.join(os.homedir(), '.flui', 'bootstrap-keys', `${keyId}.pem`),
                                path.join(os.homedir(), '.flui', 'bootstrap-keys', `${keyId}.key`),
                            ];
                            for (const p of candidates) {
                                try {
                                    return await fs.readFile(p, 'utf8');
                                }
                                catch {
                                    /* try next */
                                }
                            }
                            throw new Error(`Bootstrap key ${keyId} not found under ~/.flui/bootstrap-keys/`);
                        },
                    };
                },
            },
            cluster_node_scaling_service_1.ClusterNodeScalingService,
        ],
        exports: [
            cli_observability_cluster_service_1.CliObservabilityClusterService,
            cli_clusters_service_1.CliClustersService,
            kubernetes_service_1.KubernetesService,
            label_service_1.LabelService,
            cli_ssh_service_1.CliSshService,
            cli_ca_service_1.CliCaService,
            cli_logger_service_1.CliLoggerService,
            cli_endpoint_resolver_service_1.CliEndpointResolverService,
            cluster_storage_service_1.ClusterStorageService,
            cluster_capacity_service_1.ClusterCapacityService,
            cluster_node_scaling_service_1.ClusterNodeScalingService,
        ],
    })
], CliInfrastructureModule);
