/**
 * Content Security Policy (CSP) 配置
 *
 * 支持 iframe 嵌入场景，允许主站加载彩票系统
 */

// 允许的主站来源（生产须通过环境变量配置）
const ALLOWED_PARENT_ORIGINS: string[] = [
  process.env.NEXT_PUBLIC_MAIN_SITE_URL,
  process.env.NEXT_PUBLIC_PARENT_ORIGIN,
  // 开发环境
  ...(process.env.NODE_ENV === "development"
    ? [
        "http://localhost:5173",
        "http://127.0.0.1:5173",
        "http://localhost:3801",
        "http://127.0.0.1:3801",
      ]
    : []),
].filter((o): o is string => Boolean(o));

function normalizeOrigin(value: string): string | null {
  try {
    return new URL(value).origin;
  } catch {
    return null;
  }
}

export function staticAllowedParentOrigins(): string[] {
  return Array.from(
    new Set(
      ALLOWED_PARENT_ORIGINS
        .map((origin) => normalizeOrigin(origin))
        .filter((origin): origin is string => origin !== null),
    ),
  );
}

/**
 * 生成 CSP 指令字符串
 */
export function generateCSP(extraParentOrigins: string[] = []): string {
  const parentOrigins = Array.from(
    new Set([
      ...staticAllowedParentOrigins(),
      ...extraParentOrigins
        .map((origin) => normalizeOrigin(origin))
        .filter((origin): origin is string => origin !== null),
    ]),
  );

  const directives: Record<string, string[]> = {
    // 默认只允许同源
    "default-src": ["'self'"],

    // 脚本允许同源和内联（Next.js 需要）
    "script-src": ["'self'", "'unsafe-inline'", "'unsafe-eval'"],

    // 样式允许同源和内联
    "style-src": ["'self'", "'unsafe-inline'"],

    // 图片允许同源、data URL 和 blob
    "img-src": ["'self'", "data:", "blob:"],

    // 字体允许同源
    "font-src": ["'self'"],

    // 连接允许同源；API 由 Next 代理到 LOTTERY_API_UPSTREAM
    "connect-src": [
      "'self'",
      // WebSocket 连接
      "ws:",
      "wss:",
    ].filter(Boolean),

    // 媒体允许同源和 blob
    "media-src": ["'self'", "blob:"],

    // 对象不允许
    "object-src": ["'none'"],

    // 框架允许同源和指定父站
    "frame-src": ["'self'", ...parentOrigins],

    // 允许被嵌入到指定父站
    "frame-ancestors": ["'self'", ...parentOrigins],

    // 表单提交允许同源
    "form-action": ["'self'"],

  };

  // 构建 CSP 字符串
  return Object.entries(directives)
    .map(([key, values]) => {
      if (values.length === 0) return key;
      return `${key} ${values.join(" ")}`;
    })
    .join("; ");
}

/**
 * 检测是否允许被 iframe 嵌入
 * @param parentOrigin 父窗口来源
 */
export function isAllowedParent(parentOrigin: string): boolean {
  const origins = staticAllowedParentOrigins();
  if (origins.length === 0) return false;
  return origins.some((origin) => parentOrigin.startsWith(origin));
}

/**
 * 安全头配置（用于 next.config.ts）
 */
export const nonCspSecurityHeaders = [
  {
    key: "X-Content-Type-Options",
    value: "nosniff",
  },
  {
    key: "Referrer-Policy",
    value: "strict-origin-when-cross-origin",
  },
  {
    key: "Permissions-Policy",
    value: "camera=(), microphone=(), geolocation=()",
  },
];

export const securityHeaders = [
  {
    key: "Content-Security-Policy",
    value: generateCSP(),
  },
  ...nonCspSecurityHeaders,
];
