/* Security guard for prompt-protected banner generation.
   Keep canonical generation prompts off the client. This file only contains leak-prevention checks. */

const BANNR_SECURITY = Object.freeze({
  aiSubmitEnabled: false,
  requireImageAudit: true,
  allowExternalAiEndpoint: false,
  blockedResponseKeys: [
    "prompt",
    "systemPrompt",
    "developerPrompt",
    "rawPrompt",
    "rawRequest",
    "messages",
    "instructions",
    "chainOfThought",
  ],
  blockedTextPatterns: [
    /内部指示|システムプロンプト|開発者プロンプト|プロンプト全文|raw\s*prompt/i,
    /system\s*prompt|developer\s*prompt|hidden\s*instruction|internal\s*instruction/i,
    /以下の(指示|プロンプト)を(そのまま)?(表示|出力|描画)/i,
    /(プロンプト|指示).{0,12}(全文|本文).{0,12}(表示|出力|描画)/i,
    /#{2,}\s*.{0,20}\n(?:[-*]\s*.{4,}\n){4,}/,
  ],
});

function isSameOriginEndpoint(endpoint) {
  if (!endpoint) return false;
  try {
    const url = new URL(endpoint, window.location.origin);
    return url.origin === window.location.origin;
  } catch (e) {
    return false;
  }
}

function findBlockedResponseKeys(value, path = "response") {
  if (!value || typeof value !== "object") return [];
  const hits = [];
  Object.keys(value).forEach((key) => {
    const nextPath = `${path}.${key}`;
    if (BANNR_SECURITY.blockedResponseKeys.includes(key)) hits.push(nextPath);
    hits.push(...findBlockedResponseKeys(value[key], nextPath));
  });
  return hits;
}

function containsPromptLeakText(value) {
  if (typeof value === "string") {
    return BANNR_SECURITY.blockedTextPatterns.some((rx) => rx.test(value));
  }
  if (Array.isArray(value)) return value.some(containsPromptLeakText);
  if (value && typeof value === "object") return Object.values(value).some(containsPromptLeakText);
  return false;
}

function assertNoPromptLeak(response) {
  const keyHits = findBlockedResponseKeys(response);
  if (keyHits.length > 0) {
    throw new Error(`AI response contains blocked debug/prompt fields: ${keyHits.join(", ")}`);
  }
  if (containsPromptLeakText(response)) {
    throw new Error("AI response appears to contain protected prompt text.");
  }
  return response;
}

function buildImageAuditPayload({ imageData, ocrText = "", metadata = {}, brief = {} }) {
  return {
    kind: "sns_ad_banner_image_audit",
    version: 1,
    submittedAt: new Date().toISOString(),
    image: {
      provided: Boolean(imageData),
      dataUrl: imageData || null,
      ocrText: ocrText || "",
    },
    metadata,
    briefSummary: {
      productOrServiceName: brief.productOrServiceName || brief.name || "",
      target: brief.target || "",
      ratio: brief.ratio || "",
      platforms: brief.platforms || [],
    },
    checks: [
      "画像内に内部プロンプト本文、内部指示、システム文、開発者文が描画されていないこと",
      "画像内に長文のプロンプト断片や箇条書き指示が出ていないこと",
      "入力情報にないNo.1、受賞、推薦、効果保証、価格、割引率、期間、成分、機能が描画されていないこと",
      "規制対象ジャンルで問題になり得る断定表現が描画されていないこと",
      "商品名、CTA、価格などの表示が入力情報と矛盾していないこと",
    ],
  };
}

async function auditGeneratedBannerImage({ imageData, ocrText = "", metadata = {}, brief = {} }) {
  const payload = buildImageAuditPayload({ imageData, ocrText, metadata, brief });

  if (containsPromptLeakText(payload.image.ocrText)) {
    return { ok: false, reason: "prompt_text_detected_in_image_text", payload };
  }

  if (typeof window.BANNR_IMAGE_AUDIT_HANDLER === "function") {
    return assertNoPromptLeak(await window.BANNR_IMAGE_AUDIT_HANDLER(payload));
  }

  const endpoint = window.__BANNR_IMAGE_AUDIT_ENDPOINT__ || "";
  if (!endpoint) {
    return {
      ok: false,
      reason: "image_audit_not_configured",
      message: "画像生成を有効化する前に、サーバー側の画像監査APIを設定してください。",
      payload,
    };
  }

  if (!BANNR_SECURITY.allowExternalAiEndpoint && !isSameOriginEndpoint(endpoint)) {
    throw new Error("External image audit endpoint is blocked by default.");
  }

  const res = await fetch(endpoint, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(payload),
  });
  if (!res.ok) throw new Error(`Image audit endpoint failed: ${res.status}`);
  const data = await res.json();
  return assertNoPromptLeak(data);
}

Object.assign(window, {
  BANNR_SECURITY,
  isSameOriginEndpoint,
  assertNoPromptLeak,
  buildImageAuditPayload,
  auditGeneratedBannerImage,
});
