"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PrototypeDeployService = void 0;
const zlib_1 = require("zlib");
const logger_1 = require("../utils/logger");
const ConfigManager_1 = require("./ConfigManager");
const proxy_1 = require("../config/proxy");
const PrototypeBuildService_1 = require("./PrototypeBuildService");
const log = (0, logger_1.createLogger)('PrototypeDeployService');
/**
 * Orchestrates deploying a fresh-project variant to the Prototype Preview Host:
 * build locally → gzip the file-list → upload with the user's Rivet JWT.
 *
 * Auth mirrors `GatewayClient`: attach `Authorization: Bearer <jwt>` from
 * `ConfigManager.getAuthToken()`, and on a 401 refresh the token via the proxy
 * and retry once. The host holds all hosting credentials — the client only ever
 * sends its own token.
 */
class PrototypeDeployService {
    buildService;
    hostUrl;
    proxyUrl;
    configManager = (0, ConfigManager_1.getConfigManager)();
    constructor(buildService = new PrototypeBuildService_1.PrototypeBuildService(), hostUrl = proxy_1.PROTOTYPE_HOST_URL, proxyUrl = proxy_1.PROXY_URL) {
        this.buildService = buildService;
        this.hostUrl = hostUrl;
        this.proxyUrl = proxyUrl;
    }
    /** Build the variant's `files/` dir (Vite app) and publish it. */
    async deploy(filesDir) {
        const { files, totalBytes } = await this.buildService.build(filesDir);
        return this.publishFiles(files, totalBytes, 'Built');
    }
    /**
     * Publish an already-built static bundle (the variant's `files/` dir) with no
     * build step. Used for history static-preview variants, which are already
     * servable static sites.
     */
    async deployStatic(filesDir) {
        const { files, totalBytes } = await this.buildService.packStatic(filesDir);
        return this.publishFiles(files, totalBytes, 'Packed');
    }
    async publishFiles(files, totalBytes, verb) {
        log.info(`${verb} prototype bundle: ${files.length} files, ${Math.round(totalBytes / 1024)}KB`);
        const payload = (0, zlib_1.gzipSync)(Buffer.from(JSON.stringify({ files })));
        return this.publish(payload, 0);
    }
    async publish(payload, retryCount) {
        const authToken = this.configManager.getAuthToken();
        if (!authToken) {
            throw new Error('Not authenticated. Please run `rivet login` to deploy a prototype.');
        }
        const response = await fetch(`${this.hostUrl}/publish`, {
            method: 'POST',
            headers: {
                Authorization: `Bearer ${authToken}`,
                'Content-Type': 'application/json',
                'Content-Encoding': 'gzip',
            },
            // Node's fetch accepts a Buffer at runtime; the DOM BodyInit type doesn't
            // list it, so cast. (GatewayClient only ever sends strings, so it never
            // needed this.)
            body: payload,
        });
        if (response.status === 401 && retryCount === 0) {
            log.warn('Token expired, attempting to refresh...');
            const refreshed = await this.refreshAccessToken();
            if (refreshed) {
                return this.publish(payload, retryCount + 1);
            }
            throw new Error('Authentication expired. Please run `rivet logout` and `rivet login` to re-authenticate.');
        }
        if (!response.ok) {
            const body = await response.json().catch(() => ({}));
            const message = body.message ??
                `Deploy failed (${response.status}).`;
            throw new Error(message);
        }
        const result = (await response.json());
        if (!result.deployId || !result.shareUrl) {
            throw new Error('Deploy host returned an unexpected response.');
        }
        return { deployId: result.deployId, shareUrl: result.shareUrl };
    }
    /** Refresh the access token using the stored refresh token. Mirrors GatewayClient. */
    async refreshAccessToken() {
        const refreshToken = this.configManager.getRefreshToken();
        if (!refreshToken) {
            log.warn('No refresh token available');
            return false;
        }
        try {
            const response = await fetch(`${this.proxyUrl}/api/auth/refresh`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ refreshToken }),
            });
            if (!response.ok)
                return false;
            const result = await response.json();
            if (result.success && result.token) {
                const email = this.configManager.getEmail() || '';
                this.configManager.setAuth(result.token, email, result.refreshToken);
                return true;
            }
            return false;
        }
        catch (err) {
            log.warn('Error refreshing token:', err);
            return false;
        }
    }
}
exports.PrototypeDeployService = PrototypeDeployService;
//# sourceMappingURL=PrototypeDeployService.js.map