/**
 * PreToolUse-страж: TodoWrite заявил навык → должен быть в ЖУРНАЛЕ вызовов (М7 Фаза 4a, §4.2).
 * Выполненный todo, claim'ящий Skill, не подтверждённый журналом (канал М1) → блок следующего
 * мутирующего. Session-scope (выполненный todo мог закрыться в прошлом ходе — навык должен быть
 * в журнале за сессию, не обязательно в этом ходе; отличие от coverage, которое turn-scoped).
 *
 * fail-CLOSE (М7 Фаза 0 правило 1). PreToolUse (предотвращение до действия, §4.2 [Pre]).
 */
import { fileURLToPath } from 'url';
import {
  readStdin,
  parseEventJson,
  readTranscript,
  runtimeDir,
  exitDisciplineDecision,
} from './enforce-hook-helpers.mjs';
import {
  extractSkillMentions,
  hardSyncCheck,
} from './todowrite-skill-verifier.mjs';
import { loadJournal } from './action-journal.mjs';
import { extractSkillCalls } from './enforce-skill-journaler.mjs';

/** Find the latest TodoWrite tool_use entries in a transcript. */
export function lastTodoItems(transcript) {
  const recs = transcript || [];
  for (let i = recs.length - 1; i >= 0; i--) {
    const r = recs[i];
    if (r && r.type === 'tool_use' && r.name === 'TodoWrite') {
      return r.input && Array.isArray(r.input.todos) ? r.input.todos : [];
    }
  }
  return [];
}

/**
 * Дедуп regex-артефактов extractSkillMentions: "invoke superpowers:brainstorming" даёт и полное
 * "superpowers:brainstorming", и частичное "superpowers" (invoke-паттерн стопится на двоеточии).
 * Частичное избыточно, если из того же текста есть mention, начинающийся с "<partial>:".
 */
export function deduplicateMentions(mentions) {
  return mentions.filter((m) => {
    const nameColon = m.skill_name + ':';
    const coveredByLonger = mentions.some(
      (other) => other !== m && other.text === m.text && other.skill_name.startsWith(nameColon),
    );
    return !coveredByLonger;
  });
}

export function decide({ todoItems, journalSkillCalls = [] }) {
  const items = Array.isArray(todoItems) ? todoItems : [];
  const rawMentions = extractSkillMentions(items);
  const mentions = deduplicateMentions(rawMentions);
  const calls = (journalSkillCalls || []).map((n) => ({ skill_name: n }));
  const r = hardSyncCheck(mentions, calls);
  if (r.action === 'hard_block_next_mutating') {
    return { block: true, reason: r.reason };
  }
  return { block: false, reason: null };
}

async function main() {
  const event = parseEventJson(await readStdin());
  await exitDisciplineDecision(
    () => {
      const transcript = readTranscript(event.transcript_path);
      const todoItems = lastTodoItems(transcript);
      const { entries } = loadJournal({
        sessionId: event.session_id || 'unknown',
        runtimeDir: runtimeDir(),
      });
      const journalSkillCalls = extractSkillCalls(entries);
      const r = decide({ todoItems, journalSkillCalls });
      return { block: r.block, message: r.block ? `[todowrite-skill-verifier] ${r.reason}` : undefined };
    },
    { label: 'todowrite-skill-verifier' },
  );
}

const isCli = process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1];
if (isCli) main();
