import * as vscode from 'vscode';
import * as fs from 'fs';
import * as path from 'path';
import { exec } from 'child_process';
import { promisify } from 'util';

const execAsync = promisify(exec);

/**
 * NotebookLM 로컬 백엔드(Datacollect Bridge) 원클릭 실행/종료.
 *
 * 배경: Datacollector 의 Research(NotebookLM) 기능은 NAS 브리지로 처리할 수 없다 —
 * 로그인된 로컬 Chrome 세션과 PC 의 LM Studio(127.0.0.1) 프록시가 필요해서
 * Datacollector 프론트가 리서치 요청을 localhost:3002 로 하드코딩해 보낸다.
 * 그동안 사용자가 터미널에서 `npm run bridge` 를 직접 실행해야 했는데, 터미널이
 * 익숙지 않은 사용자를 위해 사이드바 도구 메뉴의 버튼 두 개로 감쌌다.
 *
 * 설계:
 *  - 실행은 VS Code 통합 터미널("NotebookLM Bridge")에서 `npm run bridge` 를 돌린다.
 *    → 맥/윈도우 셸 차이를 VS Code 가 흡수하고(별도 OS 분기 불필요), 사용자가
 *      브리지 로그(인증 만료 안내 등)를 그대로 볼 수 있으며, 종료 = 터미널 dispose.
 *  - 프로젝트 폴더는 설정(g1nation.datacollectLocalProjectPath) 우선, 비어 있으면
 *    워크스페이스 폴더·부모·형제에서 자동 탐색. 못 찾으면 폴더 선택 대화상자 제공.
 *  - 종료는 우리 터미널 dispose + (버튼 밖에서 띄운 프로세스 대비) 포트 점유
 *    프로세스를 OS별 명령으로 best-effort 정리한다 — 이 부분만 OS 자동 감지 분기.
 */

const TERMINAL_NAME = 'NotebookLM Bridge';
const BRIDGE_PORT = 3002;
/** 자동 탐색 시 찾는 프로젝트 폴더 이름 후보 (맥/윈도우 클론 이름이 다를 수 있음). */
const PROJECT_DIR_NAMES = ['Datacollector_MAC', 'Datacollector', 'Datacollect'];
/** 이 파일이 있어야 브리지 프로젝트로 인정. */
const BRIDGE_SCRIPT_REL = path.join('scripts', 'mcp_bridge.mjs');

/**
 * 브리지 프로젝트 후보 경로를 우선순위대로 나열한다 (존재 검증은 안 함 — 테스트 가능한 순수 함수).
 * 우선순위: 설정값 → 각 워크스페이스 폴더 자신 → 그 부모 아래 형제 폴더들.
 */
export function candidateProjectDirs(cfgPath: string, workspaceDirs: string[]): string[] {
    const out: string[] = [];
    const push = (p: string) => { if (p && !out.includes(p)) out.push(p); };
    if (cfgPath && cfgPath.trim()) push(cfgPath.trim());
    for (const ws of workspaceDirs) {
        push(ws); // 워크스페이스가 곧 Datacollector 프로젝트인 경우
        const parent = path.dirname(ws);
        for (const name of PROJECT_DIR_NAMES) push(path.join(parent, name));
    }
    return out;
}

/** 포트를 점유한 프로세스를 죽이는 OS별 셸 명령 (순수 함수 — 테스트 대상). */
export function buildPortKillCommand(platform: NodeJS.Platform, port: number): string {
    if (platform === 'win32') {
        // PowerShell: 해당 포트 LISTEN 프로세스를 강제 종료. (netstat 파싱보다 안전)
        return `powershell -NoProfile -Command "Get-NetTCPConnection -LocalPort ${port} -State Listen -ErrorAction SilentlyContinue | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force }"`;
    }
    // macOS / Linux
    return `lsof -ti :${port} | xargs kill 2>/dev/null`;
}

function findBridgeProject(): string | null {
    const cfgPath = vscode.workspace.getConfiguration('g1nation').get<string>('datacollectLocalProjectPath', '') || '';
    const wsDirs = (vscode.workspace.workspaceFolders || [])
        .filter(f => f.uri.scheme === 'file')
        .map(f => f.uri.fsPath);
    for (const dir of candidateProjectDirs(cfgPath, wsDirs)) {
        try {
            if (fs.existsSync(path.join(dir, BRIDGE_SCRIPT_REL))) return dir;
        } catch { /* 접근 불가 경로 — skip */ }
    }
    return null;
}

