type BotResponse = Record<string, unknown>;
let lastCatalog: BotCatalog | null = null;

const baseUrl = () => (process.env.BOT_API_BASE_URL || "https://kiln.spb.ru").replace(/\/$/, "");

async function botRequest<T extends BotResponse>(path: string, init?: RequestInit): Promise<T> {
  const apiKey = process.env.BOT_API_KEY;
  if (!apiKey) throw new Error("BOT_API_KEY is not configured");
  const response = await fetch(`${baseUrl()}${path}`, {
    ...init,
    headers: { accept: "application/json", "content-type": "application/json", "x-api-key": apiKey, ...(init?.headers || {}) },
    cache: "no-store",
    signal: AbortSignal.timeout(25000)
  });
  const body = await response.json().catch(() => ({}));
  if (!response.ok) {
    const error = new Error(String(body.message || body.error || `Bot API returned ${response.status}`));
    Object.assign(error, { status: response.status, body });
    throw error;
  }
  return body as T;
}

export type BotCatalogItem = { sbis_id: string | number; position_id?: string | number; name: string; price: number; description?: string | null; image?: string | null; stock_left?: number | null; available: boolean | null; unavailable_text?: string | null; variant_of?: string | null };
export type BotCatalog = { ok: true; updated_at: string; categories: { id: string | number; name: string; items: BotCatalogItem[] }[] };
export type BotOrderResponse = { ok: true; order_id: string; status: string; pay_url: string | null; track_url: string; tg_link: string | null; total: number; delivery_fee: number; moderation_id?: string | null };
export type BotOrderStatus = { ok: true; order_id: string; status: string; status_ru: string; paid: boolean; pay_url: string | null; track_url: string; eta?: string | null };
export type BotBookingResponse = { ok: true; rid: string; message: string; booking_url?: string; public_ref?: string };
export type BotInfo = {
  ok: true; name: string; address: string; coordinates: { lat: number; lon: number }; phone: string; tg_link: string;
  hours: { restaurant: { start: string; end: string }; orders: { start: string; end: string; note?: string }; booking: { start: string; end: string } };
  offhours_messages: { order: string; booking: string };
  delivery: { enabled: boolean; accepting_today?: boolean; receive_types?: string[]; cook_time_min?: number; assembly_time_min?: number; order_cutoff_min?: number; source?: string; updated_at?: string; error?: string | null };
  pickup?: { enabled: boolean; min_order?: number; delivery_fee?: number };
  zones: { zone: number; id: number; name: string; min_order: number; delivery_fee: number; free_from: number | null; delivery_time_min?: number }[];
  server_time: string;
};
export type BotSbisItemCard = {
  ok: true; sbis_id: number; name: string | null; description: string | null;
  measure_unit: unknown; production_volume: number | null; production_measure: string | null;
  weight: number | null; weight_unit: string | null; weight_status: string;
  composition: { row_id: unknown; name: string | null; sbis_id: string | null; quantity: number | null; net_g: number | null; output: number | null; unit: string | null; depth: number | null; is_contents: boolean }[];
  composition_source: string; price_list: { id: number }; updated_at: string;
};
export type BotSbisPrices = { ok: true; default_id: number; prices: { id: number; name: string; is_used?: boolean; is_archived?: boolean }[] };
export type BotDeliveryQuote = { ok: true; normalized_address: string; zone: { zone: number; id: number; name: string; min_order: number; delivery_fee: number; free_from: number | null } | null; delivery_fee: number; total_with_delivery: number };
export type ClientMessage = { id: number; direction: "system" | "client" | "restaurant"; text: string; created_at: string };
export type BotOrderView = BotOrderStatus & {
  ok: true; kind?: "order"; completed?: boolean; chat_open?: boolean; total?: number; delivery_fee?: number;
  created_at?: string; due?: string | null; fulfillment?: "delivery" | "pickup"; address?: string | null;
  items?: { n?: string; q?: number; s?: number }[]; courier?: { name?: string | null; phone?: string | null };
  courier_map_url?: string | null; messages?: ClientMessage[];
};
export type BotBookingView = {
  ok: true; kind: "booking"; booking_id: string; status: string; status_ru: string; name?: string | null;
  date_time: string; persons: number; comment?: string | null; completed: boolean; chat_open: boolean; can_change: boolean;
  pending_change?: { id: number; proposed: { date_time: string; persons: number }; requested_at: string } | null;
  messages: ClientMessage[]; calendar_url?: string | null;
};
export type BotHistory = {
  ok: true; phone: string;
  orders: { order_id: string; status: string; status_ru: string; paid: boolean; total: number; delivery_fee: number; due: string | null; created_at: string; completed: boolean; public_ref: string; track_url: string }[];
  bookings: { rid: string; dt: string; persons: number; status: string; status_ru: string; name: string; created_at: string; completed: boolean; public_ref: string }[];
};

