/**
 * GraphQL urql client 创建（ai14）
 *
 * ARB-002 裁决：Shell 暴露 GraphQL client 单例，student-portal 复用。
 * 当 NEXT_PUBLIC_MF_ENABLED=true 时，provider.tsx 优先使用 Shell 的 useGraphQLClient。
 * 当 NEXT_PUBLIC_MF_ENABLED=false（独立壳模式）时，使用本文件创建的独立 urql client。
 *
 * 独立 client 配置：
 * - url: NEXT_PUBLIC_GRAPHQL_ENDPOINT（默认 /api/v1/student/graphql）
 * - fetchOptions: credentials=include + Authorization 头（从 localStorage 读取 token）
 * - exchanges: cacheExchange + errorExchange（401 → 跳转登录）+ fetchExchange
 */

import {
  cacheExchange,
  createClient,
  errorExchange,
  fetchExchange,
} from "urql";
import type { Client } from "urql";
import type { CombinedError } from "urql";
import { ERROR_CODES } from "./types";

// ---------------------------------------------------------------------------
// token 读取（与 teacher-portal auth.ts 对齐的 key）
// ---------------------------------------------------------------------------

/** localStorage token 键名（与 @edu/hooks useAuth 对齐） */
const TOKEN_KEY = "edu_auth_token";

/**
 * 从 localStorage 读取 access token
 * @returns token 或 null（SSR 或未登录时）
 */
function getStoredToken(): string | null {
  if (typeof window === "undefined") return null;
  return localStorage.getItem(TOKEN_KEY);
}

// ---------------------------------------------------------------------------
// 401 重定向处理
// ---------------------------------------------------------------------------

/** 是否正在重定向（防止多个 401 同时触发多次跳转） */
let isRedirecting = false;

/**
 * 401 错误处理：清除 token 并跳转登录页
 */
function handleUnauthorized(): void {
  if (isRedirecting || typeof window === "undefined") return;
  isRedirecting = true;
  localStorage.removeItem(TOKEN_KEY);
  localStorage.removeItem("edu_auth_user");
  // 跳转登录页（student-portal 无独立登录页，复用 Shell 的 /login）
  window.location.href = "/login";
}

// ---------------------------------------------------------------------------
// 独立 urql client 创建
// ---------------------------------------------------------------------------

/**
 * 创建独立的 urql client（非 MF 模式使用）
 *
 * 配置说明：
 * - cacheExchange：默认文档缓存（按 operationName + variables 缓存）
 * - errorExchange：拦截 401 错误，自动跳转登录页；拦截降级标记
 * - fetchExchange：实际发起 fetch 请求
 *
 * @returns urql Client 实例
 */
export function createStandaloneClient(): Client {
  const url =
    process.env.NEXT_PUBLIC_GRAPHQL_ENDPOINT || "/api/v1/student/graphql";

  const client = createClient({
    url,
    fetchOptions: (): Record<string, unknown> => {
      const token = getStoredToken();
      const headers: Record<string, string> = {
        "Content-Type": "application/json",
      };
      if (token) {
        headers["Authorization"] = `Bearer ${token}`;
      }
      return {
        credentials: "include",
        headers,
      };
    },
    exchanges: [
      cacheExchange,
      errorExchange({
        onError: (error: CombinedError): void => {
          // 检查 401 未授权
          const isUnauthorized =
            error.response?.status === 401 ||
            error.graphQLErrors?.some(
              (e) =>
                e.extensions?.code === ERROR_CODES.IAM_UNAUTHORIZED ||
                e.message.includes("Unauthorized"),
            );

          if (isUnauthorized) {
            handleUnauthorized();
            return;
          }

          // 检查降级模式标记（ARB-001 §3.4 方案 B）
          const degradedErrors = error.graphQLErrors?.filter(
            (e) => e.extensions?.degraded === true,
          );
          if (degradedErrors && degradedErrors.length > 0) {
            // 降级模式：展示部分数据 + 降级标识（由 UI 层处理）
            // 此处仅记录，不阻断流程
            if (typeof console !== "undefined") {
              console.warn(
                "[student-portal] GraphQL 降级模式：部分数据可能不是最新",
                degradedErrors,
              );
            }
          }
        },
      }),
      fetchExchange,
    ],
  });

  return client;
}

// ---------------------------------------------------------------------------
// client 单例管理
// ---------------------------------------------------------------------------

/** 独立模式 client 单例 */
let standaloneClient: Client | null = null;

/**
 * 获取 GraphQL client（独立壳模式单例）
 *
 * ARB-002 说明：
 * - MF 模式（NEXT_PUBLIC_MF_ENABLED=true）：Shell 通过 React Context 注入 client，
 *   应使用 provider.tsx 的 GraphQLProvider + useGraphQLClient()
 * - 独立模式（NEXT_PUBLIC_MF_ENABLED=false）：返回本文件创建的单例 client
 *
 * 本函数返回独立模式的单例；MF 模式请通过 provider.tsx 获取 Context 中的 client。
 *
 * @returns urql Client 实例（独立模式单例）
 */
export function getGraphQLClient(): Client {
  if (!standaloneClient) {
    standaloneClient = createStandaloneClient();
  }
  return standaloneClient;
}

/**
 * 重置 GraphQL client 单例（测试用）
 * 清除缓存的 client 实例，下次调用 getGraphQLClient() 时重新创建
 */
export function resetGraphQLClient(): void {
  standaloneClient = null;
}

/**
 * 判断当前是否为 MF 模式
 * @returns NEXT_PUBLIC_MF_ENABLED === 'true'
 */
export function isMfMode(): boolean {
  return process.env.NEXT_PUBLIC_MF_ENABLED === "true";
}
