// Client-side inventory management library

export interface TicketAvailability {
  available: number;
  total: number;
  reserved: number;
  sold: number;
  is_available: boolean;
}

export interface TicketReservation {
  id: string;
  ticket_type_id: string;
  quantity: number;
  expires_at: string;
  seat_id?: string;
  status: string;
}

export interface PurchaseItem {
  ticket_type_id: string;
  quantity: number;
  unit_price: number;
  seat_id?: string;
}

export interface PurchaseAttempt {
  id: string;
  session_id: string;
  total_amount: number;
  platform_fee: number;
  expires_at: string;
  status: string;
  items: any[];
  reservations: string[];
}

class InventoryManager {
  private baseUrl: string;
  public sessionId: string;
  private reservations: Map<string, TicketReservation> = new Map();

  constructor() {
    this.baseUrl = '/api/inventory';
    this.sessionId = this.getOrCreateSessionId();
  }

  private getOrCreateSessionId(): string {
    if (typeof sessionStorage === 'undefined') {
      // Fallback for server-side rendering
      return 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
    }
    
    let sessionId = sessionStorage.getItem('ticket_session_id');
    if (!sessionId) {
      sessionId = 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
      sessionStorage.setItem('ticket_session_id', sessionId);
    }
    return sessionId;
  }

  async getAvailability(ticketTypeId: string): Promise<TicketAvailability> {
    const url = `${this.baseUrl}/availability/${encodeURIComponent(ticketTypeId)}`;
    
    const response = await fetch(url);
    const data = await response.json();
    
    if (!data.success) {
      throw new Error(data.error || 'Failed to get availability');
    }
    
    return data.availability;
  }

  async reserveTickets(
    ticketTypeId: string, 
    quantity: number, 
    holdMinutes: number = 15,
    seatIds?: string[]
  ): Promise<TicketReservation> {
    const response = await fetch(`${this.baseUrl}/reserve`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        ticket_type_id: ticketTypeId,
        quantity,
        session_id: this.sessionId,
        hold_minutes: holdMinutes,
        seat_ids: seatIds
      })
    });

    const data = await response.json();
    
    if (!data.success) {
      throw new Error(data.error || 'Failed to reserve tickets');
    }

    // Store reservation locally
    this.reservations.set(data.reservation.id, data.reservation);
    
    // Set up auto-release timer
    this.scheduleAutoRelease(data.reservation);
    
    return data.reservation;
  }

  async releaseReservation(reservationId: string): Promise<void> {
    const response = await fetch(`${this.baseUrl}/release`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        reservation_id: reservationId,
        session_id: this.sessionId
      })
    });

    const data = await response.json();
    
    if (!data.success) {
      throw new Error(data.error || 'Failed to release reservation');
    }

    // Remove from local storage
    this.reservations.delete(reservationId);
  }

  async createPurchaseAttempt(
    eventId: string,
    purchaserEmail: string,
    purchaserName: string,
    items: PurchaseItem[],
    platformFee: number = 0,
    holdMinutes: number = 30
  ): Promise<PurchaseAttempt> {
    const response = await fetch(`${this.baseUrl}/purchase-attempt`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        session_id: this.sessionId,
        event_id: eventId,
        purchaser_email: purchaserEmail,
        purchaser_name: purchaserName,
        items,
        platform_fee: platformFee,
        hold_minutes: holdMinutes
      })
    });

    const data = await response.json();
    
    if (!data.success) {
      throw new Error(data.error || 'Failed to create purchase attempt');
    }

    return data.purchase_attempt;
  }

  private scheduleAutoRelease(reservation: TicketReservation): void {
    const expiresAt = new Date(reservation.expires_at).getTime();
    const now = Date.now();
    const timeUntilExpiry = expiresAt - now;

    if (timeUntilExpiry > 0) {
      setTimeout(() => {
        this.reservations.delete(reservation.id);
        // Optionally notify user that reservation expired
        this.onReservationExpired?.(reservation);
      }, timeUntilExpiry);
    }
  }

  // Get all active reservations for this session
  getActiveReservations(): TicketReservation[] {
    return Array.from(this.reservations.values());
  }

  // Release all active reservations
  async releaseAllReservations(): Promise<void> {
    const promises = Array.from(this.reservations.keys()).map(id => 
      this.releaseReservation(id).catch(console.error)
    );
    await Promise.all(promises);
  }

  // Get time remaining for a reservation in milliseconds
  getTimeRemaining(reservation: TicketReservation): number {
    const expiresAt = new Date(reservation.expires_at).getTime();
    const now = Date.now();
    return Math.max(0, expiresAt - now);
  }

  // Format time remaining as a readable string
  formatTimeRemaining(reservation: TicketReservation): string {
    const ms = this.getTimeRemaining(reservation);
    const minutes = Math.floor(ms / 60000);
    const seconds = Math.floor((ms % 60000) / 1000);
    return `${minutes}:${seconds.toString().padStart(2, '0')}`;
  }

  // Callback for when a reservation expires
  onReservationExpired?: (reservation: TicketReservation) => void;
}

// Singleton instance
export const inventoryManager = new InventoryManager();

// Only run browser-specific code if we're in the browser
if (typeof window !== 'undefined') {
  // Cleanup reservations when page unloads
  window.addEventListener('beforeunload', () => {
    inventoryManager.releaseAllReservations().catch(console.error);
  });

  // Auto-cleanup expired reservations every minute
  setInterval(() => {
    const now = Date.now();
    for (const [id, reservation] of inventoryManager['reservations']) {
      if (new Date(reservation.expires_at).getTime() <= now) {
        inventoryManager['reservations'].delete(id);
      }
    }
  }, 60000);
}