import type { AuthResponse, LoginPayload, RegisterPayload } from '../types/auth';
import type { Station, Track, Train } from '../types/domain';

export class ApiError extends Error {
  readonly status: number;

  constructor(message: string, status: number) {
    super(message);
    this.name = 'ApiError';
    this.status = status;
  }
}

export interface NetworkSnapshot {
  readonly stations: Station[];
  readonly tracks: Track[];
  readonly trains: Train[];
}

const JSON_HEADERS = {
  accept: 'application/json',
  'content-type': 'application/json',
};

export async function login(credentials: LoginPayload): Promise<AuthResponse> {
  const response = await fetch('/api/auth/login', {
    method: 'POST',
    headers: JSON_HEADERS,
    body: JSON.stringify(credentials),
  });

  if (!response.ok) {
    throw new ApiError('Invalid username or password', response.status);
  }

  return (await response.json()) as AuthResponse;
}

export async function register(credentials: RegisterPayload): Promise<AuthResponse> {
  const response = await fetch('/api/auth/register', {
    method: 'POST',
    headers: JSON_HEADERS,
    body: JSON.stringify(credentials),
  });

  if (!response.ok) {
    const message =
      response.status === 409
        ? 'Username already exists'
        : 'Registration failed. Please try again.';
    throw new ApiError(message, response.status);
  }

  return (await response.json()) as AuthResponse;
}

export async function fetchNetworkSnapshot(
  token: string,
  signal?: AbortSignal
): Promise<NetworkSnapshot> {
  const response = await fetch('/api/network', {
    method: 'GET',
    headers: {
      accept: 'application/json',
      Authorization: `Bearer ${token}`,
    },
    signal,
  });

  if (!response.ok) {
    const message =
      response.status === 401
        ? 'Authorization required. Please sign in again.'
        : `Failed to fetch network snapshot (status ${response.status})`;
    throw new ApiError(message, response.status);
  }

  const data = (await response.json()) as NetworkSnapshot;
  return {
    stations: data.stations ?? [],
    tracks: data.tracks ?? [],
    trains: data.trains ?? [],
  };
}
