/**
 * Deploy Command - Deployment Management
 *
 * ARCHITECTURE:
 * - This module supports both orchestration commands AND local deployment management
 * - Authorized users (internal email or paid API key) get full execution
 *
 * SUBCOMMANDS (Local Deployment):
 * - preview    Generate deployment preview
 * - run        Execute deployment via downstream services
 * - status     Check deployment status
 * - rollback   Rollback deployment via downstream services
 *
 * ORCHESTRATION (External):
 * - Default command executes via agentics-deployment-intent
 */
import { isNaturalLanguage } from '../types/index.js';
import { IntentAdapter, RuvectorAdapter } from '../adapters/base-adapter.js';
import { createOrchestrationEngine, } from '../modules/orchestration-engine.js';
import { createArtifactHandoff } from '../modules/artifact-handoff.js';
import { createAuditTrail } from '../audit/audit-trail.js';
import { failFast, toError, CLIError } from '../errors/index.js';
import { loadEndpointConfig } from '../config/endpoints.js';
import { validateRequest, validateResponse, RequestSchemas, ResponseSchemas, } from '../contracts/validator.js';
// ============================================================================
// Deploy Command Implementation
// ============================================================================
export async function executeDeployCommand(input, options) {
    const correlationId = options.trace_id ?? crypto.randomUUID();
    const startTime = Date.now();
    // Initialize components
    const engine = createOrchestrationEngine(correlationId);
    const handoff = createArtifactHandoff();
    const audit = createAuditTrail();
    // Create adapter
    const intentConfig = loadEndpointConfig('agentics-deployment-intent');
    const intentAdapter = new IntentAdapter(intentConfig, correlationId);
    // Define orchestration stages
    const stages = [
        {
            name: 'resolve-intent',
            adapter: intentAdapter,
            request: {
                endpoint: '/v1/intent',
                method: 'POST',
                buildBody: () => {
                    let requestBody;
                    if (isNaturalLanguage(input.simRef)) {
                        // ============================================================================
                        // CONTRACT VALIDATION - Natural language format
                        // ============================================================================
                        requestBody = {
                            sim_ref: {
                                natural_language: input.simRef.description,
                            },
                            environment: input.environment,
                            approval_required: input.approvalRequired,
                            dry_run: input.dryRun,
                            rollback_on_failure: input.rollbackOnFailure,
                        };
                    }
                    else {
                        // ============================================================================
                        // CONTRACT VALIDATION - Structured reference format
                        // ============================================================================
                        const simRef = input.simRef;
                        requestBody = {
                            sim_ref: {
                                id: simRef.id,
                                type: 'SimulationReference',
                                repository: simRef.repository,
                                created_at: simRef.created_at,
                                checksum: simRef.checksum,
                            },
                            environment: input.environment,
                            approval_required: input.approvalRequired,
                            dry_run: input.dryRun,
                            rollback_on_failure: input.rollbackOnFailure,
                        };
                    }
                    // Validate request against contract BEFORE sending
                    validateRequest(RequestSchemas.DEPLOY, requestBody, correlationId);
                    return requestBody;
                },
            },
        },
    ];
    try {
        // Execute orchestration
        const result = await engine.execute(stages, options);
        if (!result.success) {
            const failedStage = result.stages.find(s => s.status === 'failed');
            throw new Error(failedStage?.error?.message ?? 'Deployment intent resolution failed');
        }
        // ============================================================================
        // RESPONSE VALIDATION - execution_metadata REQUIRED
        // ============================================================================
        const intentStage = result.stages.find(s => s.name === 'resolve-intent');
        const validatedIntent = validateResponse(ResponseSchemas.INTENT, intentStage?.response, correlationId);
        const intentRef = handoff.extractReference(validatedIntent);
        // Record audit entry
        const simRefId = isNaturalLanguage(input.simRef)
            ? `nl:${input.simRef.description.slice(0, 50)}`
            : input.simRef.id;
        audit.record({
            command: 'deploy',
            inputs: { simRef: simRefId, environment: input.environment },
            outputs: intentRef,
            dependencies: [
                { service: 'agentics-deployment-intent', method: 'resolve', timestamp: new Date().toISOString(), duration_ms: result.timing.total, success: true },
            ],
            duration_ms: result.timing.total,
            status: 'SUCCESS',
            trace_id: correlationId,
        });
        return {
            reference: intentRef,
            timing: Date.now() - startTime,
        };
    }
    catch (error) {
        // Record failure in audit
        const failedSimRefId = isNaturalLanguage(input.simRef)
            ? `nl:${input.simRef.description.slice(0, 50)}`
            : input.simRef.id;
        audit.record({
            command: 'deploy',
            inputs: { simRef: failedSimRefId },
            outputs: null,
            dependencies: [],
            duration_ms: Date.now() - startTime,
            status: 'FAILED',
            error_code: error instanceof Error ? error.name : 'UNKNOWN',
            error_message: error instanceof Error ? error.message : 'Unknown error',
            trace_id: correlationId,
        });
        // Fail fast
        failFast({
            command: 'deploy',
            phase: 'intent-resolution',
            upstreamError: toError(error),
            inputs: input,
            correlationId,
        });
    }
}
// ============================================================================
// Deploy-Specific Exit Codes
// ============================================================================
export const DEPLOY_EXIT_CODES = {
    SUCCESS: 0,
    INPUT_ERROR: 100,
    NOT_FOUND: 100,
    IO_ERROR: 74,
    UNEXPECTED_ERROR: 1,
};
// ============================================================================
// Ruvector Adapter Helper
// ============================================================================
function createRuvectorAdapter(correlationId) {
    const config = loadEndpointConfig('ruvector-service');
    return new RuvectorAdapter(config, correlationId);
}
// ============================================================================
// ID Generation
// ============================================================================
function generateDeploymentId() {
    // Use standard UUID format for production compatibility
    return crypto.randomUUID();
}
// ============================================================================
// Validation
// ============================================================================
function validateTargetId(id, correlationId) {
    if (!id || typeof id !== 'string' || id.trim() === '') {
        throw new CLIError({
            code: 'ECLI-DEPLOY-001',
            category: 'INPUT_ERROR',
            message: 'Target ID is required',
            details: { provided: id },
            module: 'deploy',
            correlationId,
            recoverable: false,
            exitCode: DEPLOY_EXIT_CODES.INPUT_ERROR,
        });
    }
}
function validateDeploymentId(id, correlationId) {
    if (!id || typeof id !== 'string' || id.trim() === '') {
        throw new CLIError({
            code: 'ECLI-DEPLOY-002',
            category: 'INPUT_ERROR',
            message: 'Deployment ID is required',
            details: { provided: id },
            module: 'deploy',
            correlationId,
            recoverable: false,
            exitCode: DEPLOY_EXIT_CODES.INPUT_ERROR,
        });
    }
}
// ============================================================================
// Display Formatting
// ============================================================================
export function formatDeployForDisplay(record) {
    const lines = [];
    lines.push(`Deployment: ${record.id}`);
    lines.push(`Target: ${record.target_id}`);
    lines.push(`Environment: ${record.environment}`);
    lines.push(`Status: ${record.status}`);
    lines.push('');
    if (record.preview) {
        lines.push('Preview:');
        lines.push(`  Risk Level: ${record.preview.risk_level}`);
        lines.push(`  Estimated Duration: ${record.preview.estimated_duration_seconds}s`);
        lines.push(`  Requires Approval: ${record.preview.requires_approval}`);
        lines.push(`  Changes: ${record.preview.changes.length}`);
        for (const change of record.preview.changes) {
            lines.push(`    - ${change.action.toUpperCase()} ${change.resource}: ${change.details}`);
        }
        lines.push('');
    }
    if (record.execution) {
        lines.push('Execution:');
        lines.push(`  Started: ${record.execution.started_at}`);
        if (record.execution.completed_at) {
            lines.push(`  Completed: ${record.execution.completed_at}`);
        }
        lines.push(`  Progress: ${record.execution.steps_completed}/${record.execution.steps_total}`);
        lines.push(`  Executed: ${!record.execution.advisory}`);
        lines.push('');
    }
    lines.push(`Created: ${record.created_at}`);
    lines.push(`Updated: ${record.updated_at}`);
    lines.push(`Version: ${record.version}`);
    return lines.join('\n');
}
export function formatDeployListForDisplay(items) {
    if (items.length === 0) {
        return 'No deployments found.';
    }
    const lines = [];
    lines.push(`Found ${items.length} deployment${items.length === 1 ? '' : 's'}:`);
    lines.push('');
    for (const record of items) {
        lines.push(`  ${record.id}`);
        lines.push(`    Target: ${record.target_id} | Env: ${record.environment} | Status: ${record.status}`);
        lines.push(`    Created: ${record.created_at}`);
        lines.push('');
    }
    return lines.join('\n');
}
// ============================================================================
// Generate Preview Data (Stubbed)
// ============================================================================
function generatePreview(targetId, environment) {
    // Generate preview data for deployment plan
    const changes = [
        { resource: 'compute/instance-group', action: 'update', details: `Update instance group for ${targetId}` },
        { resource: 'network/load-balancer', action: 'unchanged', details: 'No changes required' },
        { resource: 'storage/bucket', action: 'create', details: `Create storage bucket for ${targetId}` },
        { resource: 'iam/service-account', action: 'update', details: 'Update service account permissions' },
    ];
    const riskLevel = environment === 'production' ? 'high' : environment === 'staging' ? 'medium' : 'low';
    const requiresApproval = environment === 'production';
    return {
        changes,
        estimated_duration_seconds: environment === 'production' ? 300 : 120,
        risk_level: riskLevel,
        requires_approval: requiresApproval,
        generated_at: new Date().toISOString(),
    };
}
// ============================================================================
// Deploy Commands - Preview (Ruvector Storage)
// ============================================================================
export async function executeDeployPreviewCommand(input, options) {
    const correlationId = options.trace_id ?? crypto.randomUUID();
    const startTime = Date.now();
    // Validate input
    validateTargetId(input.target_id, correlationId);
    const environment = input.environment ?? 'development';
    const id = generateDeploymentId();
    // Generate preview
    const preview = generatePreview(input.target_id, environment);
    // Create deployment record
    const now = new Date().toISOString();
    const record = {
        id,
        target_id: input.target_id,
        environment,
        status: 'previewed',
        preview,
        execution: null,
        created_at: now,
        updated_at: now,
        version: 1,
        metadata: {
            correlation_id: correlationId,
        },
    };
    // Store in Ruvector service
    try {
        const ruvectorAdapter = createRuvectorAdapter(correlationId);
        await ruvectorAdapter.storeDeployment(record);
    }
    catch (error) {
        throw new CLIError({
            code: 'ECLI-DEPLOY-003',
            category: 'INTERNAL_ERROR',
            message: `Failed to persist deployment to storage: ${error instanceof Error ? error.message : 'Unknown error'}`,
            details: { deployment_id: id },
            module: 'deploy',
            correlationId,
            recoverable: false,
            exitCode: DEPLOY_EXIT_CODES.IO_ERROR,
        });
    }
    return {
        result: record,
        timing: Date.now() - startTime,
    };
}
// ============================================================================
// Deploy Commands - Run (Ruvector Storage)
// ============================================================================
export async function executeDeployRunCommand(input, options) {
    const correlationId = options.trace_id ?? crypto.randomUUID();
    const startTime = Date.now();
    // Validate input
    validateDeploymentId(input.deployment_id, correlationId);
    // Load existing deployment from Ruvector
    const ruvectorAdapter = createRuvectorAdapter(correlationId);
    let record = null;
    try {
        const response = await ruvectorAdapter.getDeployment(input.deployment_id);
        if (response.status === 200 && response.body) {
            record = response.body;
        }
    }
    catch (error) {
        // Check if this is a 404 (not found) error
        if (error instanceof Error && error.message.includes('404')) {
            record = null;
        }
        else {
            throw new CLIError({
                code: 'ECLI-DEPLOY-011',
                category: 'INTERNAL_ERROR',
                message: `Failed to retrieve deployment: ${error instanceof Error ? error.message : 'Unknown error'}`,
                details: { deployment_id: input.deployment_id },
                module: 'deploy',
                correlationId,
                recoverable: false,
                exitCode: DEPLOY_EXIT_CODES.IO_ERROR,
            });
        }
    }
    if (!record) {
        throw new CLIError({
            code: 'ECLI-DEPLOY-004',
            category: 'INPUT_ERROR',
            message: `Deployment not found: ${input.deployment_id}`,
            details: { deployment_id: input.deployment_id },
            module: 'deploy',
            correlationId,
            recoverable: false,
            exitCode: DEPLOY_EXIT_CODES.NOT_FOUND,
        });
    }
    // Check if deployment can be run
    if (record.status !== 'previewed' && record.status !== 'pending') {
        throw new CLIError({
            code: 'ECLI-DEPLOY-005',
            category: 'INPUT_ERROR',
            message: `Deployment cannot be run in status: ${record.status}`,
            details: { deployment_id: input.deployment_id, current_status: record.status },
            module: 'deploy',
            correlationId,
            recoverable: false,
            exitCode: DEPLOY_EXIT_CODES.INPUT_ERROR,
        });
    }
    // Execute deployment via downstream service
    const now = new Date().toISOString();
    const stepsTotal = record.preview?.changes.length ?? 4;
    record.status = 'running';
    record.execution = {
        started_at: now,
        completed_at: null,
        steps_completed: 0,
        steps_total: stepsTotal,
        advisory: false,
        logs: [
            `[${now}] Deployment execution started`,
            `[${now}] Validating configuration...`,
        ],
    };
    record.updated_at = now;
    record.version += 1;
    // Execute via deployment intent service
    try {
        const intentConfig = loadEndpointConfig('agentics-deployment-intent');
        const intentAdapter = new IntentAdapter(intentConfig, correlationId);
        const engine = createOrchestrationEngine(correlationId);
        const stages = [
            {
                name: 'execute-deployment',
                adapter: intentAdapter,
                request: {
                    endpoint: '/v1/intent/execute',
                    method: 'POST',
                    buildBody: () => ({
                        deployment_id: record.id,
                        target_id: record.target_id,
                        environment: record.environment,
                        changes: record.preview?.changes ?? [],
                    }),
                },
            },
        ];
        const result = await engine.execute(stages, options);
        const completedAt = new Date().toISOString();
        record.status = result.success ? 'completed' : 'failed';
        record.execution.completed_at = completedAt;
        record.execution.steps_completed = stepsTotal;
        record.execution.logs.push(`[${completedAt}] Applying changes...`, `[${completedAt}] Verifying deployment...`, `[${completedAt}] Deployment ${result.success ? 'completed successfully' : 'failed'}`);
    }
    catch (error) {
        const failedAt = new Date().toISOString();
        record.status = 'failed';
        record.execution.completed_at = failedAt;
        record.execution.logs.push(`[${failedAt}] Deployment failed: ${error instanceof Error ? error.message : String(error)}`);
    }
    record.updated_at = new Date().toISOString();
    record.version += 1;
    // Save updated record to Ruvector
    try {
        await ruvectorAdapter.updateDeployment(input.deployment_id, {
            status: record.status,
            execution: record.execution,
            updated_at: record.updated_at,
            version: record.version,
        });
    }
    catch (error) {
        throw new CLIError({
            code: 'ECLI-DEPLOY-006',
            category: 'INTERNAL_ERROR',
            message: `Failed to update deployment: ${error instanceof Error ? error.message : 'Unknown error'}`,
            details: { deployment_id: input.deployment_id },
            module: 'deploy',
            correlationId,
            recoverable: false,
            exitCode: DEPLOY_EXIT_CODES.IO_ERROR,
        });
    }
    return {
        result: record,
        advisory: false,
        timing: Date.now() - startTime,
    };
}
// ============================================================================
// Deploy Commands - Status (Ruvector Storage)
// ============================================================================
export async function executeDeployStatusCommand(input, options) {
    const correlationId = options.trace_id ?? crypto.randomUUID();
    const startTime = Date.now();
    // Validate input
    validateDeploymentId(input.deployment_id, correlationId);
    // Load deployment from Ruvector
    const ruvectorAdapter = createRuvectorAdapter(correlationId);
    let record = null;
    try {
        const response = await ruvectorAdapter.getDeployment(input.deployment_id);
        if (response.status === 200 && response.body) {
            record = response.body;
        }
    }
    catch {
        // Deployment not found or service error - return null
        record = null;
    }
    return {
        result: record,
        found: record !== null,
        timing: Date.now() - startTime,
    };
}
// ============================================================================
// Deploy Commands - Rollback (Ruvector Storage)
// ============================================================================
export async function executeDeployRollbackCommand(input, options) {
    const correlationId = options.trace_id ?? crypto.randomUUID();
    const startTime = Date.now();
    // Validate input
    validateDeploymentId(input.deployment_id, correlationId);
    // Load existing deployment from Ruvector
    const ruvectorAdapter = createRuvectorAdapter(correlationId);
    let record = null;
    try {
        const response = await ruvectorAdapter.getDeployment(input.deployment_id);
        if (response.status === 200 && response.body) {
            record = response.body;
        }
    }
    catch (error) {
        // Check if this is a 404 (not found) error
        if (error instanceof Error && error.message.includes('404')) {
            record = null;
        }
        else {
            throw new CLIError({
                code: 'ECLI-DEPLOY-012',
                category: 'INTERNAL_ERROR',
                message: `Failed to retrieve deployment: ${error instanceof Error ? error.message : 'Unknown error'}`,
                details: { deployment_id: input.deployment_id },
                module: 'deploy',
                correlationId,
                recoverable: false,
                exitCode: DEPLOY_EXIT_CODES.IO_ERROR,
            });
        }
    }
    if (!record) {
        throw new CLIError({
            code: 'ECLI-DEPLOY-007',
            category: 'INPUT_ERROR',
            message: `Deployment not found: ${input.deployment_id}`,
            details: { deployment_id: input.deployment_id },
            module: 'deploy',
            correlationId,
            recoverable: false,
            exitCode: DEPLOY_EXIT_CODES.NOT_FOUND,
        });
    }
    // Check if deployment can be rolled back
    if (record.status === 'rolled_back') {
        throw new CLIError({
            code: 'ECLI-DEPLOY-008',
            category: 'INPUT_ERROR',
            message: 'Deployment is already rolled back',
            details: { deployment_id: input.deployment_id, current_status: record.status },
            module: 'deploy',
            correlationId,
            recoverable: false,
            exitCode: DEPLOY_EXIT_CODES.INPUT_ERROR,
        });
    }
    if (record.status !== 'completed' && record.status !== 'failed') {
        throw new CLIError({
            code: 'ECLI-DEPLOY-009',
            category: 'INPUT_ERROR',
            message: `Deployment cannot be rolled back in status: ${record.status}`,
            details: { deployment_id: input.deployment_id, current_status: record.status },
            module: 'deploy',
            correlationId,
            recoverable: false,
            exitCode: DEPLOY_EXIT_CODES.INPUT_ERROR,
        });
    }
    // Execute rollback via downstream service
    const now = new Date().toISOString();
    record.status = 'rolled_back';
    if (record.execution) {
        record.execution.logs.push(`[${now}] Rollback initiated`);
    }
    // Execute rollback via deployment intent service
    try {
        const intentConfig = loadEndpointConfig('agentics-deployment-intent');
        const intentAdapter = new IntentAdapter(intentConfig, correlationId);
        const engine = createOrchestrationEngine(correlationId);
        const rollbackStages = [
            {
                name: 'execute-rollback',
                adapter: intentAdapter,
                request: {
                    endpoint: '/v1/intent/rollback',
                    method: 'POST',
                    buildBody: () => ({
                        deployment_id: record.id,
                        target_id: record.target_id,
                        environment: record.environment,
                    }),
                },
            },
        ];
        await engine.execute(rollbackStages, options);
        if (record.execution) {
            record.execution.logs.push(`[${new Date().toISOString()}] Reverting changes...`, `[${new Date().toISOString()}] Rollback completed successfully`);
        }
    }
    catch (error) {
        if (record.execution) {
            record.execution.logs.push(`[${new Date().toISOString()}] Rollback failed: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    record.updated_at = new Date().toISOString();
    record.version += 1;
    // Save updated record to Ruvector
    try {
        await ruvectorAdapter.updateDeployment(input.deployment_id, {
            status: record.status,
            execution: record.execution,
            updated_at: record.updated_at,
            version: record.version,
        });
    }
    catch (error) {
        throw new CLIError({
            code: 'ECLI-DEPLOY-010',
            category: 'INTERNAL_ERROR',
            message: `Failed to update deployment: ${error instanceof Error ? error.message : 'Unknown error'}`,
            details: { deployment_id: input.deployment_id },
            module: 'deploy',
            correlationId,
            recoverable: false,
            exitCode: DEPLOY_EXIT_CODES.IO_ERROR,
        });
    }
    return {
        result: record,
        advisory: false,
        timing: Date.now() - startTime,
    };
}
// ============================================================================
// Deploy Commands - List (Ruvector Storage)
// ============================================================================
export async function executeDeployListCommand(options) {
    const correlationId = options.trace_id ?? crypto.randomUUID();
    const startTime = Date.now();
    // List deployments from Ruvector
    const ruvectorAdapter = createRuvectorAdapter(correlationId);
    let items = [];
    try {
        const response = await ruvectorAdapter.listDeployments({ limit: 100 });
        if (response.status === 200 && response.body) {
            const body = response.body;
            if (Array.isArray(body)) {
                items = body;
            }
            else if (body.data && Array.isArray(body.data)) {
                items = body.data;
            }
            else if (body.items && Array.isArray(body.items)) {
                items = body.items;
            }
        }
    }
    catch {
        // Service error - return empty list
        items = [];
    }
    // Sort by created_at descending
    items.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
    return {
        items,
        count: items.length,
        timing: Date.now() - startTime,
    };
}
//# sourceMappingURL=deploy.js.map