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

import { withAdminAuthHeader } from "@/lib/admin-auth";
import {
  handleAdminAuthRejected,
  isAdminAuthRejected,
} from "@/lib/admin-auth-reject";
import { withAdminLocaleHeaders } from "@/lib/admin-locale";
import { LotteryApiBizError, LotteryApiEnvelopeError } from "@/types/api/errors";
import { isApiEnvelope } from "@/types/api/envelope";
import { resolveLotteryApiV1Base } from "@/lib/lottery-api-base";

export { hasLotteryAdminApiBaseUrl } from "@/lib/lottery-api-env";

export const adminHttp = axios.create({
  baseURL: resolveLotteryApiV1Base(),
  timeout: 30_000,
  headers: { Accept: "application/json" },
});

adminHttp.interceptors.response.use(
  (response) => response,
  (error: unknown) => {
    if (isAdminAuthRejected(error)) {
      handleAdminAuthRejected();
    }
    if (isAxiosError(error) && typeof window !== "undefined") {
      const status = error.response?.status;
      if (status === 500 || status === 502 || status === 503) {
        console.error("[admin-http] upstream unavailable", status);
      }
      if (!error.response && error.message?.includes("Network Error")) {
        console.error("[admin-http] network offline or upstream unreachable");
      }
    }
    return Promise.reject(error);
  },
);

function rejectAfterAuthCheck(err: unknown): never {
  if (isAdminAuthRejected(err)) {
    handleAdminAuthRejected();
  }
  throw err;
}

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;
}

export function unwrapResponse<T>(res: AxiosResponse<unknown>): T {
  return unwrapData<T>(res.data);
}

/** 登录/验证码等：**不**附加 `Authorization`。 */
export async function publicAdminRequest<T>(
  config: AxiosRequestConfig,
): Promise<T> {
  try {
    const res = await adminHttp.request<unknown>(
      withAdminLocaleHeaders(config),
    );
    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);
      }
    }
    rejectAfterAuthCheck(err);
  }
}

export async function request<T>(config: AxiosRequestConfig): Promise<T> {
  const merged = withAdminAuthHeader(withAdminLocaleHeaders(config));
  try {
    const res = await adminHttp.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);
      }
    }
    rejectAfterAuthCheck(err);
  }
}

export const adminRequest = {
  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 }),

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

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

export async function clearAdminSessionCookie(): Promise<void> {
  await adminHttp.request({
    url: "/admin/auth/logout",
    method: "POST",
    validateStatus: () => true,
  });
}
