(function attachEvidenceGuidance(global) {
  function searchableEvidenceItems(submission) {
    return (submission?.evidence || []).filter((item) => ["naver", "google", "llm", "failure"].includes(item.source));
  }

  function directEvidenceItems(submission) {
    return (submission?.evidence || []).filter((item) => ["full", "partial", "page"].includes(item.matchType) || item.contributed);
  }

  function realSearchableEvidenceItems(submission) {
    return searchableEvidenceItems(submission).filter((item) => item.source !== "failure");
  }

  function externalProviderStates(submission) {
    // The backend always injects internal:"ok", so it must be excluded — otherwise
    // every submission looks like it has had an external search attempted.
    return Object.entries(submission?.providerState || {})
      .filter(([provider]) => provider !== "internal")
      .map(([, status]) => status);
  }

  function hasSearchAttempt(submission) {
    const providerStates = externalProviderStates(submission);
    return Boolean(
      submission?.queryHistory?.length ||
        searchableEvidenceItems(submission).length ||
        providerStates.some((status) => ["ok", "covered", "empty", "failed"].includes(status)),
    );
  }

  function evidenceNeedsFollowup(submission) {
    if (!submission || !hasSearchAttempt(submission)) return false;
    // Use the failure-excluded count so this gate agrees with the count used in
    // evidenceFollowupReasons; counting failure items here suppressed legitimate
    // followups that the reasons function would have reported.
    return directEvidenceItems(submission).length === 0 || realSearchableEvidenceItems(submission).length < 2;
  }

  function evidenceFollowupReasons(submission) {
    if (!submission || !hasSearchAttempt(submission)) return [];

    const reasons = [];
    const directCount = directEvidenceItems(submission).length;
    const searchableCount = realSearchableEvidenceItems(submission).length;
    const providerStates = Object.values(submission.providerState || {});

    if (directCount === 0) reasons.push("직접 매칭 또는 원문 페이지 근거가 없습니다.");
    if (searchableCount < 2) reasons.push("검색 근거가 2건 미만입니다.");
    if (providerStates.includes("empty")) reasons.push("외부 검색 tool이 빈 결과를 반환했습니다.");
    if (providerStates.includes("failed")) reasons.push("외부 검색 tool 실패 이력이 있습니다.");

    return reasons;
  }

  function normalizedQuerySeed(submission) {
    return String(submission?.title || submission?.id || "")
      .replace(/\s+/g, " ")
      .trim();
  }

  function suggestedEvidenceQueries(submission) {
    const seed = normalizedQuerySeed(submission);
    if (!seed) return [];

    const existingQueries = new Set((submission.queryHistory || []).map((query) => String(query.query || "").trim().toLowerCase()));
    return [seed, `${seed} 저작권`, `${seed} 공식`, `${seed} 이미지 출처`]
      .filter((query, index, list) => query && list.indexOf(query) === index)
      .filter((query) => !existingQueries.has(query.toLowerCase()))
      .slice(0, 4);
  }

  global.OperatorEvidenceGuidance = {
    searchableEvidenceItems,
    directEvidenceItems,
    hasSearchAttempt,
    evidenceNeedsFollowup,
    evidenceFollowupReasons,
    normalizedQuerySeed,
    suggestedEvidenceQueries,
  };
})(window);
