import axios, {
  isAxiosError,
  type AxiosError,
  type AxiosRequestConfig,
  type AxiosResponse,
} from "axios";

import { isInIframe } from "@/components/iframe-bridge";
import { withPlayerAuthHeader } from "@/lib/lottery-auth";
import { usePlayerSessionStore } from "@/stores/player-session-store";
import { withLotteryLocaleHeaders } from "@/lib/lottery-locale";
import {
  LotteryApiBizError,
  LotteryApiEnvelopeError,
} from "@/types/api/errors";
import { isApiEnvelope } from "@/types/api/envelope";
import { useErrorStore } from "@/stores/error-store";
import { resolveLotteryApiV1Base } from "@/lib/lottery-api-base";
import {
  sanitizePlayerServerErrorMessage,
  shouldSkipGlobalServerError,
} from "@/lib/lottery-http-server-error";

/**
 * **第一层**：`baseURL` 对齐 Laravel `api/v1`；各 `api/*.ts` 只写业务 path（如 `/currencies`）。
 */
export const lotteryHttp = axios.create({
  baseURL: resolveLotteryApiV1Base(),
  timeout: 30_000,
  headers: { Accept: "application/json" },
});

/** 凭据类 401（非 token 失效），不应触发「会话过期」跳转 */
const PLAYER_CREDENTIAL_BIZ_CODES = new Set([8006]);

function isPlayerAuthLoginRequest(config: AxiosRequestConfig | undefined): boolean {
  if (!config || (config.method ?? "get").toLowerCase() !== "post") {
    return false;
  }
  return `${config.url ?? ""}`.includes("/player/auth/login");
}

/** 是否应将 401 视为已登录态失效并跳转入口（见 {@link EntryGate} `session=expired`） */
function shouldRedirectPlayerSessionExpired(error: AxiosError): boolean {
  if (isPlayerAuthLoginRequest(error.config)) {
    return false;
  }

  if (typeof window !== "undefined" && window.location.pathname === "/login") {
    return false;
  }

  const body = error.response?.data;
  if (isApiEnvelope(body) && PLAYER_CREDENTIAL_BIZ_CODES.has(body.code)) {
    return false;
  }

  return true;
}

/** 站内接口 401：清本地会话并回入口，与 {@link EntryGate} `session=expired` 衔接 */
/** 500 错误：更新全局服务器错误状态 */
lotteryHttp.interceptors.response.use(
  (response) => response,
  (error: unknown) => {
    if (isAxiosError(error) && typeof window !== "undefined") {
      const status = error.response?.status;

      // 401: 已登录态 token 失效 → 清会话并回入口；登录凭据错误等由页面自行提示
      if (status === 401) {
        const redirectSessionExpired = shouldRedirectPlayerSessionExpired(error);
        if (redirectSessionExpired || window.location.pathname === "/login") {
          usePlayerSessionStore.getState().clearBearerToken();
        }
        if (redirectSessionExpired) {
          const pathname = window.location.pathname;
          const alreadyExpired = window.location.search.includes("session=expired");
          const expiredTarget = isInIframe() ? "/?session=expired" : "/login?session=expired";
          const onExpiredPage =
            (pathname === "/" || pathname === "/login") && alreadyExpired;
          if (!onExpiredPage) {
            window.location.replace(expiredTarget);
          }
        }
      }

      // 500/502/503: 非入口/后台请求才触发全屏错误；文案脱敏
      if (status === 500 || status === 502 || status === 503) {
        if (!shouldSkipGlobalServerError(error.config)) {
          const setServerError = useErrorStore.getState().setServerError;
          let rawMessage: string | undefined;

          const responseData = error.response?.data;
          if (
            typeof responseData === "object" &&
            responseData !== null &&
            "msg" in responseData &&
            typeof responseData.msg === "string"
          ) {
            rawMessage = responseData.msg;
          }

          setServerError(true, sanitizePlayerServerErrorMessage(rawMessage));
        }
      }

      // 网络错误 (无响应): 检查网络状态
      if (!error.response && error.message?.includes("Network Error")) {
        const setIsOffline = useErrorStore.getState().setIsOffline;
        setIsOffline(true);
      }
    }
    return Promise.reject(error);
  },
);

/**
 * 对 **payload**（通常是 `response.data`）校验信封并成功时返回 `data`；
 * `code !== 0` 抛 {@link LotteryApiBizError}。
 */
export function unwrapData<T>(payload: unknown): T {
  if (!isApiEnvelope(payload)) {
    throw new LotteryApiEnvelopeError();
  }
  if (payload.code !== 0) {
    throw new LotteryApiBizError(payload.msg, payload.code, payload.data);
  }
  return payload.data as T;
}

/** 对已拿到的 `AxiosResponse` 解一层 `unwrapData(response.data)` */
export function unwrapResponse<T>(res: AxiosResponse<unknown>): T {
  return unwrapData<T>(res.data);
}

/**
 * **第二层**：补齐玩家鉴权与语言头，用 `lotteryHttp` 发请求，再 `unwrapResponse`。
 * 是否提示用户由各页面/特性自己 `catch` 决定。
 */
export async function request<T>(config: AxiosRequestConfig): Promise<T> {
  const merged = withPlayerAuthHeader(withLotteryLocaleHeaders(config));
  try {
    const res = await lotteryHttp.request<unknown>(merged);
    return unwrapResponse<T>(res);
  } catch (err: unknown) {
    if (isAxiosError(err) && err.response?.data !== undefined) {
      const body = err.response.data;
      if (isApiEnvelope(body) && body.code !== 0) {
        throw new LotteryApiBizError(body.msg, body.code, body.data);
      }
    }
    throw err;
  }
}

/** 第二层常用动词（内部都是 `request`） */
export const lotteryRequest = {
  request,

  get: <T>(url: string, config?: Omit<AxiosRequestConfig, "url" | "method">) =>
    request<T>({ ...config, url, method: "GET" }),

  delete: <T>(url: string, config?: Omit<AxiosRequestConfig, "url" | "method">) =>
    request<T>({ ...config, url, method: "DELETE" }),

  post: <T>(
    url: string,
    data?: unknown,
    config?: Omit<AxiosRequestConfig, "url" | "method" | "data">,
  ) => request<T>({ ...config, url, method: "POST", data }),

  put: <T>(
    url: string,
    data?: unknown,
    config?: Omit<AxiosRequestConfig, "url" | "method" | "data">,
  ) => request<T>({ ...config, url, method: "PUT", data }),

  patch: <T>(
    url: string,
    data?: unknown,
    config?: Omit<AxiosRequestConfig, "url" | "method" | "data">,
  ) => request<T>({ ...config, url, method: "PATCH", data }),
};