# ThrillWiki API Integration Guide for Next.js Frontend

## Overview

You are building a Next.js frontend for ThrillWiki, a comprehensive theme park and roller coaster database. This document provides the complete API structure and integration patterns for connecting your Next.js application to the ThrillWiki Django REST API.

**Base API URL:** `http://localhost:8000/api/v1/`

## Authentication System

### JWT Authentication
The API uses JWT tokens with refresh token rotation:

```typescript
// Authentication endpoints
POST /api/v1/auth/login/
POST /api/v1/auth/signup/
POST /api/v1/auth/logout/
POST /api/v1/auth/token/refresh/
GET  /api/v1/auth/user/
GET  /api/v1/auth/status/

// Password management
POST /api/v1/auth/password/reset/
POST /api/v1/auth/password/change/

// Email verification
POST /api/v1/auth/verify-email/<token>/
POST /api/v1/auth/resend-verification/

// Social authentication
GET  /api/v1/auth/social/providers/
GET  /api/v1/auth/social/providers/available/
GET  /api/v1/auth/social/connected/
POST /api/v1/auth/social/connect/<provider>/
POST /api/v1/auth/social/disconnect/<provider>/
GET  /api/v1/auth/social/status/
```

### Authentication Hook Example
```typescript
// hooks/useAuth.ts
import { useState, useEffect } from 'react';

interface User {
  id: number;
  username: string;
  email: string;
  first_name: string;
  last_name: string;
}

export const useAuth = () => {
  const [user, setUser] = useState<User | null>(null);
  const [loading, setLoading] = useState(true);

  const login = async (credentials: LoginCredentials) => {
    const response = await fetch('/api/v1/auth/login/', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(credentials),
    });

    if (response.ok) {
      const data = await response.json();
      localStorage.setItem('accessToken', data.access);
      localStorage.setItem('refreshToken', data.refresh);
      setUser(data.user);
    }

    return response;
  };

  const logout = async () => {
    await fetch('/api/v1/auth/logout/', { method: 'POST' });
    localStorage.removeItem('accessToken');
    localStorage.removeItem('refreshToken');
    setUser(null);
  };

  return { user, login, logout, loading };
};
```

## Core Domain APIs

### Parks API

```typescript
// Parks endpoints
GET    /api/v1/parks/                    // List parks with filtering
POST   /api/v1/parks/                    // Create park (admin)
GET    /api/v1/parks/<id>/               // Park detail (supports ID or slug)
PUT    /api/v1/parks/<id>/               // Update park (admin)
DELETE /api/v1/parks/<id>/               // Delete park (admin)

// Park search and filtering
GET /api/v1/parks/hybrid/                // Advanced search with filtering
GET /api/v1/parks/hybrid/filter-metadata/ // Get filter options
GET /api/v1/parks/filter-options/        // Simple filter options
GET /api/v1/parks/search/companies/      // Company autocomplete
GET /api/v1/parks/search-suggestions/    // Park name suggestions

// Park media
GET    /api/v1/parks/<id>/photos/        // List park photos
POST   /api/v1/parks/<id>/photos/        // Upload photo
GET    /api/v1/parks/<id>/photos/<photo_id>/ // Photo detail
PUT    /api/v1/parks/<id>/photos/<photo_id>/ // Update photo
DELETE /api/v1/parks/<id>/photos/<photo_id>/ // Delete photo
GET    /api/v1/parks/<id>/image-settings/ // Image display settings
```

### Rides API

```typescript
// Rides endpoints
GET    /api/v1/rides/                    // List rides with filtering
POST   /api/v1/rides/                    // Create ride (admin)
GET    /api/v1/rides/<id>/               // Ride detail
PUT    /api/v1/rides/<id>/               // Update ride (admin)
DELETE /api/v1/rides/<id>/               // Delete ride (admin)

// Ride search and filtering
GET /api/v1/rides/hybrid/                // Advanced search with filtering
GET /api/v1/rides/hybrid/filter-metadata/ // Get filter options
GET /api/v1/rides/filter-options/        // Simple filter options
GET /api/v1/rides/search/companies/      // Company autocomplete
GET /api/v1/rides/search/ride-models/    // Ride model search
GET /api/v1/rides/search-suggestions/    // Ride name suggestions

// Ride media
GET    /api/v1/rides/<id>/photos/        // List ride photos
POST   /api/v1/rides/<id>/photos/        // Upload photo
GET    /api/v1/rides/<id>/photos/<photo_id>/ // Photo detail
PUT    /api/v1/rides/<id>/photos/<photo_id>/ // Update photo
DELETE /api/v1/rides/<id>/photos/<photo_id>/ // Delete photo
GET    /api/v1/rides/<id>/image-settings/ // Image display settings

// Manufacturers and models
GET /api/v1/rides/manufacturers/<slug>/  // Manufacturer-specific endpoints
```

## Data Structures

### Park Object
```typescript
interface Park {
  id: number;
  name: string;
  slug: string;
  status: 'OPERATING' | 'CLOSED' | 'SBNO' | 'PLANNED';
  description: string;
  average_rating: number;
  coaster_count: number;
  ride_count: number;
  location: {
    city: string;
    state: string;
    country: string;
  };
  operator: {
    id: number;
    name: string;
    slug: string;
  };
}
```

