/**
 * Phase 6 — Stage 4: Deployment Finalization
 *
 * Generates production-ready deployment scripts:
 * - deploy.sh (gcloud CLI commands)
 * - teardown.sh (cleanup script)
 * - env.template (Secret Manager references)
 * - vpc-setup.sh (VPC connector for ERP network)
 * - monitoring.yaml (Cloud Monitoring alert policies)
 *
 * References infra repo patterns for IAM/networking.
 * References integrations repo for webhook/event patterns.
 */
import * as fs from 'node:fs';
import * as path from 'node:path';
import { writeFileSync, mkdirSync, existsSync } from 'node:fs';
import { join } from 'node:path';
import { createSpan, endSpan, emitSpan } from '../../phase2/telemetry.js';
// ============================================================================
// Constants
// ============================================================================
const DIR_MODE = 0o700;
const FILE_MODE = 0o600;
const EXEC_MODE = 0o700;
const SCRIPT_HEADER = [
    '#!/usr/bin/env bash',
    '# Generated by Phase 6 pipeline — do not edit manually',
    '#',
    '# This script is deterministic and idempotent.',
    '',
    'set -euo pipefail',
    '',
].join('\n');
function deriveDeploymentVars(context) {
    const registrationStage = context.stageOutputs.get('service-registration');
    let serviceName = 'erp-service';
    let serviceAccount = 'erp-service-sa@PROJECT_ID.iam.gserviceaccount.com';
    let vpcConnector = 'sap-connector';
    let erpAuthScheme = 'api-key';
    let erpSecretNames = ['erp-api-key'];
    let erpEnvVars = ['ERP_BASE_URL', 'ERP_API_KEY'];
    if (registrationStage?.status === 'completed' && registrationStage.data) {
        const data = registrationStage.data;
        const registration = data['registration'];
        if (registration) {
            serviceName = registration['service_name'] ?? serviceName;
            const vpcConfig = registration['vpc_config'];
            if (vpcConfig)
                vpcConnector = vpcConfig['connector_name'] ?? vpcConnector;
            const iamConfig = registration['iam_config'];
            if (iamConfig)
                serviceAccount = iamConfig['service_account'] ?? serviceAccount;
            if (registration['auth_scheme'])
                erpAuthScheme = registration['auth_scheme'];
            if (registration['erp_secret_names'])
                erpSecretNames = registration['erp_secret_names'];
            if (registration['erp_env_vars'])
                erpEnvVars = registration['erp_env_vars'];
        }
    }
    return { serviceName, region: 'us-central1', serviceAccount, vpcConnector, erpAuthScheme, erpSecretNames, erpEnvVars };
}
// ============================================================================
// Script Generators
// ============================================================================
function generateDeployScript(vars, erpSystem) {
    // Build ERP-specific secrets string for --set-secrets
    const secretMappings = vars.erpSecretNames
        .map(name => {
        const envKey = name.toUpperCase().replace(/[^A-Z0-9]/g, '_');
        return `${envKey}=${name}:latest`;
    })
        .join(',');
    return [
        SCRIPT_HEADER,
        `# Deploy ${vars.serviceName} to Cloud Run`,
        `# ERP System: ${erpSystem}`,
        `# Auth Scheme: ${vars.erpAuthScheme}`,
        '',
        'GCP_PROJECT_ID=${GCP_PROJECT_ID:?ERROR: GCP_PROJECT_ID must be set}',
        `GCP_REGION="\${GCP_REGION:-${vars.region}}"`,
        `SERVICE_NAME="\${SERVICE_NAME:-${vars.serviceName}}"`,
        'IMAGE_TAG="${IMAGE_TAG:-latest}"',
        'IMAGE_URL="gcr.io/${GCP_PROJECT_ID}/${SERVICE_NAME}:${IMAGE_TAG}"',
        `SERVICE_ACCOUNT="\${SERVICE_ACCOUNT:-${vars.serviceAccount}}"`,
        `VPC_CONNECTOR="\${VPC_CONNECTOR:-${vars.vpcConnector}}"`,
        '',
        'echo "[1/5] Checking GCP authentication..."',
        'gcloud auth print-identity-token > /dev/null 2>&1 || { echo "Not authenticated."; exit 1; }',
        '',
        'echo "[2/5] Setting project..."',
        'gcloud config set project "${GCP_PROJECT_ID}"',
        '',
        'echo "[3/5] Building container image..."',
        'gcloud builds submit --tag "${IMAGE_URL}" --timeout=600s .',
        '',
        'echo "[4/5] Deploying to Cloud Run..."',
        'gcloud run deploy "${SERVICE_NAME}" \\',
        '  --image "${IMAGE_URL}" \\',
        '  --region "${GCP_REGION}" \\',
        '  --platform managed \\',
        '  --no-allow-unauthenticated \\',
        '  --vpc-connector "${VPC_CONNECTOR}" \\',
        '  --vpc-egress all-traffic \\',
        '  --service-account "${SERVICE_ACCOUNT}" \\',
        ...(secretMappings ? [`  --set-secrets "${secretMappings}" \\`] : []),
        `  --set-env-vars "NODE_ENV=production,PORT=8080,ERP_SYSTEM=${erpSystem}" \\`,
        '  --min-instances 0 --max-instances 10 \\',
        '  --memory 512Mi --cpu 1 --timeout 300 --concurrency 80 \\',
        '  --ingress internal-and-cloud-load-balancing --quiet',
        '',
        'echo "[5/5] Verifying deployment..."',
        'SERVICE_URL=$(gcloud run services describe "${SERVICE_NAME}" --region "${GCP_REGION}" --format "value(status.url)")',
        'echo "Deployed: ${SERVICE_URL}"',
        '',
    ].join('\n');
}
function generateTeardownScript(vars) {
    return [
        SCRIPT_HEADER,
        `# Teardown ${vars.serviceName}`,
        '',
        'GCP_PROJECT_ID=${GCP_PROJECT_ID:?ERROR: GCP_PROJECT_ID must be set}',
        `GCP_REGION="\${GCP_REGION:-${vars.region}}"`,
        `SERVICE_NAME="\${SERVICE_NAME:-${vars.serviceName}}"`,
        '',
        'read -rp "Are you sure you want to delete ${SERVICE_NAME}? (y/N): " CONFIRM',
        'if [[ "${CONFIRM}" != "y" && "${CONFIRM}" != "Y" ]]; then echo "Cancelled."; exit 0; fi',
        '',
        'echo "[1/3] Deleting Cloud Run service..."',
        'gcloud run services delete "${SERVICE_NAME}" --region "${GCP_REGION}" --quiet 2>/dev/null || echo "  Not found."',
        '',
        'echo "[2/3] Cleaning container images..."',
        'gcloud container images list-tags "gcr.io/${GCP_PROJECT_ID}/${SERVICE_NAME}" --format="get(digest)" 2>/dev/null | while read -r DIGEST; do',
        '  gcloud container images delete "gcr.io/${GCP_PROJECT_ID}/${SERVICE_NAME}@${DIGEST}" --quiet --force-delete-tags 2>/dev/null || true',
        'done',
        '',
        'echo "[3/3] Done."',
        '',
    ].join('\n');
}
function generateEnvTemplate(vars, erpSystem) {
    const lines = [
        '# Generated by Phase 6 pipeline',
        `# ERP System: ${erpSystem}`,
        `# Auth Scheme: ${vars.erpAuthScheme}`,
        '',
        `GCP_REGION=${vars.region}`,
        `SERVICE_NAME=${vars.serviceName}`,
        `SERVICE_ACCOUNT=${vars.serviceAccount}`,
        'PORT=8080',
        'NODE_ENV=production',
        `ERP_SYSTEM=${erpSystem}`,
        `VPC_CONNECTOR=${vars.vpcConnector}`,
        '',
        '# ERP-specific environment variables',
    ];
    for (const envVar of vars.erpEnvVars) {
        lines.push(`${envVar}=`);
    }
    // Add secret references for each ERP secret
    lines.push('');
    lines.push('# Secret Manager references');
    for (const secretName of vars.erpSecretNames) {
        const envKey = secretName.toUpperCase().replace(/[^A-Z0-9]/g, '_');
        lines.push(`${envKey}=projects/\${GCP_PROJECT_ID}/secrets/${secretName}/versions/latest`);
    }
    lines.push('');
    return lines.join('\n');
}
function generateVpcSetupScript(vars, infraRepoPath) {
    let infraNote = '';
    if (infraRepoPath) {
        infraNote = `# Follows patterns from: ${infraRepoPath}/modules/networking/\n`;
    }
    return [
        SCRIPT_HEADER,
        `# VPC Connector Setup for ${vars.serviceName}`,
        infraNote,
        'GCP_PROJECT_ID=${GCP_PROJECT_ID:?ERROR: GCP_PROJECT_ID must be set}',
        `GCP_REGION="\${GCP_REGION:-${vars.region}}"`,
        `VPC_CONNECTOR="\${VPC_CONNECTOR:-${vars.vpcConnector}}"`,
        '',
        'gcloud services enable vpcaccess.googleapis.com --project "${GCP_PROJECT_ID}" --quiet',
        'gcloud compute networks vpc-access connectors create "${VPC_CONNECTOR}" \\',
        '  --region "${GCP_REGION}" --network default --range 10.8.0.0/28 \\',
        '  --min-instances 2 --max-instances 10 --machine-type e2-micro \\',
        '  --quiet 2>/dev/null || echo "VPC connector already exists."',
        '',
        'echo "VPC setup complete: ${VPC_CONNECTOR}"',
        '',
    ].join('\n');
}
function generateMonitoringYaml(vars) {
    const sn = vars.serviceName;
    return [
        '# Generated by Phase 6 pipeline',
        `# Alert policies for ${sn}`,
        '',
        'alertPolicies:',
        `  - displayName: "[${sn}] High Error Rate"`,
        '    conditions:',
        '      - displayName: "5xx > 5%"',
        '        conditionThreshold:',
        `          filter: resource.labels.service_name="${sn}" AND metric.labels.response_code_class="5xx"`,
        '          comparison: COMPARISON_GT',
        '          thresholdValue: 0.05',
        '          duration: 300s',
        '',
        `  - displayName: "[${sn}] Elevated Latency"`,
        '    conditions:',
        '      - displayName: "p99 > 5s"',
        '        conditionThreshold:',
        `          filter: resource.labels.service_name="${sn}"`,
        '          comparison: COMPARISON_GT',
        '          thresholdValue: 5000',
        '          duration: 300s',
        '',
    ].join('\n');
}
// ============================================================================
// File writers
// ============================================================================
function writeScript(absPath, content) {
    writeFileSync(absPath, content, { encoding: 'utf-8', mode: EXEC_MODE });
}
function writeArtifact(absPath, content) {
    writeFileSync(absPath, content, { encoding: 'utf-8', mode: FILE_MODE });
}
function resolveInfraRepoPath(platformRepoPaths) {
    const infraPath = platformRepoPaths['infra'];
    if (!infraPath || !existsSync(infraPath))
        return undefined;
    return infraPath;
}
// ============================================================================
// README Generator
// ============================================================================
function generateReadme(vars, erpSystem, context) {
    const serviceName = vars.serviceName;
    const serviceNameUpper = serviceName.replace(/-/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
    const scenario = context.scenarioQuery ?? '';
    // ── Load ADRs and DDD model from pipeline artifacts for solution description ──
    const runDir = path.dirname(context.phase6Dir);
    let adrs = [];
    let dddContexts = [];
    // Load ADRs
    for (const candidate of ['phase4/adrs/adr-index.json', 'phase2/adrs/adr-index.json']) {
        const p = path.join(runDir, candidate);
        if (fs.existsSync(p)) {
            try {
                adrs = JSON.parse(fs.readFileSync(p, 'utf-8'));
                break;
            }
            catch { /* skip */ }
        }
    }
    // Load DDD model
    for (const candidate of ['phase4/ddd/domain-model.json', 'phase2/ddd/domain-model.json']) {
        const p = path.join(runDir, candidate);
        if (fs.existsSync(p)) {
            try {
                const model = JSON.parse(fs.readFileSync(p, 'utf-8'));
                dddContexts = model.contexts ?? [];
                break;
            }
            catch { /* skip */ }
        }
    }
    // ── Extract a meaningful description from the scenario query ──
    // Take the first ~3 sentences that describe the problem/solution, skip preamble
    const scenarioDescription = extractSolutionDescription(scenario);
    const lines = [];
    // Title and badges
    lines.push(`# ${serviceNameUpper}`, '', `![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue.svg)`, `![ERP](https://img.shields.io/badge/ERP-${encodeURIComponent(erpSystem)}-orange.svg)`, `![Generated](https://img.shields.io/badge/generated_by-Agentics_Pipeline-blueviolet.svg)`, '');
    // Overview — use the actual scenario context
    lines.push('## Overview', '');
    if (scenarioDescription) {
        lines.push(scenarioDescription, '');
    }
    else {
        lines.push(`**${serviceNameUpper}** — an enterprise service integrating with **${erpSystem}**.`, '');
    }
    lines.push(`This service was generated by the Agentics CLI pipeline using SPARC methodology, domain-driven design, and London School TDD.`, '');
    // Key Architecture Decisions (from actual ADRs)
    if (adrs.length > 0) {
        lines.push('## Key Architecture Decisions', '');
        for (const adr of adrs.slice(0, 10)) {
            lines.push(`- **${adr.title}** — ${adr.decision?.slice(0, 200) ?? adr.context?.slice(0, 200) ?? 'See ADR document'}`);
        }
        lines.push('', `> Full ADR documentation in \`.agentics/plans/adrs/\``, '');
    }
    // Domain Model (from actual DDD bounded contexts)
    if (dddContexts.length > 0) {
        lines.push('## Domain Model', '');
        lines.push(`The system is organized into **${dddContexts.length} bounded contexts**:`, '');
        for (const ctx of dddContexts) {
            const details = [];
            if (ctx.aggregates?.length)
                details.push(`${ctx.aggregates.length} aggregates`);
            if (ctx.commands?.length)
                details.push(`${ctx.commands.length} commands`);
            if (ctx.queries?.length)
                details.push(`${ctx.queries.length} queries`);
            if (ctx.domainEvents?.length)
                details.push(`${ctx.domainEvents.length} events`);
            const detailStr = details.length > 0 ? ` (${details.join(', ')})` : '';
            lines.push(`### ${ctx.name}${detailStr}`, '');
            if (ctx.description)
                lines.push(ctx.description, '');
        }
    }
    // Project structure
    lines.push('## Project Structure', '', '```', 'src/                       # Application source code', 'backend/                   # Backend services and API', 'frontend/                  # Frontend application', 'erp/                       # ERP integration layer', 'integrations/              # External system connectors', 'plans/                     # SPARC specs, ADRs, implementation prompts', 'docs/                      # Project documentation', 'tests/                     # Unit and integration tests', '```', '');
    // Quick Start
    lines.push('## Quick Start', '', '```bash', 'npm install', 'npm run build', 'npm start', '```', '');
    // API Endpoints — only show a summary, not 60 rows of [object Object]
    const registrationStage = context.stageOutputs.get('service-registration');
    const registration = registrationStage?.data;
    const registrationData = registration?.['registration'];
    const rawEndpoints = (registrationData?.['endpoints'] ?? []);
    const endpoints = rawEndpoints.map(ep => {
        if (typeof ep === 'string')
            return { method: 'POST', path: ep, erp_service: '' };
        return { method: ep.method ?? 'POST', path: ep.path ?? String(ep), erp_service: ep.erp_service ?? '' };
    });
    lines.push('## API Endpoints', '', '| Method | Path | Description |', '|--------|------|-------------|');
    lines.push('| GET | `/health` | Health check and readiness probe |');
    if (endpoints.length > 0 && endpoints.length <= 20) {
        for (const ep of endpoints) {
            lines.push(`| ${ep.method} | \`${ep.path}\` | ${ep.erp_service ? `${ep.erp_service} endpoint` : 'Domain endpoint'} |`);
        }
    }
    else if (endpoints.length > 20) {
        // Too many endpoints — show summary instead of a wall of rows
        for (const ep of endpoints.slice(0, 10)) {
            lines.push(`| ${ep.method} | \`${ep.path}\` | ${ep.erp_service ? `${ep.erp_service} endpoint` : 'Domain endpoint'} |`);
        }
        lines.push(`| ... | ... | *${endpoints.length - 10} more endpoints — see route definitions* |`);
    }
    else {
        lines.push('| POST | `/api/commands/:command` | Execute domain command |');
        lines.push('| GET | `/api/queries/:query` | Execute domain query |');
    }
    lines.push('');
    // ERP Integration
    lines.push('## ERP Integration', '', `| Property | Value |`, `|----------|-------|`, `| ERP System | ${erpSystem} |`, `| Auth Scheme | ${vars.erpAuthScheme} |`, `| Region | ${vars.region} |`, '');
    // Environment Variables
    lines.push('## Environment Variables', '', '| Variable | Description | Required |', '|----------|-------------|----------|');
    lines.push('| `PORT` | Server port (default: 8080) | No |');
    lines.push('| `NODE_ENV` | Environment (production/development) | Yes |');
    lines.push(`| \`ERP_SYSTEM\` | ERP system identifier (${erpSystem}) | Yes |`);
    for (const v of vars.erpEnvVars) {
        lines.push(`| \`${v}\` | ERP connection variable | Yes |`);
    }
    lines.push('');
    // Deployment
    lines.push('## Deployment', '', '```bash', `docker build -t ${serviceName} .`, `docker run -p 8080:8080 --env-file .env ${serviceName}`, '```', '');
    // Testing
    lines.push('## Testing', '', '```bash', 'npm test              # Run all tests', 'npm run test:coverage # With coverage', '```', '');
    // Footer
    lines.push('---', '', `*Generated on ${new Date().toISOString().split('T')[0]} by [Agentics CLI](https://platform.agentics.dev)*`, '', '> Pipeline documentation: `.agentics/plans/`', '');
    return lines.join('\n');
}
/**
 * Extract a meaningful solution description from the scenario query.
 * Skips "I lead..." / "We are..." preamble and finds the sentences that
 * describe what the system should actually do.
 */
function extractSolutionDescription(scenario) {
    if (!scenario)
        return '';
    const sentences = scenario
        .replace(/\n+/g, ' ')
        .split(/(?<=[.!?])\s+/)
        .filter(s => s.trim().length > 10);
    // Skip sentences that are preamble (first-person context, company description)
    const preamblePatterns = [
        /^I\s+(lead|manage|am|work|run)\b/i,
        /^We\s+(are|have|believe|face|collect|want)\b/i,
        /^Our\s+(finance|company|team|org)/i,
        /^One\s+of\s+the\s+biggest/i,
        /^Today,?\s+these/i,
        /^However,?\s/i,
        /^If\s+viable/i,
        /^If\s+this\s+concept/i,
        /^Because\s+these/i,
        /^Rather\s+than/i,
        /^This\s+should\s+be\s+implemented/i,
    ];
    // Find sentences that describe what the system should do
    const systemPatterns = [
        /system\s+should/i,
        /AI\s+could/i,
        /model\s+the/i,
        /simulate/i,
        /quantif/i,
        /recommend/i,
        /evaluat/i,
        /optim/i,
        /prototype\s+that/i,
        /produce\s+structured/i,
        /dynamically/i,
    ];
    // Collect good descriptive sentences
    const goodSentences = [];
    for (const s of sentences) {
        const isPreamble = preamblePatterns.some(p => p.test(s.trim()));
        const isSystem = systemPatterns.some(p => p.test(s));
        if (isSystem && !isPreamble) {
            goodSentences.push(s.trim());
        }
        if (goodSentences.length >= 4)
            break;
    }
    // If we found system-describing sentences, use them
    if (goodSentences.length > 0) {
        return goodSentences.join(' ');
    }
    // Fallback: skip first 2 preamble sentences, take next 3
    const nonPreamble = sentences.filter(s => !preamblePatterns.some(p => p.test(s.trim())));
    return nonPreamble.slice(0, 3).join(' ').slice(0, 800);
}
// ============================================================================
// Main: finalizeDeployment
// ============================================================================
/**
 * Stage 4: Generate production-ready deployment scripts.
 *
 * @param context - The mutable Phase 6 pipeline context
 * @returns Stage output describing success or failure
 */
export function finalizeDeployment(context) {
    const startTime = Date.now();
    const rootSpan = createSpan('deployment-finalization', 'finalize-deployment', {
        phase6Dir: context.phase6Dir,
        erpSystem: context.phase5Artifacts.erpSystem,
    });
    try {
        const vars = deriveDeploymentVars(context);
        const erpSystem = context.phase5Artifacts.erpSystem;
        const infraRepoPath = resolveInfraRepoPath(context.platformRepoPaths);
        const varsSpan = createSpan('deployment-finalization', 'derive-vars', {}, rootSpan.spanId);
        const finalVarsSpan = endSpan(varsSpan, 'ok', {
            serviceName: vars.serviceName, hasInfraRepo: infraRepoPath !== undefined,
        });
        emitSpan(finalVarsSpan);
        context.telemetrySpans.push(finalVarsSpan);
        const deployDir = join(context.phase6Dir, 'deploy');
        mkdirSync(deployDir, { recursive: true, mode: DIR_MODE });
        const writtenPaths = [];
        const genSpan = createSpan('deployment-finalization', 'generate-scripts', { deployDir }, rootSpan.spanId);
        writeScript(join(deployDir, 'deploy.sh'), generateDeployScript(vars, erpSystem));
        writtenPaths.push(join(deployDir, 'deploy.sh'));
        writeScript(join(deployDir, 'teardown.sh'), generateTeardownScript(vars));
        writtenPaths.push(join(deployDir, 'teardown.sh'));
        writeArtifact(join(deployDir, 'env.template'), generateEnvTemplate(vars, erpSystem));
        writtenPaths.push(join(deployDir, 'env.template'));
        writeScript(join(deployDir, 'vpc-setup.sh'), generateVpcSetupScript(vars, infraRepoPath));
        writtenPaths.push(join(deployDir, 'vpc-setup.sh'));
        writeArtifact(join(deployDir, 'monitoring.yaml'), generateMonitoringYaml(vars));
        writtenPaths.push(join(deployDir, 'monitoring.yaml'));
        // Generate enterprise README.md for the project root
        const projectDir = join(context.phase6Dir, 'project');
        if (existsSync(projectDir)) {
            const readmeContent = generateReadme(vars, erpSystem, context);
            writeArtifact(join(projectDir, 'README.md'), readmeContent);
            writtenPaths.push(join(projectDir, 'README.md'));
        }
        const finalGenSpan = endSpan(genSpan, 'ok', { filesGenerated: writtenPaths.length });
        emitSpan(finalGenSpan);
        context.telemetrySpans.push(finalGenSpan);
        const finalRootSpan = endSpan(rootSpan, 'ok', {
            serviceName: vars.serviceName, erpSystem, filesGenerated: writtenPaths.length,
        });
        emitSpan(finalRootSpan);
        context.telemetrySpans.push(finalRootSpan);
        const timing = Date.now() - startTime;
        const output = {
            stage: 'deployment-finalization',
            status: 'completed',
            data: {
                deployDir, serviceName: vars.serviceName, region: vars.region,
                vpcConnector: vars.vpcConnector, filesGenerated: writtenPaths.length,
            },
            artifacts: writtenPaths,
            timing,
        };
        context.stageOutputs.set('deployment-finalization', output);
        return output;
    }
    catch (err) {
        const errorMessage = err instanceof Error ? err.message : String(err);
        const finalRootSpan = endSpan(rootSpan, 'error', { error: errorMessage });
        emitSpan(finalRootSpan);
        context.telemetrySpans.push(finalRootSpan);
        const timing = Date.now() - startTime;
        const output = {
            stage: 'deployment-finalization',
            status: 'failed',
            data: { error: errorMessage },
            artifacts: [],
            timing,
        };
        context.stageOutputs.set('deployment-finalization', output);
        return output;
    }
}
//# sourceMappingURL=deployment-finalizer.js.map