import AsyncStorage from '@react-native-async-storage/async-storage';
import { API_URL } from './config';

export type Role = 'passenger' | 'driver' | 'admin';
export type Lang = 'fr' | 'ar' | 'en';
export interface User { id: number; phone: string; name: string | null; role: Role; lang?: Lang }
export interface LineSummary {
  id: number; code: string; direction: number; name: string; color: string; length_m: number;
  from: string | null; to: string | null; stop_names: string[]; live_buses: number;
}
export interface Stop { id: number; seq: number; name: string; lat: number; lng: number; dist_m: number }
export interface LineDetail { id: number; code: string; direction: number; name: string; color: string; length_m: number; stops: Stop[]; shape: [number, number][] }
export interface LiveBus {
  trip_id: number; bus_id: number; bus_code: string; line_id: number; lat: number; lng: number;
  speed_kmh: number; heading: number | null; along_m: number; off_m: number; avg_kmh: number;
  occupancy: number; capacity: number; age_s: number; status: 'live' | 'lost' | 'off_route';
  next_stop: { id: number; name: string; eta_s: number | null } | null;
  eta_s?: number | null; dist_m?: number | null;
}
export interface LiveResponse {
  line_id: number; server_time: string; poll_ms: number; buses: LiveBus[]; stop: Stop | null;
  arrivals: { trip_id: number; bus_code: string; eta_s: number; dist_m: number; occupancy: number }[] | null;
}
export interface DriverSetup {
  buses: { id: number; code: string; plate: string | null; capacity: number }[];
  lines: { id: number; code: string; direction: number; name: string; color: string; length_m: number }[];
  current_trip: { id: number; bus_id: number; line_id: number; occupancy: number; started_at: string } | null;
}
export interface GpsPoint { lat: number; lng: number; speed_kmh?: number; heading?: number; accuracy?: number; ts: number }
export interface PositionsResponse { ok: boolean; accepted: number; along_m?: number; off_route?: boolean; at_terminus?: boolean }

export const TOKEN_KEY = 'bt.token';

export class ApiError extends Error {
  constructor(message: string, public status: number) { super(message); }
}

async function request<T>(method: string, path: string, body?: unknown, token?: string | null): Promise<T> {
  const tok = token === undefined ? await AsyncStorage.getItem(TOKEN_KEY) : token;
  const ctrl = new AbortController();
  const timer = setTimeout(() => ctrl.abort(), 15000);
  let res: Response;
  try {
    res = await fetch(API_URL + path, {
      method,
      headers: { 'Content-Type': 'application/json', Accept: 'application/json', ...(tok ? { Authorization: `Bearer ${tok}` } : {}) },
      body: body === undefined ? undefined : JSON.stringify(body),
      signal: ctrl.signal,
    });
  } catch {
    throw new ApiError('network', 0);
  } finally {
    clearTimeout(timer);
  }
  let data: any = null;
  try { data = await res.json(); } catch { /* réponse vide ou HTML */ }
  if (!res.ok) throw new ApiError(data?.error ?? `HTTP ${res.status}`, res.status);
  return data as T;
}

export const api = {
  login: (phone: string, password: string) => request<{ token: string; user: User }>('POST', '/auth/login', { phone, password }, null),
  register: (phone: string, password: string, name?: string) => request<{ token: string; user: User }>('POST', '/auth/register', { phone, password, name }, null),
  logout: () => request<{ ok: boolean }>('POST', '/auth/logout'),
  me: () => request<User>('GET', '/me'),
  setLang: (lang: Lang) => request<User>('PUT', '/me', { lang }),

  lines: () => request<{ lines: LineSummary[]; poll_ms: number }>('GET', '/lines'),
  line: (id: number) => request<LineDetail>('GET', `/lines/${id}`),
  live: (id: number, stopId?: number) => request<LiveResponse>('GET', `/lines/${id}/live${stopId ? `?stop=${stopId}` : ''}`),

  driverSetup: () => request<DriverSetup>('GET', '/driver/setup'),
  startTrip: (bus_id: number, line_id: number) => request<{ trip_id: number; line: LineDetail }>('POST', '/driver/trips', { bus_id, line_id }),
  sendPositions: (trip_id: number, points: GpsPoint[], token?: string | null) =>
    request<PositionsResponse>('POST', '/driver/positions', { trip_id, points }, token),
  setOccupancy: (trip_id: number, level: number) => request<{ ok: boolean }>('POST', `/driver/trips/${trip_id}/occupancy`, { level }),
  endTrip: (trip_id: number) => request<{ ok: boolean }>('POST', `/driver/trips/${trip_id}/end`, {}),
};
