import { isThinkingPartnerRequest } from './promptDetection';

/**
 * 로컬 프로젝트 *의도 분류* + *tone-shaping* 의 한 묶음. 옛 코드는 agent.ts 의
 * 6개 private 메서드 + 2개 static regex 로 흩어져 있었음.
 *
 * 의존 그래프:
 *   containsLocalFilePath ──┐
 *                           ├─→ classifyLocalProjectIntent ─→ {isProjectKnowledge..,
 *                           │                                  isProjectReview..,
 *                           │                                  buildAstraStanceContext}
 *   shouldPreflightLocalProjectPath ─┘
 *
 *   buildLocalProjectIntentGuidance — 독립, intent 만 받음
 *
 * 모두 stateless 정규식 기반이라 god-file 무게 빼기 + 단위 테스트 노출 + 다른
 * 모드에서 재사용을 위해 한 모듈로 격리.
 *
 * 주의 — 정규식 lastIndex pollution 방지:
 *   /g/ flag 없이 만든 RegExp 인스턴스는 `.test()` 반복 호출에 안전. /g/ 를
 *   붙이면 lastIndex 가 호출간 누적돼 두 번째 .test() 가 false 가 되는 버그가
 *   날 수 있으니 새 패턴 추가 시 주의.
 */

export type LocalProjectIntent =
    | 'review-evaluation'
    | 'knowledge-creation'
    | 'implementation'
    | 'documentation'
    | 'thinking'
    | 'general';

// POSIX: /Volumes/, /Users/, /home/, /opt/, ... or ~/  — backtick 제외 (markdown code spans).
// Source string 도 export — 호출자가 /g/ flag 가 필요한 matchAll 패턴에 새 RegExp 인스턴스를
// 만들 수 있어야 함 (lastIndex pollution 방지 위해 인스턴스 공유 안 함).
export const POSIX_ABS_PATH_SRC = "(?:\\/(?:Volumes|Users|home|opt|srv|mnt|data|workspace)\\/|~\\/)[^\\s`\"'<>|*?]+";
// Windows: drive letter (C:\ or C:/) or UNC (\\server\share). Backslash 가 separator 로 허용됨.
export const WIN_ABS_PATH_SRC = "(?:[A-Za-z]:[\\\\/]|\\\\\\\\[^\\s\\\\/]+\\\\[^\\s\\\\/]+)[^\\s`\"'<>|*?]*";

export const ABS_PATH_RE = new RegExp(POSIX_ABS_PATH_SRC, 'i');
export const WIN_ABS_PATH_RE = new RegExp(WIN_ABS_PATH_SRC, 'i');

/**
 * Prompt 에 로컬 파일/디렉토리 경로가 포함돼 있는지. 절대 경로 (POSIX + Windows
 * + UNC) 또는 흔한 상대 경로 패턴 (`src/...`, `lib/...` + 확장자) 둘 다 잡는다.
 */
export function containsLocalFilePath(prompt: string): boolean {
    if (ABS_PATH_RE.test(prompt) || WIN_ABS_PATH_RE.test(prompt)) {
        return true;
    }
    if (/(?:^|[\s,])(?:src|lib|components|pages|app|tests|test|utils|core|features|hooks|services|config|public|assets|docs|scripts)[\\/]/i.test(prompt)
        && /\.[a-z]{1,6}(?:[\s,;)\]]|$)/i.test(prompt)) {
        return true;
    }
    return false;
}

/**
 * 사용자 prompt 가 로컬 경로 + 어떤 *작업 동사* 둘 다 포함하는지. 둘 다 있어야
 * preflight (실제 디스크 scan + 컨텍스트 주입) 가 의미 있음. 작업 동사 없이
 * 경로만 있으면 사용자가 단순히 경로를 언급한 것일 수 있어 scan skip.
 */
export function shouldPreflightLocalProjectPath(prompt: string): boolean {
    const hasActionKeyword = /(검토|리뷰|분석|확인|봐줘|읽어|열어|파일|내용|코드|고쳐|개선|디버그|지식|문서화|문서|정리|기록|위키|저장|만들|생성|설계|아키텍처|구조|방향|의견|생각|판단|어떤\s*거?\s*같|어때|순서대로|보면|knowledge|document|documentation|wiki|summari[sz]e|review|analy[sz]e|inspect|debug|fix|improve|architecture|design|structure|opinion|think|judge|read|open|file|content|code)/i.test(prompt);
    const hasLocalPath = containsLocalFilePath(prompt);
    return hasActionKeyword && hasLocalPath;
}

