const GOOGLE_MAPS_API_KEY = process.env.GOOGLE_MAPS_API_KEY || '';

interface Stop {
  eventAddress: string;
  eventCity: string;
  eventZip: string;
  setupTimeStart: Date;
  setupTimeLatest?: Date;
}

interface RouteResult {
  optimizedOrder: number[];
  totalDistance: number;
  totalDuration: number;
  waypoints: Array<{
    address: string;
    lat: number;
    lng: number;
    arrivalTime?: string;
    setupWindow?: string;
  }>;
}

export async function optimizeRouteBySchedule(stops: Stop[]): Promise<RouteResult> {
  if (!GOOGLE_MAPS_API_KEY) {
    throw new Error('Google Maps API key not configured');
  }

  if (stops.length === 0) {
    return {
      optimizedOrder: [],
      totalDistance: 0,
      totalDuration: 0,
      waypoints: [],
    };
  }

  const stopsWithTimes = stops.map((stop, index) => ({
    ...stop,
    index,
    setupStart: new Date(stop.setupTimeStart),
    setupLatest: stop.setupTimeLatest ? new Date(stop.setupTimeLatest) : null,
  }));

  stopsWithTimes.sort((a, b) => a.setupStart.getTime() - b.setupStart.getTime());

  const sortedIndices = stopsWithTimes.map(s => s.index);

  let totalDistance = 0;
  let totalDuration = 0;
  const waypoints: RouteResult['waypoints'] = [];

  for (let i = 0; i < stopsWithTimes.length; i++) {
    const stop = stopsWithTimes[i];
    const address = `${stop.eventAddress}, ${stop.eventZip} ${stop.eventCity}`;
    const geocoded = await geocodeAddress(address);
    
    const setupWindow = stop.setupLatest
      ? `${stop.setupStart.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' })} - ${stop.setupLatest.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' })}`
      : `ab ${stop.setupStart.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' })}`;

    waypoints.push({
      address: `${stop.eventAddress}, ${stop.eventCity}`,
      lat: geocoded.lat,
      lng: geocoded.lng,
      setupWindow,
    });

    if (i > 0) {
      const prevStop = stopsWithTimes[i - 1];
      const origin = `${prevStop.eventAddress}, ${prevStop.eventZip} ${prevStop.eventCity}`;
      const destination = address;
      
      const { distance, duration } = await calculateDistance(origin, destination);
      totalDistance += distance;
      totalDuration += duration;
    }
  }

  return {
    optimizedOrder: sortedIndices,
    totalDistance,
    totalDuration,
    waypoints,
  };
}

export async function optimizeRoute(stops: Stop[]): Promise<RouteResult> {
  if (!GOOGLE_MAPS_API_KEY) {
    throw new Error('Google Maps API key not configured');
  }

  if (stops.length === 0) {
    return {
      optimizedOrder: [],
      totalDistance: 0,
      totalDuration: 0,
      waypoints: [],
    };
  }

  if (stops.length === 1) {
    const geocoded = await geocodeAddress(
      `${stops[0].eventAddress}, ${stops[0].eventZip} ${stops[0].eventCity}`
    );
    return {
      optimizedOrder: [0],
      totalDistance: 0,
      totalDuration: 0,
      waypoints: [
        {
          address: `${stops[0].eventAddress}, ${stops[0].eventCity}`,
          lat: geocoded.lat,
          lng: geocoded.lng,
        },
      ],
    };
  }

  const origin = `${stops[0].eventAddress}, ${stops[0].eventZip} ${stops[0].eventCity}`;
  const destination = `${stops[stops.length - 1].eventAddress}, ${stops[stops.length - 1].eventZip} ${stops[stops.length - 1].eventCity}`;
  
  const waypoints = stops.slice(1, -1).map(stop => 
    `${stop.eventAddress}, ${stop.eventZip} ${stop.eventCity}`
  );

  const url = new URL('https://maps.googleapis.com/maps/api/directions/json');
  url.searchParams.append('origin', origin);
  url.searchParams.append('destination', destination);
  if (waypoints.length > 0) {
    url.searchParams.append('waypoints', `optimize:true|${waypoints.join('|')}`);
  }
  url.searchParams.append('key', GOOGLE_MAPS_API_KEY);
  url.searchParams.append('mode', 'driving');
  url.searchParams.append('language', 'de');

  const response = await fetch(url.toString());
  
  if (!response.ok) {
    throw new Error(`Google Maps API error: ${response.statusText}`);
  }

  const data = await response.json();

  if (data.status !== 'OK') {
    throw new Error(`Google Maps API returned status: ${data.status}`);
  }

  const route = data.routes[0];
  const waypointOrder = route.waypoint_order || [];
  
  const optimizedOrder = [
    0,
    ...waypointOrder.map((i: number) => i + 1),
    stops.length - 1,
  ];

  let totalDistance = 0;
  let totalDuration = 0;

  route.legs.forEach((leg: any) => {
    totalDistance += leg.distance.value;
    totalDuration += leg.duration.value;
  });

  const waypointsData = await Promise.all(
    stops.map(async (stop, index) => {
      const address = `${stop.eventAddress}, ${stop.eventZip} ${stop.eventCity}`;
      const geocoded = await geocodeAddress(address);
      return {
        address: `${stop.eventAddress}, ${stop.eventCity}`,
        lat: geocoded.lat,
        lng: geocoded.lng,
      };
    })
  );

  return {
    optimizedOrder,
    totalDistance: Math.round(totalDistance / 1000),
    totalDuration: Math.round(totalDuration / 60),
    waypoints: waypointsData,
  };
}

async function geocodeAddress(address: string): Promise<{ lat: number; lng: number }> {
  const url = new URL('https://maps.googleapis.com/maps/api/geocode/json');
  url.searchParams.append('address', address);
  url.searchParams.append('key', GOOGLE_MAPS_API_KEY);
  url.searchParams.append('language', 'de');

  const response = await fetch(url.toString());
  const data = await response.json();

  if (data.status === 'OK' && data.results.length > 0) {
    const location = data.results[0].geometry.location;
    return {
      lat: location.lat,
      lng: location.lng,
    };
  }

  return { lat: 0, lng: 0 };
}

export async function calculateDistance(
  origin: string,
  destination: string
): Promise<{ distance: number; duration: number }> {
  if (!GOOGLE_MAPS_API_KEY) {
    throw new Error('Google Maps API key not configured');
  }

  const url = new URL('https://maps.googleapis.com/maps/api/distancematrix/json');
  url.searchParams.append('origins', origin);
  url.searchParams.append('destinations', destination);
  url.searchParams.append('key', GOOGLE_MAPS_API_KEY);
  url.searchParams.append('mode', 'driving');
  url.searchParams.append('language', 'de');

  const response = await fetch(url.toString());
  const data = await response.json();

  if (data.status === 'OK' && data.rows[0].elements[0].status === 'OK') {
    const element = data.rows[0].elements[0];
    return {
      distance: Math.round(element.distance.value / 1000),
      duration: Math.round(element.duration.value / 60),
    };
  }

  return { distance: 0, duration: 0 };
}
