// Why not: previewAllowedOrigins は本来 string[] だが、値が未設定・型不整合（例えば将来別の
// 経路で書き換えられた場合）でも Array メソッド呼び出し自体で例外を投げないよう、配列でなければ
// 空配列扱いにする。ACMS.Config は index signature が any のため型チェックだけでは防げない。
export const getPreviewAllowedOrigins = (): string[] => {
  const origins = ACMS.Config.previewAllowedOrigins;
  return Array.isArray(origins) ? origins : [];
};

// Why not: 呼び出し元の url は window.postMessage 経由でプレビュー対象から届く（DeviceMode 側で
// origin/e.source を検証済みだが、単一箇所の判定に依存させず多層防御として rewriteUrl 側でも
// 許可オリジンを再チェックする）。相対 URL は現在ページ（管理画面）自身の origin として解決され、
// getManagedOrigins() は own（HTTP_HOST）側を常に含めて返すため、素通しにできる。
const isAllowedOrigin = (uri: string): boolean => {
  let origin: string;
  try {
    origin = new URL(uri, window.location.href).origin;
  } catch {
    return false;
  }
  return getPreviewAllowedOrigins().includes(origin);
};

export const rewriteUrl = (uri: string) => {
  if (!uri) {
    return uri;
  }
  if (!isAllowedOrigin(uri)) {
    // Why not: 許可オリジン外の URL に CSRF トークンを付けて iframe に読み込ませると、
    // プレビュー対象に仕込まれた JS が任意の外部 URL にトークンを持ち出す経路になるため、
    // トークンを付けずに（書き換えずに）そのまま返す。
    return uri;
  }
  const key = 'acms-preview-mode';
  const regex = new RegExp(`([?&])${key}=.*?(&|$)`, 'i');
  const separator = uri.indexOf('?') !== -1 ? '&' : '?';
  let hash = '';
  if (uri.match(/#(.*)$/)) {
    uri = uri.replace(/#(.*)$/, (val1) => {
      hash = val1;
      return '';
    });
  }
  if (uri.match(regex)) {
    return uri.replace(regex, `$1${key}=${window.csrfToken}$2`);
  }
  return `${uri + separator + key}=${window.csrfToken}&timestamp=${new Date().getTime()}${hash}`;
};
