import type { FinancialsResponse, HistoryPoint, MarketIndex, RatiosResponse, SearchResult, TickerOverview, ValuationResponse, WatchlistResponse } from "@/types/api"; const API_BASE = (process.env.NEXT_PUBLIC_API_BASE_URL || "").trim().replace(/\/$/, ""); export class ApiError extends Error { status: number; constructor(message: string, status: number) { super(message); this.name = "ApiError"; this.status = status; } } async function request(path: string, init?: RequestInit): Promise { const res = await fetch(`${API_BASE}${path}`, { ...init, headers: { "Content-Type": "application/json", ...(init?.headers || {}) } }); if (!res.ok) { const body = await res.json().catch(() => ({})); throw new ApiError(body.detail || `Request failed: ${res.status}`, res.status); } return res.json() as Promise; } export const api = { search(query: string) { return request(`/api/search?q=${encodeURIComponent(query)}`); }, marketIndices() { return request("/api/market/indices"); }, overview(symbol: string) { return request(`/api/tickers/${encodeURIComponent(symbol)}/overview`); }, history(symbol: string, period: string) { return request(`/api/tickers/${encodeURIComponent(symbol)}/history?period=${encodeURIComponent(period)}`); }, watchlist() { return request("/api/watchlist"); }, addWatchlist(symbol: string) { return request(`/api/watchlist/${encodeURIComponent(symbol)}`, { method: "POST" }); }, removeWatchlist(symbol: string) { return request(`/api/watchlist/${encodeURIComponent(symbol)}`, { method: "DELETE" }); }, financials(symbol: string, period: "annual" | "quarterly" = "annual") { return request( `/api/tickers/${encodeURIComponent(symbol)}/financials?period=${encodeURIComponent(period)}` ); }, valuation(symbol: string) { return request( `/api/tickers/${encodeURIComponent(symbol)}/valuation` ); }, ratios(symbol: string) { return request( `/api/tickers/${encodeURIComponent(symbol)}/ratios` ); } };