"use strict";
/**
 * Copilot Auth Handler
 *
 * Handles GitHub OAuth authentication for copilot-api.
 * Uses local installation from ~/.ccs/copilot/ (managed by copilot-package-manager).
 */
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 (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.startAuthFlow = exports.checkAuthStatus = exports.getCopilotDebugInfo = exports.isCopilotApiInstalled = exports.hasTokenFile = exports.getTokenPath = void 0;
const child_process_1 = require("child_process");
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const os = __importStar(require("os"));
const copilot_package_manager_1 = require("./copilot-package-manager");
const logging_1 = require("../services/logging");
const logger = (0, logging_1.createLogger)('copilot:auth');
/**
 * Get the path to copilot-api's GitHub token file.
 * copilot-api stores tokens in ~/.local/share/copilot-api/github_token (Linux/macOS)
 * or %APPDATA%/copilot-api/github_token (Windows)
 */
function getTokenPath() {
    if (process.platform === 'win32') {
        return path.join(process.env.APPDATA || os.homedir(), 'copilot-api', 'github_token');
    }
    return path.join(os.homedir(), '.local', 'share', 'copilot-api', 'github_token');
}
exports.getTokenPath = getTokenPath;
/**
 * Check if GitHub token file exists.
 * Fast check that doesn't require spawning copilot-api process.
 */
function hasTokenFile() {
    try {
        return fs.existsSync(getTokenPath());
    }
    catch {
        return false;
    }
}
exports.hasTokenFile = hasTokenFile;
/**
 * Check if copilot-api is installed locally.
 * Uses copilot-package-manager to check ~/.ccs/copilot/node_modules/.bin/copilot-api
 */
function isCopilotApiInstalled() {
    return (0, copilot_package_manager_1.isCopilotApiInstalled)();
}
exports.isCopilotApiInstalled = isCopilotApiInstalled;
/**
 * Get copilot-api debug info.
 * Returns authentication status and version info.
 */
async function getCopilotDebugInfo() {
    const binPath = (0, copilot_package_manager_1.getCopilotApiBinPath)();
    return new Promise((resolve) => {
        try {
            const proc = (0, child_process_1.spawn)(binPath, ['debug', '--json'], {
                stdio: ['ignore', 'pipe', 'pipe'],
                shell: process.platform === 'win32',
                timeout: 15000,
            });
            let stdout = '';
            let _stderr = '';
            proc.stdout.on('data', (data) => {
                stdout += data.toString();
            });
            proc.stderr.on('data', (data) => {
                _stderr += data.toString();
            });
            proc.on('close', (code) => {
                if (code === 0 && stdout) {
                    try {
                        const info = JSON.parse(stdout.trim());
                        resolve(info);
                    }
                    catch {
                        resolve(null);
                    }
                }
                else {
                    resolve(null);
                }
            });
            proc.on('error', () => {
                resolve(null);
            });
            // Timeout after 15 seconds
            setTimeout(() => {
                proc.kill();
                resolve(null);
            }, 15000);
        }
        catch {
            resolve(null);
        }
    });
}
exports.getCopilotDebugInfo = getCopilotDebugInfo;
/**
 * Check copilot authentication status.
 * Uses fast token file check first, falls back to copilot-api debug if needed.
 */
async function checkAuthStatus() {
    // Fast path: check if token file exists (instant, no subprocess)
    if (hasTokenFile()) {
        logger.stage('auth', 'copilot.auth.token_present', 'Copilot token file present', {
            provider: 'copilot',
            method: 'token_file',
        });
        return { authenticated: true };
    }
    // Slow path: try copilot-api debug --json (may timeout)
    // Only used if token file doesn't exist
    const debugInfo = await getCopilotDebugInfo();
    if (debugInfo?.authenticated) {
        logger.stage('auth', 'copilot.auth.debug_ok', 'Copilot reports authenticated via debug', {
            provider: 'copilot',
            method: 'debug',
        });
        return { authenticated: true };
    }
    logger.stage('auth', 'copilot.auth.unauthenticated', 'Copilot is not authenticated', { provider: 'copilot' }, { level: 'warn' });
    return {
        authenticated: false,
    };
}
exports.checkAuthStatus = checkAuthStatus;
/**
 * Start GitHub OAuth authentication flow.
 * Captures device code from copilot-api output and returns it.
 *
 * @returns Promise that resolves with auth result including device code
 */
function startAuthFlow() {
    const binPath = (0, copilot_package_manager_1.getCopilotApiBinPath)();
    return new Promise((resolve) => {
        console.log('[i] Starting GitHub authentication for Copilot...');
        console.log('');
        const startedAt = Date.now();
        logger.stage('auth', 'copilot.auth.start', 'Starting Copilot OAuth device flow', {
            provider: 'copilot',
        });
        const proc = (0, child_process_1.spawn)(binPath, ['auth'], {
            stdio: ['ignore', 'pipe', 'pipe'],
            shell: process.platform === 'win32',
        });
        let stdout = '';
        let deviceCode;
        let verificationUrl;
        proc.stdout.on('data', (data) => {
            const chunk = data.toString();
            stdout += chunk;
            // Echo to console for terminal users
            process.stdout.write(chunk);
            // Parse device code from output like:
            // "Please enter the code "5653-38A1" in https://github.com/login/device"
            const codeMatch = stdout.match(/code\s+"([A-Z0-9]{4}-[A-Z0-9]{4})"/i);
            const urlMatch = stdout.match(/(https:\/\/github\.com\/login\/device)/i);
            if (codeMatch && !deviceCode) {
                deviceCode = codeMatch[1];
            }
            if (urlMatch && !verificationUrl) {
                verificationUrl = urlMatch[1];
            }
        });
        proc.stderr.on('data', (data) => {
            // Echo stderr to console
            process.stderr.write(data.toString());
        });
        proc.on('close', (code) => {
            if (code === 0) {
                logger.stage('auth', 'copilot.auth.complete', 'Copilot OAuth device flow completed', { provider: 'copilot', exitCode: code }, { latencyMs: Date.now() - startedAt });
                resolve({ success: true, deviceCode, verificationUrl });
            }
            else {
                logger.stage('cleanup', 'copilot.auth.failed', 'Copilot OAuth device flow failed', { provider: 'copilot', exitCode: code }, { level: 'error', latencyMs: Date.now() - startedAt });
                resolve({
                    success: false,
                    error: `Authentication failed with exit code ${code}`,
                    deviceCode,
                    verificationUrl,
                });
            }
        });
        proc.on('error', (err) => {
            logger.stage('cleanup', 'copilot.auth.error', 'Failed to start Copilot OAuth process', { provider: 'copilot' }, {
                level: 'error',
                latencyMs: Date.now() - startedAt,
                error: { name: err.name, message: err.message },
            });
            resolve({
                success: false,
                error: `Failed to start auth: ${err.message}`,
            });
        });
    });
}
exports.startAuthFlow = startAuthFlow;
//# sourceMappingURL=copilot-auth.js.map