"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@oclif/core");
const chalk_1 = __importDefault(require("chalk"));
const ora_1 = __importDefault(require("ora"));
const http = __importStar(require("node:http"));
const api_client_1 = require("../../lib/api-client");
const config_storage_1 = require("../../lib/config-storage");
const browser_callback_1 = require("../../lib/browser-callback");
const CONNECT_TIMEOUT_MS = 5 * 60 * 1000;
class IntegrationConnect extends core_1.Command {
    async run() {
        const { args, flags } = await this.parse(IntegrationConnect);
        const configStorage = new config_storage_1.ConfigStorage();
        const apiUrl = configStorage.getApiUrlOrThrow();
        const apiKey = configStorage.getApiKey();
        if (!apiKey) {
            this.error('Not logged in. Run `flui auth login` first.', { exit: 1 });
        }
        const api = new api_client_1.ApiClient({ baseUrl: apiUrl, apiKey });
        if (args.provider !== 'github') {
            this.error(`Unknown provider "${args.provider}"`, { exit: 1 });
        }
        const port = await (0, browser_callback_1.findFreeCallbackPort)();
        const cliCallbackUrl = `http://127.0.0.1:${port}/callback`;
        const spinner = (0, ora_1.default)('Requesting GitHub App install URL…').start();
        let install;
        try {
            install = await api.get(`/repositories/github-app/install-url?cliCallback=${encodeURIComponent(cliCallbackUrl)}`);
            spinner.stop();
        }
        catch (error) {
            spinner.fail('Failed to get install URL');
            console.log(chalk_1.default.red(`  ${error.message}`));
            this.exit(1);
        }
        if (install.alreadyConnected) {
            console.log(chalk_1.default.green(`\n  ✔ GitHub is already connected as ${chalk_1.default.bold(install.login ?? '?')}.\n`));
            return;
        }
        if (!install.installUrl) {
            console.log(chalk_1.default.red('\n  API did not return an install URL. Please retry or contact support.\n'));
            this.exit(1);
        }
        if (flags.headless) {
            console.log('');
            console.log(chalk_1.default.dim('  Open this URL in a browser to install the GitHub App:'));
            console.log(`  ${chalk_1.default.cyan(install.installUrl)}`);
            console.log('');
            console.log(chalk_1.default.dim(`  Waiting for the post-install callback on ${cliCallbackUrl}…`));
        }
        else {
            const opened = (0, browser_callback_1.openInBrowser)(install.installUrl);
            if (opened) {
                console.log(chalk_1.default.dim(`\n  Opened browser to install the Flui GitHub App.`));
            }
            else {
                console.log(chalk_1.default.yellow(`\n  Could not open browser. Open this URL manually:\n  ${install.installUrl}\n`));
            }
            console.log(chalk_1.default.dim(`  Waiting for the post-install callback on ${cliCallbackUrl}…`));
        }
        const result = await this.waitForCallback(port);
        if (result.status === 'connected') {
            console.log(chalk_1.default.green(`\n  ✔ GitHub connected as ${chalk_1.default.bold(result.login ?? '?')}.\n`));
            console.log(chalk_1.default.dim(`  Next: \`flui repo connect <owner/repo>\` to make a repository deployable.\n`));
            return;
        }
        console.log(chalk_1.default.red(`\n  ✖ Connection failed: ${result.error}\n`));
        this.exit(1);
    }
    waitForCallback(port) {
        return new Promise((resolve) => {
            const timer = setTimeout(() => {
                server.close();
                resolve({
                    status: 'error',
                    error: `timed out after ${CONNECT_TIMEOUT_MS / 1000}s`,
                });
            }, CONNECT_TIMEOUT_MS);
            const server = http.createServer((req, res) => {
                const url = new URL(req.url ?? '/', `http://127.0.0.1:${port}`);
                if (url.pathname !== '/callback') {
                    res.writeHead(404);
                    res.end();
                    return;
                }
                const status = url.searchParams.get('status');
                const login = url.searchParams.get('login');
                const error = url.searchParams.get('error');
                if (status === 'connected' && login) {
                    res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
                    res.end((0, browser_callback_1.renderPage)('GitHub connected', `<h2>GitHub connected</h2><p>Connected as <code>${login}</code>. You can close this tab and return to the terminal.</p>`));
                    clearTimeout(timer);
                    server.close(() => resolve({ status: 'connected', login }));
                    return;
                }
                const errMsg = error ?? 'unknown callback shape';
                res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
                res.end((0, browser_callback_1.renderPage)('GitHub connection failed', `<h2>Connection failed</h2><p>${errMsg}</p>`));
                clearTimeout(timer);
                server.close(() => resolve({ status: 'error', error: errMsg }));
            });
            server.listen(port, '127.0.0.1');
        });
    }
}
IntegrationConnect.description = 'Connect a third-party integration to your Flui account. Currently supports GitHub: opens a browser to install the Flui GitHub App, then waits for the local callback to confirm the connection.';
IntegrationConnect.examples = [
    '<%= config.bin %> <%= command.id %> github',
    '<%= config.bin %> <%= command.id %> github --headless',
];
IntegrationConnect.args = {
    provider: core_1.Args.string({
        description: 'Integration provider (currently only `github`)',
        required: true,
        options: ['github'],
    }),
};
IntegrationConnect.flags = {
    headless: core_1.Flags.boolean({
        description: 'Print the install URL instead of opening a browser (useful over SSH)',
        default: false,
    }),
};
exports.default = IntegrationConnect;
