import axios from "axios";
import type { AxiosError, AxiosRequestConfig } from "axios";
import { getCurrentLocale } from "@/i18n";
import type {
  ApiResponse,
  NormalizedError,
  NormalizedErrorKind,
  RequestContext,
  RequestOptions,
} from "@/shared/request-types";

function resolveBaseURL(): string {
  const baseURL = (import.meta.env as Record<string, unknown>)
    .VITE_API_BASE_URL;
  if (typeof baseURL !== "string" || baseURL.trim() === "") {
    throw new Error("Missing VITE_API_BASE_URL");
  }
  return baseURL;
}

function resolveTimeout(): number {
  const raw = (import.meta.env as Record<string, unknown>).VITE_API_TIMEOUT_MS;
  if (typeof raw !== "string" || raw.trim() === "") {
    return 15000;
  }
  const parsed = Number.parseInt(raw, 10);
  return Number.isFinite(parsed) ? parsed : 15000;
}

const http = axios.create({
  baseURL: resolveBaseURL(),
  timeout: resolveTimeout(),
});

let context: RequestContext = {
  token: null,
  clientId: import.meta.env.VITE_CLIENT_ID,
  latitude: null,
  longitude: null,
  language: null,
};

export function setAuthToken(token: string | null): void {
  context = { ...context, token };
}

export function setClientId(clientId: string | null): void {
  context = { ...context, clientId };
}

export function setLocation(
  latitude: number | null,
  longitude: number | null,
): void {
  context = { ...context, latitude, longitude };
}

export function setLanguage(language: string | null): void {
  context = { ...context, language };
}

export function getRequestContext(): RequestContext {
  return { ...context };
}

class RequestError extends Error implements NormalizedError {
  kind: NormalizedErrorKind;
  code?: number;
  httpStatus?: number;
  response?: unknown;

  constructor(params: {
    message: string;
    kind: NormalizedErrorKind;
    code?: number;
    httpStatus?: number;
    response?: unknown;
  }) {
    super(params.message);
    this.name = "RequestError";
    this.kind = params.kind;
    this.code = params.code;
    this.httpStatus = params.httpStatus;
    this.response = params.response;
  }
}

function resolveRequestLanguage(): string | null {
  if (context.language) {
    return context.language;
  }
  try {
    return getCurrentLocale();
  } catch {
    return null;
  }
}

function buildContextHeaders(options?: RequestOptions): Record<string, string> {
  const headers: Record<string, string> = {};

  // 临时token，后续需要从登录获取token
  setAuthToken(import.meta.env.VITE_TOKEN);

  if (!options?.skipAuth && context.token) {
    headers.Authorization = `Bearer ${context.token}`;
  }

  if (context.clientId) {
    headers.clientId = context.clientId;
  }

  if (context.latitude !== null && Number.isFinite(context.latitude)) {
    headers["X-Latitude"] = String(context.latitude);
  }

  if (context.longitude !== null && Number.isFinite(context.longitude)) {
    headers["X-Longitude"] = String(context.longitude);
  }

  const language = resolveRequestLanguage();
  if (language) {
    headers.language = language;
  }

  return headers;
}

function isApiResponse(value: unknown): value is ApiResponse<unknown> {
  if (!value || typeof value !== "object") {
    return false;
  }
  const v = value as Record<string, unknown>;
  return typeof v.code === "number" && "data" in v;
}

function normalizeAxiosError(error: AxiosError): RequestError {
  if (error.response) {
    const httpStatus = error.response.status;
    const message = error.message || `HTTP ${httpStatus}`;
    return new RequestError({
      kind: "http",
      httpStatus,
      message,
      response: error.response.data,
    });
  }

  return new RequestError({
    kind: "network",
    message: error.message || "Network Error",
  });
}

export async function request<T>(
  config: AxiosRequestConfig,
  options: RequestOptions = {},
): Promise<ApiResponse<T>> {
  try {
    const ctxHeaders = buildContextHeaders(options);
    const mergedHeaders: Record<string, string> = {
      ...ctxHeaders,
      ...((config.headers ?? {}) as Record<string, string>),
      ...(options.headers ?? {}),
    };

    const res = await http.request<ApiResponse<T>>({
      ...config,
      signal: options.signal ?? config.signal,
      headers: mergedHeaders,
    });

    const body = res.data as unknown;
    if (!isApiResponse(body)) {
      throw new RequestError({
        kind: "unknown",
        message: "Unexpected response shape",
        response: body,
      });
    }

    if (body.code !== 0) {
      throw new RequestError({
        kind: "business",
        code: body.code,
        message: body.message || "Business Error",
        response: body,
      });
    }

    return body as ApiResponse<T>;
  } catch (e: unknown) {
    if (e instanceof RequestError) {
      throw e;
    }

    if (axios.isAxiosError(e)) {
      throw normalizeAxiosError(e);
    }

    const err = e instanceof Error ? e : new Error(String(e));
    throw new RequestError({
      kind: "unknown",
      message: err.message || "Unknown Error",
      response: err,
    });
  }
}

export async function requestData<T>(
  config: AxiosRequestConfig,
  options: RequestOptions = {},
): Promise<T> {
  const res = await request<T>(config, options);
  return res.data;
}
