/**
 * Vercel Integration
 *
 * Integration with Vercel for deployment verification.
 * Uses the Vercel API for deployment status, promotion, and rollback.
 *
 * @module scanners/deploy/vercel-integration
 */
import { logger } from "../../logger.js";
const VERCEL_API_BASE = "https://api.vercel.com";
/**
 * Get Vercel API token from environment
 */
function getVercelToken() {
    return process.env.VERCEL_TOKEN || process.env.VERCEL_ACCESS_TOKEN;
}
/**
 * Check if Vercel integration is available
 */
export function isVercelAvailable() {
    return !!getVercelToken();
}
/**
 * Make authenticated request to Vercel API
 */
async function vercelFetch(endpoint, options = {}) {
    const token = getVercelToken();
    if (!token) {
        throw new Error("VERCEL_TOKEN not configured");
    }
    const url = `${VERCEL_API_BASE}${endpoint}`;
    const response = await fetch(url, {
        ...options,
        headers: {
            Authorization: `Bearer ${token}`,
            "Content-Type": "application/json",
            ...options.headers,
        },
    });
    return response;
}
/**
 * Map Vercel status to our status
 */
function mapVercelStatus(state) {
    switch (state) {
        case "QUEUED":
        case "INITIALIZING":
            return "pending";
        case "BUILDING":
            return "building";
        case "DEPLOYING":
            return "deploying";
        case "READY":
            return "ready";
        case "ERROR":
            return "failed";
        case "CANCELED":
            return "canceled";
        default:
            return "pending";
    }
}
/**
 * Map Vercel target to environment
 */
function mapVercelTarget(target) {
    switch (target) {
        case "production":
            return "production";
        case "preview":
            return "preview";
        case "development":
            return "development";
        default:
            return "preview";
    }
}
/**
 * Get latest deployment for a project
 */
export async function getLatestDeployment(projectId, options = {}) {
    try {
        const params = new URLSearchParams({
            projectId,
            limit: "1",
            ...(options.target && { target: options.target }),
        });
        const response = await vercelFetch(`/v6/deployments?${params}`);
        if (!response.ok) {
            const error = await response.json();
            logger.error("deploy.vercel_api_error", {
                status: response.status,
                error: error.error?.message,
            });
            return null;
        }
        const data = await response.json();
        const deployment = data.deployments?.[0];
        if (!deployment)
            return null;
        return {
            id: deployment.uid,
            provider: "vercel",
            environment: mapVercelTarget(deployment.target),
            status: mapVercelStatus(deployment.state),
            url: `https://${deployment.url}`,
            createdAt: new Date(deployment.created).toISOString(),
            readyAt: deployment.ready ? new Date(deployment.ready).toISOString() : undefined,
            meta: {
                commit: deployment.meta?.githubCommitSha,
                branch: deployment.meta?.githubCommitRef,
                buildTime: deployment.buildingAt && deployment.ready
                    ? deployment.ready - deployment.buildingAt
                    : undefined,
            },
        };
    }
    catch (error) {
        logger.error("deploy.vercel_get_deployment_error", {
            error: error.message,
        });
        return null;
    }
}
/**
 * Get deployment by ID
 */
export async function getDeployment(deploymentId) {
    try {
        const response = await vercelFetch(`/v13/deployments/${deploymentId}`);
        if (!response.ok) {
            return null;
        }
        const deployment = await response.json();
        return {
            id: deployment.id,
            provider: "vercel",
            environment: mapVercelTarget(deployment.target),
            status: mapVercelStatus(deployment.readyState),
            url: `https://${deployment.url}`,
            createdAt: new Date(deployment.createdAt).toISOString(),
            readyAt: deployment.ready ? new Date(deployment.ready).toISOString() : undefined,
            meta: {
                commit: deployment.meta?.githubCommitSha,
                branch: deployment.meta?.githubCommitRef,
            },
        };
    }
    catch (error) {
        logger.error("deploy.vercel_get_deployment_error", {
            deploymentId,
            error: error.message,
        });
        return null;
    }
}
/**
 * List recent deployments
 */
