type ApiEnv = {
  NEXT_PUBLIC_API_URL?: string;
  NODE_ENV?: string;
};

export function resolveApiBase(env: ApiEnv = process.env) {
  const fallback = env.NODE_ENV === 'production' ? '/api/v1' : 'http://localhost:3001/api/v1';
  return (env.NEXT_PUBLIC_API_URL || fallback).replace(/\/$/, '');
}

const API_BASE = resolveApiBase();

let apiAvailable: boolean | null = null;
let probePromise: Promise<boolean> | null = null;

function getErrorMessage(body: unknown, status: number) {
  if (typeof body === 'object' && body !== null && 'message' in body) {
    const message = (body as { message?: unknown }).message;
    if (typeof message === 'string') return message;
    if (Array.isArray(message)) return message.join(', ');
  }
  return `Request failed: ${status}`;
}

export class ApiRequestError extends Error {
  constructor(
    public readonly status: number,
    public readonly body: unknown,
  ) {
    super(getErrorMessage(body, status));
    this.name = 'ApiRequestError';
  }
}

async function checkApi(): Promise<boolean> {
  if (apiAvailable === true) return true;
  if (probePromise) return probePromise;
  probePromise = (async () => {
    try {
      // 探测一个不依赖数据库的端点（/config/ai 总是返回 200，只要 NestJS 起来了）
      const res = await fetch(`${API_BASE}/config/ai`, { method: 'GET', signal: AbortSignal.timeout(1500) });
      apiAvailable = res.ok ? true : null;
    } catch {
      apiAvailable = null;
    } finally {
      probePromise = null;
    }
    return apiAvailable === true;
  })();
  return probePromise;
}

async function request<T>(path: string, options?: RequestInit): Promise<T> {
  const available = await checkApi();
  if (!available) throw new Error('API 不可用');
  const res = await fetch(`${API_BASE}${path}`, {
    headers: { 'Content-Type': 'application/json', ...options?.headers },
    ...options,
  }).catch(() => null);
  if (!res) {
    apiAvailable = null;
    throw new Error('API 不可用');
  }
  if (!res.ok) {
    const error = await res.json().catch(() => ({}));
    throw new ApiRequestError(res.status, error);
  }
  return res.json();
}

export const api = {
  get: <T>(path: string) => request<T>(path),
  post: <T>(path: string, data: unknown) =>
    request<T>(path, { method: 'POST', body: JSON.stringify(data) }),
  put: <T>(path: string, data: unknown) =>
    request<T>(path, { method: 'PUT', body: JSON.stringify(data) }),
  patch: <T>(path: string, data: unknown) =>
    request<T>(path, { method: 'PATCH', body: JSON.stringify(data) }),
  delete: <T>(path: string) => request<T>(path, { method: 'DELETE' }),
  postRaw: async <T>(path: string, data: unknown, timeoutMs = 120000): Promise<T> => {
    // 调用 AI 类长耗时接口时使用，跳过 checkApi 短路（确保走真实请求）
    const controller = new AbortController();
    const tid = setTimeout(() => controller.abort(), timeoutMs);
    try {
      const res = await fetch(`${API_BASE}${path}`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data),
        signal: controller.signal,
      });
      if (!res.ok) {
        const err = await res.json().catch(() => ({}));
        throw new ApiRequestError(res.status, err);
      }
      return res.json();
    } finally {
      clearTimeout(tid);
    }
  },
};

export function __resetApiAvailabilityForTests() {
  apiAvailable = null;
  probePromise = null;
}
