/**
 * Shared prompt intent detection for CLI routing, V3 hints, and rescue gating.
 * Keep aligned with V3-Code-Agent/agent.py _classify_request heuristics.
 */
const CLI_SHAPING_BLOCK = /(?:^|\n\n)Platform:\s*(?:Windows|macOS|Linux)\.[\s\S]*?(?=\n\n[A-Z][^\n]{0,40}:|\s*$)/i;
const READONLY_SHAPING_BLOCK = /(?:^|\n\n)(?:Read-only analysis mode is active\.|Diagnostic mode is active\.)[\s\S]*?(?=\n\n[A-Z][^\n]{0,40}:|\s*$)/i;
const BUILD_VERBS = /\b(build|create|make|implement|complete|fix|repair|edit|modify|write|generate|add|finish|scaffold|develop|update|change|refactor|want|need|require|looking for|let's|let us|we need|we should|erstelle|erstellen|schreib|schreibe|bearbeite)\b/i;
const ARTIFACT_NOUNS = /\b(file|files|project|game|spiel|app|website|html5|frontend|component|feature|code|workspace|repo|clone|replica|remake|page|site|screen|button|popup|modal|alert|canvas|sprite|level|levels|enemy|enemies|character|npc|world|scene|script|module|api|database|config|landing|dashboard|platformer|arcade|playable|collectible|scoreboard|leaderboard|pitfall|pacman|rogue|html|css|javascript|typescript)\b/i;
/** Canvas/playable games only — bare "html5" or "website" must NOT match. */
const GAME_INTENT = /\b(game|spiel|playable|babylon(?:\.js|js)?|vge|webgl|3d\s+(?:game|runner|prototype|world|experience)|html5\s+(?:game|canvas)|html5\s+game|canvas\s+game|game\s+canvas|arcade|platformer|side[- ]?scroller|pitfall|pac[- ]?man|tetris|snake|breakout|pong|roguelike|metroidvania|tower\s+defense|clone\s+of\s+(?:a\s+)?(?:game|pitfall|pac|mario|zelda|arcade)|gameplay|collectible|boss\s+fight|level\s+design|sprite\s+sheet|wild\s+(?:boar|pig|forest)|forest\s+pig)\b/i;
const WEB_PAGE_INTENT = /\b(website|web\s*site|webpage|web\s*page|landing\s+page|home\s*page|index\.html|html\s+page|static\s+page|single\s+page|popup|alert|modal|hello\s+world)\b/i;
const CLONE_BUILD = /\bclone\s+of\b|\b(build|create|make)\s+(?:a|an|the|us|me)?\s*(?:clone|replica|remake|port)\b/i;
const READ_ONLY_INTENT = /\b(analy[sz]e|analyse|analysis|audit|review|inspect|proof|understand|summari[sz]e|scan|read[\s-]?only|where we left|what is|how does|show me|tell me|identify\s+gaps?|gap\s+analysis|production\s+blockers?)\b/i;
const EXPLICIT_WRITE_VERBS = /\b(implement|write|edit|modify|update|fix|repair|create|build|generate|scaffold|deploy|refactor|develop|integrate|correct|apply|patch)\b/i;
const TRIVIAL_HTML_PAGE = /\b(hello\s*world|simple\s+(?:html|web|page|site)|html5\s+website|html\s+5\s+website|popup|alert\s*\(|show\s+a\s+popup|one\s+page|single\s+html)\b/i;
/** User explicitly grants write permission after an analysis or confirmation gate. */
const WRITE_PERMISSION_GRANT = /\b(?:hereby\s+confirm|i\s+confirm|confirm(?:ed)?\s+that|give\s+(?:you|permission)|granting\s+permission|allow\s+(?:you|me\s+to)|you\s+(?:may|can|have\s+permission\s+to)|permission\s+to|authorized?\s+to|approve(?:d)?\s+(?:the\s+)?(?:changes?|writes?|edits?)|go\s+ahead\s+and(?:\s+write|\s+apply|\s+make|\s+do)?|do\s+all\s+the\s+changes|apply\s+(?:the\s+)?(?:changes?|fixes?|fix)|proceed\s+with\s+(?:the\s+)?(?:changes?|fixes?|implementation|writes?)|make\s+(?:the\s+)?changes|please\s+write)\b/i;
/** Fix/correct/repair syntax or errors — write path without requiring artifact nouns. */
const FIX_CORRECT_INTENT = /\b(correct|fix|repair|resolve|patch|address|remedy)\b[\s\S]{0,48}\b(syntax|errors?|bugs?|issues?|mistakes?|typos?)\b|\b(syntax|errors?|bugs?|issues?)\b[\s\S]{0,48}\b(correct|fix|repair|resolve|patch)\b/i;
/** Read-only audit: check/review/find issues without an paired fix/implement verb nearby. */
const READ_ONLY_CHECK = /\b(check|verify|audit|inspect|review|investigate|look\s+for|find|scan|validate|examine)\b[\s\S]{0,60}\b(syntax|errors?|bugs?|issues?|missing|gaps?|functionality)\b/i;
/** Strip CLI-appended platform / mode shaping so it cannot flip quality profiles. */
export function stripExecutionShaping(prompt) {
    return String(prompt || '')
        .replace(CLI_SHAPING_BLOCK, '')
        .replace(READONLY_SHAPING_BLOCK, '')
        .trim();
}
export function hasBuildVerb(prompt) {
    return BUILD_VERBS.test(stripExecutionShaping(prompt));
}
export function hasArtifactNoun(prompt) {
    return ARTIFACT_NOUNS.test(stripExecutionShaping(prompt));
}
/** Game clones require a game target — generic "clone of X" must not imply game-build. */
const GAME_CLONE_TARGET = /\bclone\s+of\s+(?:a\s+)?(?:the\s+)?(?:game|pitfall|pac[- ]?man|mario|zelda|tetris|snake|arcade|spiel)\b/i;
export function inferGameEngine(prompt) {
    const text = stripExecutionShaping(prompt);
    if (/\bthree(?:\.js|js)?\b/i.test(text))
        return 'three';
    if (/\bbabylon(?:\.js|js)?\b|\bvge\b|vigthoria gaming engine/i.test(text))
        return 'babylon';
    if (/\b3d\s+(?:game|runner|prototype|world|experience)\b|\bwebgl\b/i.test(text))
        return 'babylon';
    return 'canvas-2d';
}
export function hasGameIntent(prompt) {
    const text = stripExecutionShaping(prompt);
    if (GAME_INTENT.test(text)) {
        return true;
    }
    if (GAME_CLONE_TARGET.test(text)) {
        return true;
    }
    if (CLONE_BUILD.test(text) && /\b(game|spiel|pitfall|pacman|arcade|platformer|playable|canvas)\b/i.test(text)) {
        return true;
    }
    return false;
}
const CONTINUE_VERB = /\b(?:continue|contiune|continu|proceed|resume|keep\s+going|go\s+on|carry\s+on|pick\s+up\s+where)\b/i;
const CONTINUE_OBJECT = /\b(?:task|tasks|work|build|building|implementation|project|run|plan|planning|remaining|unfinished|missing|components?|next\s+steps?|previous|last|where\s+we\s+left|hyperloop|report)\b/i;
/** True when the CLI already expanded a /continue-style follow-up prompt. */
export function isBuiltContinuePrompt(prompt) {
    return /^Continue the previous agent run/i.test(stripExecutionShaping(prompt));
}
/** True when the CLI already expanded a /retry-style follow-up prompt. */
export function isBuiltRetryPrompt(prompt) {
    const text = stripExecutionShaping(prompt);
    return /^(?:Resume the previous agent run|Retry the previous request)/i.test(text);
}
export function isAgentContinuePrompt(prompt) {
    const text = stripExecutionShaping(prompt).trim();
    if (!text) {
        return false;
    }
    if (isBuiltContinuePrompt(text) || isBuiltRetryPrompt(text)) {
        return false;
    }
    if (/^\/(?:continue|contiune|contiunue)$/i.test(text)) {
        return true;
    }
    if (/\bcontinue\s+(?:the\s+)?(?:previous|last|current)\s+(?:agent\s+)?run\b/i.test(text)) {
        return true;
    }
    if (/\bresume\s+(?:the\s+)?(?:failed|unfinished)\b/i.test(text)) {
        return true;
    }
    if (/\bplanner\s+produced\s+\d+\s+execution\s+tasks\b/i.test(text)) {
        return true;
    }
    if (CONTINUE_VERB.test(text) && CONTINUE_OBJECT.test(text)) {
        return true;
    }
    if (/^(?:please\s+)?(?:continue|contiune|proceed)(?:[!?.]|$)/i.test(text)) {
        return true;
    }
    return false;
}
export function isAgentRetryPrompt(prompt) {
    const text = stripExecutionShaping(prompt).trim();
    if (!text || isBuiltContinuePrompt(text) || isBuiltRetryPrompt(text)) {
        return false;
    }
    if (/^\/retry$/i.test(text)) {
        return true;
    }
    return /\b(?:retry|re-?try)\s+(?:the\s+)?(?:failed|last|previous|unfinished)\b/i.test(text);
}
export function isContinueOrRetryPrompt(prompt) {
    return isAgentContinuePrompt(prompt) || isAgentRetryPrompt(prompt);
}
export function hasWebPageIntent(prompt) {
    const text = stripExecutionShaping(prompt);
    return WEB_PAGE_INTENT.test(text) || /\bhtml5\s+website\b/i.test(text);
}
export function isTrivialHtmlPageRequest(prompt) {
    const text = stripExecutionShaping(prompt);
    if (isContinueOrRetryPrompt(prompt)) {
        return false;
    }
    if (!hasBuildVerb(prompt) && !/\b(write|create|make|show|want|need|looking\s+for)\b/i.test(text)) {
        return false;
    }
    if (hasGameIntent(prompt)) {
        return false;
    }
    if (text.length > 420) {
        return false;
    }
    if (/\b(multi[- ]?page|full\s+saas|dashboard|e[\s-]?commerce|auth|database|backend|api|microservice)\b/i.test(text)) {
        return false;
    }
    return TRIVIAL_HTML_PAGE.test(text)
        || (hasWebPageIntent(prompt) && /\b(html5|html5\s+website|website|popup|hello\s*world)\b/i.test(text));
}
export function hasCloneBuildIntent(prompt) {
    return CLONE_BUILD.test(stripExecutionShaping(prompt)) && hasBuildVerb(prompt);
}
export function isWritePermissionGrant(prompt) {
    const text = stripExecutionShaping(prompt);
    return WRITE_PERMISSION_GRANT.test(text)
        || /\ballow\s+you\s+to\s+do\s+all\s+the\s+changes\b/i.test(text)
        || /\b(?:i\s+)?(?:allow|permit)\s+you\s+to\s+write\b/i.test(text);
}
/** Short or extended confirmations that should chain to the prior actionable request. */
export function isConfirmationFollowUp(prompt) {
    const normalized = stripExecutionShaping(prompt).trim().toLowerCase().replace(/[.!?]+$/g, '').replace(/\s+/g, ' ');
    if (!normalized) {
        return false;
    }
    if (/^(ja|ja bitte|ja bitte mach das|mach das|bitte mach das|genau|ok|okay|yes|yes please|please do|do it|go ahead|continue|proceed|make it so)$/.test(normalized)) {
        return true;
    }
    if (/^(please\s+)?(?:do\s+it|make\s+(?:the\s+)?changes|apply\s+(?:them|the\s+fixes|changes|the\s+fix)|fix\s+(?:them|it|now)|go\s+ahead)$/.test(normalized)) {
        return true;
    }
    return isWritePermissionGrant(prompt);
}
/** True when the CLI expanded a write-confirmation follow-up for V3. */
export function isBuiltWriteConfirmationPrompt(prompt) {
    return /^The user confirmed they want file changes applied/i.test(stripExecutionShaping(prompt));
}
export function hasFixOrCorrectIntent(prompt) {
    return FIX_CORRECT_INTENT.test(stripExecutionShaping(prompt));
}
export function isReadOnlyCheckIntent(prompt) {
    const text = stripExecutionShaping(prompt);
    if (!READ_ONLY_CHECK.test(text)) {
        return false;
    }
    if (hasFixOrCorrectIntent(prompt) || isWritePermissionGrant(prompt)) {
        return false;
    }
    if (/\b(?:fix|correct|repair|implement|apply|write|change|update)\b/i.test(text)) {
        return false;
    }
    return true;
}
export function hasExplicitWriteIntent(prompt) {
    const text = stripExecutionShaping(prompt);
    if (isWritePermissionGrant(prompt)) {
        return true;
    }
    if (hasFixOrCorrectIntent(prompt)) {
        return true;
    }
    if (isReadOnlyCheckIntent(prompt)) {
        return false;
    }
    return (BUILD_VERBS.test(text) && ARTIFACT_NOUNS.test(text))
        || hasCloneBuildIntent(prompt)
        || (BUILD_VERBS.test(text) && hasGameIntent(prompt));
}
export function taskRequiresWorkspaceChanges(prompt) {
    const text = String(prompt || '').trim();
    const shaped = stripExecutionShaping(text);
    const readOnlyIntent = READ_ONLY_INTENT.test(shaped) || isReadOnlyCheckIntent(text);
    const explicitWriteIntent = hasExplicitWriteIntent(text);
    if (readOnlyIntent && !explicitWriteIntent) {
        return false;
    }
    return explicitWriteIntent;
}
export function resolveClassificationPrompt(prompt, context = {}) {
    if (isBuiltContinuePrompt(prompt) || isBuiltRetryPrompt(prompt) || isBuiltWriteConfirmationPrompt(prompt)) {
        return prompt;
    }
    const prior = String(context.priorPrompt || '').trim();
    if (prior && (isConfirmationFollowUp(prompt) || isWritePermissionGrant(prompt))) {
        return `${prompt}\n\nPrior actionable request:\n${prior}`;
    }
    return prompt;
}
export function taskRequiresWorkspaceChangesWithContext(prompt, context = {}) {
    if (isBuiltWriteConfirmationPrompt(prompt) || isWritePermissionGrant(prompt)) {
        const prior = String(context.priorPrompt || '').trim();
        if (prior) {
            return true;
        }
        return isWritePermissionGrant(prompt);
    }
    const effective = resolveClassificationPrompt(prompt, context);
    if (taskRequiresWorkspaceChanges(effective)) {
        return true;
    }
    const prior = String(context.priorPrompt || '').trim();
    if (prior && isConfirmationFollowUp(prompt)) {
        return true;
    }
    return false;
}
export function hasAnalyzeAndBuildIntent(prompt) {
    const text = stripExecutionShaping(prompt);
    return /\b(analy[sz]e|analyse)\b/i.test(text)
        && /\b(complete|finish|fix|implement|build|repair|missing\s+elements?)\b/i.test(text)
        && hasExplicitWriteIntent(prompt);
}
export function inferAgentTaskType(prompt) {
    const text = stripExecutionShaping(prompt);
    if (isBuiltWriteConfirmationPrompt(prompt)) {
        if (hasGameIntent(prompt)) {
            return 'game-build';
        }
        if (hasFixOrCorrectIntent(prompt) || /\bsyntax\b/i.test(text)) {
            return 'repair';
        }
        return 'implementation';
    }
    if (hasFixOrCorrectIntent(prompt)) {
        if (hasGameIntent(prompt)) {
            return 'game-build';
        }
        return 'repair';
    }
    if (hasAnalyzeAndBuildIntent(prompt)) {
        if (hasGameIntent(prompt)) {
            return 'game-build';
        }
        if (hasWebPageIntent(prompt)) {
            return 'web-build';
        }
        return 'implementation';
    }
    if (isReadOnlyCheckIntent(prompt)) {
        return 'debugging';
    }
    if (/\b(inspect|analyze|analyse|audit|review|find|diagnose|debug|trace|compare|diff|investigate)\b/i.test(text)
        && !hasExplicitWriteIntent(prompt)) {
        return 'debugging';
    }
    if (/\b(analy[sz]e|analyse|audit|review|inspect|identify\s+gaps?|gap\s+analysis|production\s+blockers?|read[\s-]?only)\b/i.test(text)
        && !hasExplicitWriteIntent(prompt)) {
        return 'analysis';
    }
    if (hasBuildVerb(prompt) && !/\b(analy[sz]e|analyse|audit|review|inspect)\b/i.test(text)) {
        if (hasGameIntent(prompt)) {
            return 'game-build';
        }
        if (hasWebPageIntent(prompt)) {
            return 'web-build';
        }
        return 'implementation';
    }
    if (hasExplicitWriteIntent(prompt)) {
        return 'implementation';
    }
    return 'general';
}
export function inferAgentTaskTypeWithContext(prompt, context = {}) {
    const prior = String(context.priorPrompt || '').trim();
    if ((isConfirmationFollowUp(prompt) || isWritePermissionGrant(prompt) || isBuiltWriteConfirmationPrompt(prompt)) && prior) {
        const priorType = inferAgentTaskType(prior);
        if (isWritePermissionGrant(prompt) || isBuiltWriteConfirmationPrompt(prompt)) {
            if (priorType === 'analysis' || priorType === 'debugging' || priorType === 'general') {
                if (hasFixOrCorrectIntent(prior) || /\bsyntax\b/i.test(prior)) {
                    return 'repair';
                }
                if (hasGameIntent(prior)) {
                    return 'game-build';
                }
                return 'implementation';
            }
        }
        if (priorType !== 'general') {
            return priorType;
        }
    }
    return inferAgentTaskType(resolveClassificationPrompt(prompt, context));
}
export function shouldSkipAnalysisRescue(liveOutcome) {
    if (liveOutcome.requiresWorkspaceChanges) {
        return true;
    }
    if ((liveOutcome.tasksTotal || 0) > 0) {
        return true;
    }
    if ((liveOutcome.changedFileCount || 0) > 0) {
        return true;
    }
    return false;
}
export function isPlannerBuildTask(agentTaskType, prompt) {
    const kind = String(agentTaskType || '').toLowerCase();
    if (isTrivialHtmlPageRequest(prompt)) {
        return false;
    }
    if (/^(game-build|web-build|implementation|build|repair|refactor-build)$/.test(kind)) {
        return true;
    }
    return hasExplicitWriteIntent(prompt) && !READ_ONLY_INTENT.test(stripExecutionShaping(prompt));
}
export function resolvePlannerAgentTimeoutMs(baseTimeoutMs, agentTaskType, prompt) {
    if (!isPlannerBuildTask(agentTaskType, prompt)) {
        return baseTimeoutMs;
    }
    const raw = process.env.VIGTHORIA_AGENT_PLANNER_TIMEOUT_MS || process.env.V3_AGENT_PLANNER_TIMEOUT_MS;
    if (!raw) {
        return baseTimeoutMs;
    }
    const extended = Number.parseInt(raw, 10);
    if (!Number.isFinite(extended) || extended <= 0) {
        return baseTimeoutMs;
    }
    return Math.max(baseTimeoutMs, extended);
}
/** V3 workflow mode: suppress write path when the user did not ask for file changes. */
export function resolveWorkflowType(agentTaskType, prompt, context = {}) {
    if (isBuiltWriteConfirmationPrompt(prompt) || isWritePermissionGrant(prompt)) {
        return 'full';
    }
    if (hasAnalyzeAndBuildIntent(prompt)) {
        return 'full';
    }
    if (isBuiltContinuePrompt(prompt) || isBuiltRetryPrompt(prompt)) {
        return taskRequiresWorkspaceChangesWithContext(prompt, context) ? 'full' : 'analysis_only';
    }
    const prior = String(context.priorPrompt || '').trim();
    if (prior && isConfirmationFollowUp(prompt)) {
        return 'full';
    }
    if (!taskRequiresWorkspaceChangesWithContext(prompt, context)) {
        return 'analysis_only';
    }
    const kind = String(agentTaskType || '').toLowerCase();
    if ((kind === 'analysis' || kind === 'debugging' || kind === 'verification')
        && !hasFixOrCorrectIntent(prompt)
        && !isWritePermissionGrant(prompt)) {
        return 'analysis_only';
    }
    return 'full';
}
export function buildExecutionHints(agentTaskType, prompt, options = {}) {
    const context = { priorPrompt: options.priorPrompt ?? null };
    const effectiveTaskType = inferAgentTaskTypeWithContext(prompt, context);
    const workflowType = resolveWorkflowType(effectiveTaskType, prompt, context);
    const kind = String(effectiveTaskType || agentTaskType || 'general').toLowerCase();
    const hints = {
        task_kind: kind,
        requires_file_changes: workflowType === 'analysis_only' ? false : undefined,
        classify_from: String(prompt || ''),
        workflow_type: workflowType,
    };
    if (kind === 'game-build' || hasGameIntent(prompt)) {
        hints.game_engine = inferGameEngine(prompt);
        if (hints.game_engine === 'babylon')
            hints.render_transport = 'client-state';
    }
    if (options.fastPath) {
        hints.fast_path = options.fastPath;
    }
    else if (isTrivialHtmlPageRequest(prompt)) {
        hints.fast_path = 'template-instant';
    }
    return hints;
}