### Ride Object
```typescript
interface Ride {
  id: number;
  name: string;
  slug: string;
  status: 'OPERATING' | 'CLOSED' | 'SBNO' | 'PLANNED';
  description: string;
  average_rating: number;
  park: {
    id: number;
    name: string;
    slug: string;
  };
  ride_model: {
    id: number;
    name: string;
    description: string;
    category: string;
    manufacturer: {
      id: number;
      name: string;
      slug: string;
    };
  };
  statistics?: {
    height_ft: number;
    speed_mph: number;
    length_ft: number;
    inversions: number;
  };
}
```

## Advanced Features

### Hybrid Search System
The API includes a sophisticated hybrid search system for both parks and rides:

```typescript
// Hybrid search example
const searchParks = async (filters: SearchFilters) => {
  const params = new URLSearchParams({
    search: filters.query || '',
    park_type: filters.parkType || '',
    status: filters.status || '',
    country: filters.country || '',
    has_coasters: filters.hasCoasters?.toString() || '',
    min_coasters: filters.minCoasters?.toString() || '',
    view_mode: filters.viewMode || 'card',
    page: filters.page?.toString() || '1',
  });

  const response = await fetch(`/api/v1/parks/hybrid/?${params}`);
  return response.json();
};
```

### Filter Metadata
Get dynamic filter options for building search UIs:

```typescript
const getFilterMetadata = async () => {
  const response = await fetch('/api/v1/parks/hybrid/filter-metadata/');
  const data = await response.json();

  // Returns available options for dropdowns:
  // { countries: [...], states: [...], park_types: [...] }
  return data;
};
```

## Additional Endpoints

### Statistics & Analytics
```typescript
GET /api/v1/stats/                    // Platform statistics
POST /api/v1/stats/recalculate/       // Trigger stats recalculation
```

### Trending & Discovery
```typescript
GET /api/v1/trending/                 // Trending content
GET /api/v1/new-content/              // Recently added content
POST /api/v1/trending/calculate/      // Trigger trending calculation
```

### Reviews & Rankings
```typescript
GET /api/v1/reviews/latest/           // Latest reviews
GET /api/v1/rankings/                 // Ride rankings
POST /api/v1/rankings/calculate/      // Trigger ranking calculation
```

### Health & Monitoring
```typescript
GET /api/v1/health/                   // Detailed health check
GET /api/v1/health/simple/            // Simple health status
GET /api/v1/health/performance/       // Performance metrics
```

## Implementation Patterns

### API Client Setup
```typescript
// lib/api.ts
class ThrillWikiAPI {
  private baseURL = 'http://localhost:8000/api/v1';

  private async request<T>(
    endpoint: string,
    options: RequestInit = {}
  ): Promise<T> {
    const token = localStorage.getItem('accessToken');

    const response = await fetch(`${this.baseURL}${endpoint}`, {
      ...options,
      headers: {
        'Content-Type': 'application/json',
        ...(token && { Authorization: `Bearer ${token}` }),
        ...options.headers,
      },
    });

    if (!response.ok) {
      throw new Error(`API Error: ${response.status}`);
    }

    return response.json();
  }

  // Parks methods
  async getParks(params?: URLSearchParams) {
    return this.request<Park[]>(`/parks/?${params || ''}`);
  }

  async getPark(id: string | number) {
    return this.request<Park>(`/parks/${id}/`);
  }

  // Rides methods
  async getRides(params?: URLSearchParams) {
    return this.request<Ride[]>(`/rides/?${params || ''}`);
  }

  async getRide(id: number) {
    return this.request<Ride>(`/rides/${id}/`);
  }
}

export const api = new ThrillWikiAPI();
```

### Error Handling
```typescript
// hooks/useApiError.ts
export const useApiError = () => {
  const [error, setError] = useState<string | null>(null);

  const handleError = (error: any) => {
    if (error.response?.status === 401) {
      // Handle unauthorized
      window.location.href = '/login';
    } else if (error.response?.status === 403) {
      setError('You do not have permission to perform this action');
    } else {
      setError('An unexpected error occurred');
    }
  };

  return { error, handleError, clearError: () => setError(null) };
};
```

### Pagination Hook
```typescript
// hooks/usePagination.ts
export const usePagination = <T>(
  fetchFn: (page: number) => Promise<{ results: T[]; count: number }>
) => {
  const [data, setData] = useState<T[]>([]);
  const [loading, setLoading] = useState(false);
  const [page, setPage] = useState(1);
  const [hasMore, setHasMore] = useState(true);

  const loadMore = async () => {
    setLoading(true);
    try {
      const response = await fetchFn(page);
      setData(prev => [...prev, ...response.results]);
      setHasMore(response.results.length > 0);
      setPage(prev => prev + 1);
    } catch (error) {
      console.error('Failed to load more:', error);
    } finally {
      setLoading(false);
    }
  };

  return { data, loading, hasMore, loadMore };
};
```

## Key Implementation Notes

1. **Authentication**: All protected endpoints require JWT tokens in the Authorization header
2. **Pagination**: List endpoints support standard pagination with `page` and `page_size` parameters
3. **Filtering**: Use the hybrid endpoints for advanced filtering and search functionality
4. **Media**: Image uploads are handled through Cloudflare Images with automatic optimization
5. **Slugs**: Both parks and rides support access by ID or slug in detail endpoints
6. **Real-time**: Consider implementing WebSocket connections for live updates on trending content
7. **Caching**: Implement proper caching strategies for filter metadata and statistics
8. **Error Handling**: Handle 401/403 responses appropriately for authentication flows

This API provides comprehensive access to all ThrillWiki functionality. Focus on implementing the core park and ride browsing features first, then add authentication and advanced features like reviews and rankings as needed.