let infoCache: { value: BotInfo; at: number } | null = null;
const INFO_TTL_MS = 10 * 60 * 1000;

/** GET /api/info with a 10-minute server-side cache (contract §3в). */
export async function getBotInfo() {
  if (infoCache && Date.now() - infoCache.at < INFO_TTL_MS) return infoCache.value;
  const info = await botRequest<BotInfo>("/api/info");
  infoCache = { value: info, at: Date.now() };
  return info;
}

export async function getBotCatalog() {
  try {
    const catalog = await botRequest<BotCatalog>("/api/catalog");
    lastCatalog = catalog;
    return catalog;
  } catch (error) {
    const status = (error as { status?: unknown }).status;
    if (status === 502 && lastCatalog) return lastCatalog;
    throw error;
  }
}
export function createBotOrder(payload: unknown) { return botRequest<BotOrderResponse>("/api/order", { method: "POST", body: JSON.stringify(payload) }); }
export function getBotOrder(clientRef: string) { return botRequest<BotOrderStatus>(`/api/order/${encodeURIComponent(clientRef)}`); }
export function createBotBooking(payload: unknown) {
  return botRequest<BotBookingResponse>("/api/booking", { method: "POST", body: JSON.stringify(payload) });
}
export function quoteBotDelivery(address: string, orderTotal: number) {
  return botRequest<BotDeliveryQuote>("/api/delivery/quote", { method: "POST", body: JSON.stringify({ address, order_total: orderTotal }) });
}
export function sendBotSmsPin(phone: string, code: string) {
  return botRequest<{ ok: true }>("/api/sms/pin", { method: "POST", body: JSON.stringify({ phone, code }) });
}
/** POST /api/email/send — plain-text letter; PIN is generated by the site (contract §2а). */
export function sendBotEmail(to: string, subject: string, text: string) {
  return botRequest<{ ok: true }>("/api/email/send", { method: "POST", body: JSON.stringify({ to, subject, text }) });
}
export type BotLoginClaim = { ok: true; status: "pending" } | { ok: true; status: "claimed"; messenger: string; messenger_user_id: string; display_name: string | null; phone_confirmed: boolean; phone?: string };
/** GET /api/auth/claim/{nonce} — one-time messenger identity claim (contract §2в). */
export function getBotLoginClaim(nonce: string) {
  return botRequest<BotLoginClaim>(`/api/auth/claim/${encodeURIComponent(nonce)}`);
}
export function getBotHistory(phone: string) {
  return botRequest<BotHistory>(`/api/history/${encodeURIComponent(phone)}`);
}
export function getBotOrderView(reference: string) {
  return botRequest<BotOrderView>(`/api/client/order/${encodeURIComponent(reference)}`);
}
export function getBotBookingView(reference: string) {
  return botRequest<BotBookingView>(`/api/client/booking/${encodeURIComponent(reference)}`);
}
export function sendBotClientMessage(kind: "order" | "booking", reference: string, message: string) {
  return botRequest<{ ok: true }>(`/api/client/${kind}/${encodeURIComponent(reference)}/message`, { method: "POST", body: JSON.stringify({ text: message }) });
}
export function requestBotBookingChange(reference: string, dateTime: string, persons: number) {
  return botRequest<{ ok: true; status: "pending" }>(`/api/client/booking/${encodeURIComponent(reference)}/change`, { method: "POST", body: JSON.stringify({ date_time: dateTime, persons }) });
}
export function getBotSbisItem(sbisId: string) {
  return botRequest<BotSbisItemCard>(`/api/item/${encodeURIComponent(sbisId)}`);
}
export function getBotSbisPrices() {
  return botRequest<BotSbisPrices>("/api/sbis/prices");
}
export type BotPushResult = {
  ok: boolean; sbis_id: number; updated: string[]; skipped: string[];
  actual: { name: string | null; description: string | null; image_present: boolean } | null;
  errors: { fields: string[]; error: string }[];
};
/** POST /api/item/{sbis_id} — manual push of editorial fields (contract §3а). */
export function pushBotSbisItem(sbisId: string, payload: { name?: string; description?: string; image_base64?: string }) {
  return botRequest<BotPushResult>(`/api/item/${encodeURIComponent(sbisId)}`, { method: "POST", body: JSON.stringify(payload) });
}
