import * as fs from 'fs';
import * as path from 'path';
import * as vscode from 'vscode';
import type { CompanyState } from '../../features/company';

/**
 * Telegram 메시지 처리 파이프라인의 순수 헬퍼 5개.
 * 모두 stateless — 테스트 가능 + Telegram 라우팅 정책 바뀔 때 한 곳만 수정.
 *
 *   - buildTelegramSystemPrompt(hasContext)   — 시스템 프롬프트 (4가지 역할/규칙)
 *   - looksLikeWorkOrder(text)                — 회사 모드 라우팅용 휴리스틱
 *   - buildTelegramCompanyContext(state, ctx) — 비서 역할용 [COMPANY CONTEXT] 블록
 *   - latestCompanySessionDir(ctx)            — 최근 세션 디렉토리 (위 블록의 데이터)
 *   - chunkTelegramMessage(text, max)         — 4096자 제한 대응 분할
 */

/**
 * Build the Telegram-specific system prompt.
 *
 * Why this matters: small local models (gemma e2b/e4b) drift badly when
 * called as a single user message with no role grounding. The reported
 * symptom ("path 입력 → 시 못 써드려요" 같은 환각 거절) is exactly that
 * drift — the model invents an interpretation because it has no anchor.
 *
 * The prompt does four things:
 *   1. Names the role (Astra Telegram assistant) so the model has a
 *      consistent persona across messages.
 *   2. States the language rule (mirror the user's language).
 *   3. Tells the model how to treat brain context (evidence when relevant,
 *      ignore otherwise — never refuse the question because context
 *      doesn't match).
 *   4. Specifies behavior for ambiguous inputs (paths, single words,
 *      fragments) — ask a clarifying question instead of guessing.
 */
export function buildTelegramSystemPrompt(hasContext: boolean): string {
    const base = [
        'You are Astra, a Telegram assistant connected to the user\'s personal Second Brain knowledge base.',
        'Reply in the user\'s language (mirror Korean ↔ English exactly as the user wrote).',
        'Be concise but complete. Telegram messages should feel like a knowledgeable friend, not a formal report.',
        '',
        'Behavior rules:',
        '- Never refuse a question by claiming you can only do certain things. If you can answer, just answer.',
        '- If the user\'s message is ambiguous (a single word, a file path, a fragment with no question), ask one short clarifying question instead of guessing what they meant.',
        '- Do NOT invent that the user asked for poetry, songs, code, or any content type they did not request.',
    ];
    if (hasContext) {
        base.push(
            '',
            'You will receive a [SECOND BRAIN CONTEXT] block before the user\'s message.',
            '- Use it as evidence only when it directly answers the question. Cite the file path (relative form, e.g. `10_Wiki/Topics/Foo.md`) inline when you do.',
            '- If the context is unrelated to the question, ignore it silently. Do NOT mention that the context exists, do NOT explain why it doesn\'t apply, do NOT refuse the question because of it.',
        );
    }
    return base.join('\n');
}

/**
 * Cheap heuristic: does the message look like a *work order* the user
 * wants the company to execute? Triggers company-turn routing.
 *
 * Conservative matches only — we'd rather miss a borderline case
 * (user retries with clearer wording) than mis-route a question
 * into a company turn (which spends LLM calls + writes to disk).
 *
 * Positive signals:
 *   • Explicit dispatch prefix: "CEO한테", "회사한테", "팀한테"
 *   • Korean imperative verbs at sentence end: 만들어/해줘/작성해줘/
 *     짜줘/구현해/만들어줘/돌려줘/실행해줘/분석해줘/정리해줘
 *   • English imperatives: "make X", "build X", "create X", "implement"
 *
 * Negative signals (override → treat as question, not order):
 *   • Ends with "?" — pure question
 *   • Contains "알려줘 / 어디 / 뭐야 / what / where" — informational
 */
export function looksLikeWorkOrder(text: string): boolean {
    const t = (text || '').trim();
    if (!t) return false;
    if (/(CEO|회사|팀)\s*(한테|에게|보고|에)/i.test(t)) return true;
    if (/[?？]$/.test(t)) return false;
    if (/(어디(에|에서|야)|뭐야|얼마|언제|왜|^(누구|어떻게|뭐))/i.test(t)) return false;
    if (/(만들어|짜줘|작성해|구현해|돌려줘|실행해|분석해|정리해|보고해|해줘|짜봐|만들어줘)/i.test(t)) return true;
    if (/^\s*(make|build|create|implement|run|analyze|generate|write|fix|add|remove)\b/i.test(t)) return true;
    return false;
}

/** Find the newest `<workspace>/.astra/company/sessions/<ts>/` directory, or '' if none. */
export function latestCompanySessionDir(ctx: vscode.ExtensionContext): string {
    try {
        const ws = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
        const baseDir = ws
            ? path.join(ws, '.astra', 'company', 'sessions')
            : path.join(ctx.globalStorageUri.fsPath, 'company', 'sessions');
        if (!fs.existsSync(baseDir)) return '';
        const dirs = fs.readdirSync(baseDir)
            .filter((n) => fs.statSync(path.join(baseDir, n)).isDirectory())
            .sort()
            .reverse();
        return dirs[0] ? path.join(baseDir, dirs[0]) : '';
    } catch { return ''; }
}

/**
 * Build a `[COMPANY CONTEXT]` block describing the workspace, the
 * current company state, and the most recent session directory. Lets
 * the bot answer questions like "어디에 저장했어?" by reading its own
 * mirror history *plus* the resolved absolute path on disk.
 *
 * Returns '' when company mode is off, so the prompt stays minimal
 * for users who only use the Telegram bot for RAG-chat.
 */
export function buildTelegramCompanyContext(state: CompanyState, ctx: vscode.ExtensionContext): string {
    if (!state.enabled) return '';
    const ws = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || '';
    const lines: string[] = [`[COMPANY CONTEXT]`];
    lines.push(`회사명: ${state.companyName || '1인 기업'}`);
    if (ws) lines.push(`작업 폴더 (워크스페이스 루트): ${ws}`);
    const latestSession = latestCompanySessionDir(ctx);
    if (latestSession) {
        lines.push(`최근 작업 세션 폴더: ${latestSession}`);
        lines.push(`(이 안에 _brief.md, _report.md, 각 에이전트별 산출물이 저장됨)`);
    }
    lines.push('');
    lines.push('당신의 역할: 이 회사의 비서(Secretary). 사용자(사장님)의 질문에 답할 때 위 경로 정보를 *그대로* 활용하세요.');
    lines.push('"실제 파일 시스템에 접근할 수 없다" 같은 답변은 잘못된 것입니다 — 위 경로가 실제 시스템 경로입니다.');
    return lines.join('\n');
}

/** Telegram has a 4096-char per-message limit. Split on paragraph/sentence boundaries to keep replies readable. */
export function chunkTelegramMessage(text: string, max = 4000): string[] {
    if (text.length <= max) return [text];
    const out: string[] = [];
    let remaining = text;
    while (remaining.length > max) {
        let cut = remaining.lastIndexOf('\n\n', max);
        if (cut < max * 0.5) cut = remaining.lastIndexOf('\n', max);
        if (cut < max * 0.5) cut = remaining.lastIndexOf('. ', max);
        if (cut < max * 0.5) cut = max;
        out.push(remaining.slice(0, cut).trim());
        remaining = remaining.slice(cut).trim();
    }
    if (remaining) out.push(remaining);
    return out;
}