/**
 * Intent 분류기 — preflight 결과에 따라 어떤 tone / 어떤 가이던스 블록을 prompt 에
 * 박을지 결정. 경로가 안 보이면 'general' 로 단락 — 분류 자체가 의미 없음.
 *
 * 분류 우선순위: review > implementation > knowledge-creation > documentation
 * > thinking > general. 이 순서가 *겹치는 키워드* 가 있을 때 어느 쪽으로 단정할지를
 * 결정하므로 함부로 바꾸지 말 것.
 */
export function classifyLocalProjectIntent(prompt: string): LocalProjectIntent {
    if (!containsLocalFilePath(prompt)) {
        return 'general';
    }

    const normalized = prompt.replace(/\s+/g, ' ').trim();
    const asksReview = /(코드\s*리뷰|코드리뷰|리뷰|검토|평가|봐줘|장점|단점|약점|강점|확장성|문제점|리스크|개선점|의견|판단|괜찮|어때|어떤\s*거?\s*같|review|evaluate|assessment|strength|weakness|pros?\s*and\s*cons?|extensibility|scalability|risk|issue)/i.test(normalized);
    if (asksReview) {
        return 'review-evaluation';
    }

    const asksImplementation = /(고쳐|수정|개선해|구현|추가|삭제|리팩토링|디버그|fix|implement|add|remove|refactor|debug)/i.test(normalized);
    if (asksImplementation) {
        return 'implementation';
    }

    const explicitKnowledgeCreation = /((?:이|그|현재|해당)?\s*(?:프로젝트|프로그램|코드베이스).{0,20}(?:대한|기반|관련).{0,20}지식.{0,12}(?:만들|생성|정리|문서화|기록|저장))|(지식.{0,12}(?:만들|생성|정리|문서화|기록|저장).{0,20}(?:프로젝트|프로그램|코드베이스))|(project\s+knowledge.{0,20}(?:create|generate|record|document|overview))|((?:create|generate|record|document).{0,20}project\s+knowledge)/i.test(normalized);
    if (explicitKnowledgeCreation) {
        return 'knowledge-creation';
    }

    const asksDocumentation = /(문서화(?:해|해줘|를)|문서(?:로)?\s*(?:정리|작성|만들)|README|가이드|wiki|documentation|document\s+this|write\s+docs)/i.test(normalized);
    if (asksDocumentation) {
        return 'documentation';
    }

    const asksThinking = /(설계|아키텍처|구조|방향|생각|의견|판단|어떤\s*거?\s*같|어때|architecture|design|structure|direction|opinion|think|judge)/i.test(normalized);
    if (asksThinking) {
        return 'thinking';
    }

    return 'general';
}

export function isProjectKnowledgeCreationRequest(prompt: string): boolean {
    return classifyLocalProjectIntent(prompt) === 'knowledge-creation';
}

export function isProjectReviewEvaluationRequest(prompt: string): boolean {
    return classifyLocalProjectIntent(prompt) === 'review-evaluation';
}

/**
 * Intent 별로 모델에게 어떤 출력 contract 를 강제할지 적는 가이던스 블록.
 * `review-evaluation` 만 길고 strict (사용자가 옛 리뷰가 template 같다고 피드백한
 * 항목들 일일이 반영), 나머지 intent 는 간결한 contract.
 */
