// Typed CRUD functions for the /api/trips endpoints.
//
// This is the React counterpart of Angular's TripDataService. Instead
// of an injectable class returning RxJS Observables, each operation is
// a plain async function returning a typed Promise. Components consume
// these with async/await inside useEffect or event handlers, which
// removes the subscribe/unsubscribe lifecycle management entirely.
import apiClient from './client';
import { Trip, TripFormData } from '../models/trip';

export async function getTrips(): Promise<Trip[]> {
  const response = await apiClient.get<Trip[]>('/trips');
  return response.data;
}

// The Express API returns an array even for a single-code lookup, so
// this normalizes to one record (or null) at the API boundary instead
// of forcing every caller to remember that quirk, as the Angular
// EditTripComponent had to.
export async function getTrip(tripCode: string): Promise<Trip | null> {
  const response = await apiClient.get<Trip[]>(`/trips/${tripCode}`);
  return Array.isArray(response.data) ? response.data[0] ?? null : response.data;
}

export async function addTrip(formData: TripFormData): Promise<Trip> {
  const response = await apiClient.post<Trip>('/trips', formData);
  return response.data;
}

export async function updateTrip(formData: TripFormData): Promise<Trip> {
  const response = await apiClient.put<Trip>(
    `/trips/${formData.code}`,
    formData
  );
  return response.data;
}

export async function deleteTrip(tripCode: string): Promise<void> {
  await apiClient.delete(`/trips/${tripCode}`);
}

// ---- Enhancement Two: algorithms and data structures ----

export type SortField = 'name' | 'price' | 'start' | 'relevance';

export interface TripSearchParams {
  search?: string;
  sortBy?: SortField;
  order?: 'asc' | 'desc';
  limit?: number;
  cursor?: string | null;
}

export interface TripSearchPage {
  results: Trip[];
  totalMatches: number;
  nextCursor: string | null;
  sortBy: SortField;
  order: 'asc' | 'desc';
}

// Server-side search + merge sort + cursor pagination. The cursor for
// the next page comes back in the response; passing it in the next
// call resumes exactly where the previous page ended.
export async function searchTrips(params: TripSearchParams): Promise<TripSearchPage> {
  const response = await apiClient.get<TripSearchPage>('/trips/search', {
    params: {
      search: params.search || undefined,
      sortBy: params.sortBy || undefined,
      order: params.order || undefined,
      limit: params.limit || undefined,
      cursor: params.cursor || undefined
    }
  });
  return response.data;
}

export interface RecommendedTrip extends Trip {
  similarity: number;
}

// Top-k similar trips, selected server-side with a bounded min-heap.
export async function getRecommendations(
  basedOn: string,
  k = 3
): Promise<RecommendedTrip[]> {
  const response = await apiClient.get<{ basedOn: string; recommendations: RecommendedTrip[] }>(
    '/trips/recommendations',
    { params: { basedOn, k } }
  );
  return response.data.recommendations;
}