export async function listDeployments(projectId, options = {}) {
    try {
        const params = new URLSearchParams({
            projectId,
            limit: String(options.limit || 10),
            ...(options.target && { target: options.target }),
        });
        const response = await vercelFetch(`/v6/deployments?${params}`);
        if (!response.ok) {
            return [];
        }
        const data = await response.json();
        return (data.deployments || []).map((deployment) => ({
            id: deployment.uid,
            provider: "vercel",
            environment: mapVercelTarget(deployment.target),
            status: mapVercelStatus(deployment.state),
            url: `https://${deployment.url}`,
            createdAt: new Date(deployment.created).toISOString(),
            meta: {
                commit: deployment.meta?.githubCommitSha,
                branch: deployment.meta?.githubCommitRef,
            },
        }));
    }
    catch (error) {
        logger.error("deploy.vercel_list_deployments_error", {
            error: error.message,
        });
        return [];
    }
}
/**
 * Promote a preview deployment to production
 */
export async function promoteToProduction(deploymentId, projectId) {
    try {
        const response = await vercelFetch(`/v10/projects/${projectId}/promote/${deploymentId}`, {
            method: "POST",
        });
        if (!response.ok) {
            const error = await response.json();
            return {
                success: false,
                error: error.error?.message || "Promotion failed",
            };
        }
        logger.info("deploy.vercel_promoted", { deploymentId, projectId });
        return { success: true };
    }
    catch (error) {
        return {
            success: false,
            error: error.message,
        };
    }
}
/**
 * Rollback to a previous deployment
 */
export async function rollback(projectId, deploymentId) {
    // Vercel rollback is essentially promoting an older deployment
    return promoteToProduction(deploymentId, projectId);
}
/**
 * Analyze canary deployment (simulated - would use Vercel Edge Config in production)
 */
export async function analyzeCanary(deploymentUrl, options = {}) {
    const { duration = 60000, checkInterval = 5000 } = options;
    const startTime = Date.now();
    const checks = [];
    logger.info("deploy.canary_analysis_started", { deploymentUrl, duration });
    // Run health checks for the duration
    while (Date.now() - startTime < duration) {
        try {
            const checkStart = Date.now();
            const response = await fetch(deploymentUrl, {
                signal: AbortSignal.timeout(5000),
            });
            const latency = Date.now() - checkStart;
            checks.push({
                success: response.ok,
                latency,
            });
        }
        catch {
            checks.push({ success: false, latency: 5000 });
        }
        await new Promise((resolve) => setTimeout(resolve, checkInterval));
    }
    // Calculate metrics
    const successfulChecks = checks.filter((c) => c.success);
    const errorRate = 1 - (successfulChecks.length / checks.length);
    const latencies = successfulChecks.map((c) => c.latency).sort((a, b) => a - b);
    const p95Index = Math.floor(latencies.length * 0.95);
    const p95Latency = latencies[p95Index] || 0;
    const thresholdsPassed = errorRate < 0.01 && p95Latency < 500;
    const analysis = {
        phase: thresholdsPassed ? "passed" : "failed",
        trafficPercent: 10, // Simulated
        duration: Date.now() - startTime,
        metrics: {
            errorRate,
            p95Latency,
            requestCount: checks.length,
            healthChecksPassed: successfulChecks.length,
            healthChecksFailed: checks.length - successfulChecks.length,
        },
        thresholdsPassed,
        recommendation: thresholdsPassed ? "promote" : "rollback",
    };
    logger.info("deploy.canary_analysis_completed", {
        phase: analysis.phase,
        errorRate,
        p95Latency,
        recommendation: analysis.recommendation,
    });
    return analysis;
}
//# sourceMappingURL=vercel-integration.js.map