const API_BASE = (import.meta.env.VITE_API_BASE_URL || "").replace(/\/$/, "");
const SESSION_KEY = "email-unlimit-session";

export class ApiError extends Error {
  constructor(message, status = 0) {
    super(message);
    this.name = "ApiError";
    this.status = status;
  }
}

export function readSession() {
  try {
    return JSON.parse(localStorage.getItem(SESSION_KEY)) || null;
  } catch {
    return null;
  }
}

export function writeSession(session) {
  if (session) {
    localStorage.setItem(SESSION_KEY, JSON.stringify(session));
  } else {
    localStorage.removeItem(SESSION_KEY);
  }
}

let refreshPromise = null;

async function refreshSession() {
  const session = readSession();
  if (!session?.refresh_token) return null;

  if (!refreshPromise) {
    refreshPromise = fetch(`${API_BASE}/auth/refresh`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ refresh_token: session.refresh_token }),
    })
      .then(async (response) => {
        const payload = await response.json().catch(() => null);
        if (!response.ok || !payload?.data) {
          writeSession(null);
          return null;
        }
        const nextSession = { ...session, ...payload.data };
        writeSession(nextSession);
        return nextSession;
      })
      .finally(() => {
        refreshPromise = null;
      });
  }

  return refreshPromise;
}

function responseFilename(response) {
  const disposition = response.headers.get("content-disposition") || "";
  const utf8Match = disposition.match(/filename\*=UTF-8''([^;]+)/i);
  const plainMatch = disposition.match(/filename="?([^";]+)"?/i);
  const encoded = utf8Match?.[1] || plainMatch?.[1];
  if (!encoded) return null;
  try {
    return decodeURIComponent(encoded);
  } catch {
    return encoded;
  }
}

export async function apiRequest(path, options = {}) {
  const {
    auth = "user",
    mailboxToken,
    body,
    responseType = "json",
    retry = true,
    headers: customHeaders,
    ...fetchOptions
  } = options;
  const headers = new Headers(customHeaders || {});

  if (body !== undefined && !(body instanceof FormData)) {
    headers.set("Content-Type", "application/json");
  }
  if (auth === "user") {
    const token = readSession()?.access_token;
    if (token) headers.set("Authorization", `Bearer ${token}`);
  } else if (auth === "mailbox" && mailboxToken) {
    headers.set("Authorization", `Bearer ${mailboxToken}`);
  }

  const response = await fetch(`${API_BASE}${path}`, {
    ...fetchOptions,
    headers,
    body:
      body === undefined || body instanceof FormData
        ? body
        : JSON.stringify(body),
  });

  if (response.status === 401 && auth === "user" && retry) {
    const refreshed = await refreshSession();
    if (refreshed) {
      return apiRequest(path, { ...options, retry: false });
    }
  }

  if (responseType === "blob") {
    if (!response.ok) {
      throw new ApiError("附件下载失败", response.status);
    }
    return {
      blob: await response.blob(),
      filename: responseFilename(response),
    };
  }

  const payload = await response.json().catch(() => null);
  if (!response.ok) {
    throw new ApiError(
      payload?.message || `请求失败 (${response.status})`,
      response.status,
    );
  }
  return payload && Object.prototype.hasOwnProperty.call(payload, "data")
    ? payload.data
    : payload;
}

export function websocketUrl(path) {
  const url = new URL(`${API_BASE}${path}`, window.location.origin);
  url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
  return url.toString();
}