export function buildLocalProjectIntentGuidance(intent: LocalProjectIntent): string {
    switch (intent) {
        case 'review-evaluation':
            return [
                'Intent operating contract — Code Review:',
                'The user wants a real review, not a meta-plan of how to review.',
                'OUTPUT FORMAT: 선택적 마크다운 — 비교/수치는 표, 경고는 "> " 인용구, 파일/함수명은 인라인 코드, 장식 목적 사용 금지. Bullets use "- ". Long answers MUST start with a "핵심 요약" block (2~4 bullets) before any detail.',
                'Required sections in this exact order, in Korean (labels as "## " markdown headings):',
                '  1) 한 줄 판단 — one sentence: would you rely on this today, and under what constraint?',
                '  2) 잘된 점 — 2~4 concrete strengths. Each MUST cite a specific file path (and a function or section if you can name one) and explain WHY it works, not just that it exists.',
                '  3) 부족한 점 — 2~4 concrete weaknesses or risks. Same rule: cite a specific file/area, name the actual problem (race condition, missing retry, coupling, etc.), and say what breaks because of it.',
                '  4) 사용자 관점 개선 — 2~4 changes phrased from the END USER\'s perspective ("when X happens, the user currently sees Y; they should see Z"). Tie each to a code location that needs to change.',
                '  5) 다음 한 수 — exactly one next action, small enough to do this week.',
                '',
                'Hard rules — these are the things that made past reviews feel like a template:',
                '- Do NOT write meta-sentences like "확인해야 합니다", "다음 리뷰에서는 ~를 보면 됩니다", "~로 보입니다", "~인지 확인하는 것이 핵심입니다". Either you observed it or you read the file with <read_file> right now.',
                '- Do NOT list the file structure tree back to the user — they already see it. Reference files only when making a specific claim.',
                '- Do NOT use the words "blind spot", "파이프라인 안정화", "골격은 있습니다" — these are tells of the old canned response.',
                '- If a file preview is insufficient to support a claim, USE <read_file path="..."> immediately to read it before writing the section. Do not hedge with "preview만으로는 판단할 수 없습니다".',
                '- Strengths and weaknesses must be SPECIFIC to this project. A sentence that would still be true if you swapped the project name is not allowed.',
                '- Skip every section that has nothing concrete to say. Better to write 잘된 점 with 2 strong items than 4 weak ones.',
            ].join('\n');
        case 'knowledge-creation':
            return [
                'Intent operating contract:',
                '- Create a reusable project knowledge note from inspected evidence.',
                '- Do not ask for scope if the path is accessible; choose a small MVP overview by default.',
                '- Separate confirmed structure from inferred purpose and next deep-dive targets.',
            ].join('\n');
        case 'implementation':
            return [
                'Intent operating contract:',
                '- Treat this as a change request, not advice.',
                '- Inspect the relevant files, make the smallest safe implementation, and verify it.',
                '- Preserve unrelated user changes.',
            ].join('\n');
        case 'documentation':
            return [
                'Intent operating contract:',
                '- Produce or update documentation from inspected evidence.',
                '- Separate user-facing usage docs from internal architecture notes.',
                '- Avoid claiming behavior that is not visible in code or existing docs.',
            ].join('\n');
        case 'thinking':
            return [
                'Intent operating contract:',
                '- Act as a thinking partner.',
                '- Give a direct opinion, then split confirmed facts, inferences, risks, decision forks, and one next move.',
                '- Avoid generic encouragement.',
            ].join('\n');
        default:
            return [
                'Intent operating contract:',
                '- Use the inspected local files as grounding.',
                '- If the user request is ambiguous, answer the most likely project-oriented task and state the assumption.',
            ].join('\n');
    }
}

/**
 * "Astra Stance Layer" — 모델이 template-style 답변이 아니라 *시니어 협업자 톤*
 * 으로 직접 의견을 내도록 톤·접근법을 prepend. intent 가 review/thinking 이면
 * 더 강하게 opinionated, 나머지는 light persona.
 */
export function buildAstraStanceContext(prompt: string, localPathContext: string): string {
    const intent = localPathContext ? classifyLocalProjectIntent(prompt) : 'general';
    const wantsThinkingPartner = isThinkingPartnerRequest(prompt) || intent === 'review-evaluation' || intent === 'thinking';

    const lines = [
        '[ASTRA STANCE LAYER]',
        'Use this to make the response feel like Astra thinking with the user, not a template being filled.',
        '',
        'Voice:',
        '- Warm, direct, and grounded. Do not over-explain the framework.',
        '- Prefer sentences that sound like a senior collaborator: "나는 여기서 X를 먼저 볼 것 같아요" / "이건 좋아요, 그런데 위험은 Y예요."',
        '- Avoid sterile balance like "장단점이 있습니다" unless you immediately make a call.',
        '',
        'Judgment habits:',
        '- State the real bet you think the user is making.',
        '- Name one thing to keep, one thing to cut, and one thing to verify next when relevant.',
        '- Use the user’s own goal as the yardstick, not generic best practice.',
        '- If there are many possible improvements, choose the one that compounds the project fastest.',
        '',
        wantsThinkingPartner
            ? 'For this request, be especially opinionated. Give a clear personal verdict before structure.'
            : 'For this request, keep the persona light but still make concrete choices.',
        intent !== 'general' ? `Local project intent for tone: ${intent}` : '',
    ];

    if (intent === 'review-evaluation') {
        lines.push(
            '',
            'Review stance:',
            '- Do not merely list strengths and weaknesses. Say whether you would rely on this project today and under what constraint.',
            '- Prefer the product-owner question: "What has to become boring and reliable before this deserves expansion?"',
            '- If evidence is shallow, say which file would change your opinion most.',
        );
    }

    if (intent === 'thinking') {
        lines.push(
            '',
            'Thinking stance:',
            '- Do not solve every branch. Reduce the user’s uncertainty to the next decision.',
            '- A useful answer may say: "I would not expand yet" or "This deserves a spike, not a feature."',
        );
    }

    return lines.filter(Boolean).join('\n');
}
