/**
 * Deployment Verification Scanner
 *
 * Orchestrates deployment verification including health checks,
 * smoke tests, and canary analysis.
 *
 * @module scanners/deploy
 */
import { readFile, mkdir, writeFile } from "fs/promises";
import { join } from "path";
import { parse as parseYaml } from "yaml";
import { logger } from "../../logger.js";
import { detectProvider } from "./provider-detector.js";
import { checkAllHealth, runAllSmokeTests, calculateHealthScore, calculateSmokeTestScore, } from "./health-checker.js";
import { isVercelAvailable, getLatestDeployment, analyzeCanary, } from "./vercel-integration.js";
import { DeployConfigSchema, } from "./types.js";
export * from "./types.js";
export { detectProvider, isDeploymentEnvironment, } from "./provider-detector.js";
export { checkAllHealth, runAllSmokeTests, calculateHealthScore, calculateSmokeTestScore, } from "./health-checker.js";
export { isVercelAvailable, getLatestDeployment, getDeployment, listDeployments, promoteToProduction, rollback, analyzeCanary, } from "./vercel-integration.js";
const CONFIG_PATH = ".vaspera/deploy.yaml";
/**
 * Load deployment config
 */
export async function loadDeployConfig(projectPath) {
    try {
        const configPath = join(projectPath, CONFIG_PATH);
        const content = await readFile(configPath, "utf-8");
        const parsed = parseYaml(content);
        return DeployConfigSchema.parse(parsed);
    }
    catch {
        return null;
    }
}
/**
 * Generate sample deploy config
 */
export async function generateDeployConfig(projectPath, provider) {
    const configDir = join(projectPath, ".vaspera");
    await mkdir(configDir, { recursive: true });
    const config = `# Deployment Verification Configuration
# This file configures health checks, smoke tests, and canary deployment

${provider ? `provider: ${provider}` : "# provider: vercel  # Auto-detected if not specified"}

# Endpoints to check for health
healthEndpoints:
  - /
  - /api/health

# Smoke tests to run after deployment
smokeTests:
  - name: "Homepage loads"
    endpoint: "/"
    method: GET
    expectedStatus: 200

  - name: "API health check"
    endpoint: "/api/health"
    method: GET
    expectedStatus: 200
    assertions:
      - type: latency
        operator: lt
        value: 500

  # Add your critical path tests:
  # - name: "User can login"
  #   endpoint: "/api/auth/login"
  #   method: POST
  #   expectedStatus: 200
  #   body:
  #     email: "test@example.com"
  #     password: "testpass"

# Canary deployment settings (for supported providers)
canary:
  enabled: false
  trafficPercent: 10
  duration: "10m"
  thresholds:
    errorRate: 0.01
    p95Latency: 500
    healthCheckFailures: 2
  rollbackOnFailure: true

# Rollback settings
rollback:
  autoRollback: true
  retainVersions: 5

# Optional notifications
# notifications:
#   slack: "https://hooks.slack.com/..."
#   email:
#     - team@example.com
`;
    const configPath = join(configDir, "deploy.yaml");
    await writeFile(configPath, config, "utf-8");
    logger.info("deploy.config_generated", { path: configPath });
    return configPath;
}
/**
 * Run deployment verification
 */
export async function runDeployVerification(projectPath, deploymentUrl, options = {}) {
    const startTime = Date.now();
    logger.info("deploy.verification_started", { projectPath, deploymentUrl });
    // Detect provider
    const providerDetection = await detectProvider(projectPath);
    // Load config
    const config = await loadDeployConfig(projectPath);
    const healthEndpoints = config?.healthEndpoints || ["/", "/api/health"];
    const smokeTests = config?.smokeTests || [];
    // Run health checks
    let healthResults = [];
    if (!options.skipHealthCheck) {
        healthResults = await checkAllHealth(deploymentUrl, healthEndpoints);
    }
    // Run smoke tests
    let smokeTestResults = [];
    if (!options.skipSmokeTests && smokeTests.length > 0) {
        smokeTestResults = await runAllSmokeTests(deploymentUrl, smokeTests);
    }
    // Run canary analysis if requested
    let canaryResult;
    if (options.runCanary) {
        canaryResult = await analyzeCanary(deploymentUrl, {
            duration: options.canaryDuration || 60000,
        });
    }
    // Calculate scores
    const healthScore = calculateHealthScore(healthResults);
    const smokeTestScore = smokeTests.length > 0
        ? calculateSmokeTestScore(smokeTestResults)
        : 50; // Neutral if no tests
    const canaryScore = canaryResult
        ? (canaryResult.thresholdsPassed ? 100 : 30)
        : 50; // Neutral if no canary
    const overallScore = Math.round((healthScore * 0.4) + (smokeTestScore * 0.4) + (canaryScore * 0.2));
    // Get deployment info if Vercel
    let deployment;
    if (providerDetection.provider === "vercel" && isVercelAvailable() && providerDetection.projectId) {
        deployment = await getLatestDeployment(providerDetection.projectId) || undefined;
    }
    const result = {
        success: overallScore >= 70,
        provider: providerDetection.provider,
        deployment,
        healthChecks: healthResults,
        smokeTests: smokeTestResults,
        canary: canaryResult,
        score: {
            healthScore,
            smokeTestScore,
            canaryScore,
            overallScore,
        },
        duration: Date.now() - startTime,
    };
    logger.info("deploy.verification_completed", {
        success: result.success,
        overallScore,
        healthScore,
        smokeTestScore,
        canaryScore,
        duration: result.duration,
    });
    return result;
}
/**
 * Quick health check (no smoke tests or canary)
 */
export async function quickDeployCheck(deploymentUrl, endpoints = ["/", "/api/health"]) {
    const checks = await checkAllHealth(deploymentUrl, endpoints);
    const score = calculateHealthScore(checks);
    return {
        healthy: score >= 70,
        score,
        checks,
    };
}
/**
 * Create default smoke tests from OpenAPI/routes
 */
export function createDefaultSmokeTests() {
    return [
        {
            name: "Homepage loads",
            endpoint: "/",
            method: "GET",
            expectedStatus: 200,
            timeout: 10000,
        },
        {
            name: "Health endpoint",
            endpoint: "/api/health",
            method: "GET",
            expectedStatus: 200,
            timeout: 10000,
            assertions: [
                { type: "latency", operator: "lt", value: 500 },
            ],
        },
    ];
}
//# sourceMappingURL=index.js.map