/** 브리지 생존 확인 — 어떤 HTTP 응답이든(404 포함) 살아 있는 것. */
async function isBridgeAlive(): Promise<boolean> {
    try {
        await fetch(`http://127.0.0.1:${BRIDGE_PORT}/`, { signal: AbortSignal.timeout(1500) });
        return true;
    } catch {
        return false;
    }
}

function findOurTerminal(): vscode.Terminal | undefined {
    return vscode.window.terminals.find(t => t.name === TERMINAL_NAME);
}

export async function startNotebookLmBridge(): Promise<void> {
    if (await isBridgeAlive()) {
        findOurTerminal()?.show(true);
        vscode.window.showInformationMessage('NotebookLM 백엔드가 이미 실행 중입니다 (포트 3002 응답 확인).');
        return;
    }

    let projectDir = findBridgeProject();
    if (!projectDir) {
        // 자동 탐색 실패 — 비개발자도 해결할 수 있게 폴더 선택 대화상자를 제공한다.
        const pick = await vscode.window.showErrorMessage(
            'Datacollector 프로젝트 폴더를 찾지 못했습니다. 폴더를 직접 선택하면 설정에 저장되어 다음부터는 버튼만 누르면 됩니다.',
            '폴더 선택'
        );
        if (pick !== '폴더 선택') return;
        const chosen = await vscode.window.showOpenDialog({
            canSelectFiles: false, canSelectFolders: true, canSelectMany: false,
            openLabel: 'Datacollector 폴더 선택',
        });
        const dir = chosen?.[0]?.fsPath;
        if (!dir) return;
        if (!fs.existsSync(path.join(dir, BRIDGE_SCRIPT_REL))) {
            vscode.window.showErrorMessage(`선택한 폴더에 ${BRIDGE_SCRIPT_REL} 가 없습니다 — Datacollector 프로젝트 폴더가 맞는지 확인하세요.`);
            return;
        }
        await vscode.workspace.getConfiguration('g1nation')
            .update('datacollectLocalProjectPath', dir, vscode.ConfigurationTarget.Global);
        projectDir = dir;
    }

    // 기존 우리 터미널이 남아 있으면 재사용하지 않고 정리 후 새로 연다 (죽은 셸 방지).
    findOurTerminal()?.dispose();
    const terminal = vscode.window.createTerminal({ name: TERMINAL_NAME, cwd: projectDir });
    terminal.show(true);
    terminal.sendText('npm run bridge');
    vscode.window.showInformationMessage(
        'NotebookLM 백엔드를 시작했습니다 — 준비까지 몇 초 걸릴 수 있어요. (로그는 "NotebookLM Bridge" 터미널에서 확인)'
    );
}

export async function stopNotebookLmBridge(): Promise<void> {
    const term = findOurTerminal();
    if (term) term.dispose();

    // 터미널 밖(예전 수동 실행 등)에서 뜬 프로세스까지 정리 — 포트 점유 시 OS별 명령으로 kill.
    await new Promise(r => setTimeout(r, 600)); // 터미널 dispose 가 프로세스를 정리할 시간
    if (await isBridgeAlive()) {
        try {
            await execAsync(buildPortKillCommand(process.platform, BRIDGE_PORT), { timeout: 8000 });
        } catch { /* 이미 죽었거나 권한 문제 — 아래 재확인으로 판정 */ }
    }

    if (await isBridgeAlive()) {
        vscode.window.showWarningMessage('NotebookLM 백엔드가 아직 응답합니다 — 다른 프로그램이 포트 3002 를 쓰고 있을 수 있습니다.');
    } else {
        vscode.window.showInformationMessage('NotebookLM 백엔드를 종료했습니다.');
    }
}

/** 사이드바 웹뷰 메시지 핸들러 — sidebarProvider 의 핸들러 체인에 등록된다. */
export async function handleBridgeLauncherMessage(_provider: unknown, data: any): Promise<boolean> {
    switch (data?.type) {
        case 'startNotebookLmBridge':
            await startNotebookLmBridge();
            return true;
        case 'stopNotebookLmBridge':
            await stopNotebookLmBridge();
            return true;
        default:
            return false;
    }
}
