interface RouteStop {
  address: string;
  lat?: number;
  lng?: number;
  bookingId?: string;
  setupTime?: string;
}

interface OptimizedRoute {
  stops: RouteStop[];
  totalDistance: number;
  totalDuration: number;
  legs: any[];
}

export class RouteOptimizationService {
  private apiKey: string;

  constructor() {
    this.apiKey = process.env.GOOGLE_MAPS_API_KEY || '';
    if (!this.apiKey) {
      console.warn('Google Maps API Key nicht konfiguriert');
    }
  }

  async geocodeAddress(address: string): Promise<{ lat: number; lng: number } | null> {
    try {
      const response = await fetch(
        `https://maps.googleapis.com/maps/api/geocode/json?address=${encodeURIComponent(address)}&key=${this.apiKey}`
      );
      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 null;
    } catch (error) {
      console.error('Geocoding error:', error);
      return null;
    }
  }

  async calculateDistanceMatrix(
    origins: string[],
    destinations: string[]
  ): Promise<any> {
    try {
      const originsParam = origins.map(o => encodeURIComponent(o)).join('|');
      const destinationsParam = destinations.map(d => encodeURIComponent(d)).join('|');

      const response = await fetch(
        `https://maps.googleapis.com/maps/api/distancematrix/json?origins=${originsParam}&destinations=${destinationsParam}&key=${this.apiKey}`
      );

      const data = await response.json();

      if (data.status === 'OK') {
        return data;
      }

      return null;
    } catch (error) {
      console.error('Distance Matrix error:', error);
      return null;
    }
  }

  async optimizeRoute(stops: RouteStop[], startLocation?: string): Promise<OptimizedRoute | null> {
    try {
      if (stops.length === 0) {
        return null;
      }

      for (const stop of stops) {
        if (!stop.lat || !stop.lng) {
          const coords = await this.geocodeAddress(stop.address);
          if (coords) {
            stop.lat = coords.lat;
            stop.lng = coords.lng;
          }
        }
      }

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

      const origin = startLocation || stops[0].address;
      const destination = stops[stops.length - 1].address;
      const waypoints = stops.slice(1, -1).map(s => s.address);

      const waypointsParam = waypoints.length > 0
        ? `&waypoints=optimize:true|${waypoints.map(w => encodeURIComponent(w)).join('|')}`
        : '';

      const response = await fetch(
        `https://maps.googleapis.com/maps/api/directions/json?origin=${encodeURIComponent(origin)}&destination=${encodeURIComponent(destination)}${waypointsParam}&key=${this.apiKey}`
      );

      const data = await response.json();

      if (data.status === 'OK' && data.routes.length > 0) {
        const route = data.routes[0];
        const legs = route.legs;

        let totalDistance = 0;
        let totalDuration = 0;

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

        const waypointOrder = route.waypoint_order || [];
        const optimizedStops = [stops[0]];

        waypointOrder.forEach((index: number) => {
          optimizedStops.push(stops[index + 1]);
        });

        if (stops.length > 1) {
          optimizedStops.push(stops[stops.length - 1]);
        }

        return {
          stops: optimizedStops,
          totalDistance: totalDistance / 1000,
          totalDuration: Math.round(totalDuration / 60),
          legs: legs,
        };
      }

      return null;
    } catch (error) {
      console.error('Route optimization error:', error);
      return null;
    }
  }

  async calculateSimpleRoute(
    startAddress: string,
    endAddress: string
  ): Promise<{ distance: number; duration: number } | null> {
    try {
      const response = await fetch(
        `https://maps.googleapis.com/maps/api/directions/json?origin=${encodeURIComponent(startAddress)}&destination=${encodeURIComponent(endAddress)}&key=${this.apiKey}`
      );

      const data = await response.json();

      if (data.status === 'OK' && data.routes.length > 0) {
        const route = data.routes[0];
        const leg = route.legs[0];

        return {
          distance: leg.distance.value / 1000,
          duration: Math.round(leg.duration.value / 60),
        };
      }

      return null;
    } catch (error) {
      console.error('Simple route calculation error:', error);
      return null;
    }
  }

  sortStopsByTime(stops: RouteStop[]): RouteStop[] {
    return stops.sort((a, b) => {
      if (!a.setupTime || !b.setupTime) return 0;
      return new Date(a.setupTime).getTime() - new Date(b.setupTime).getTime();
    });
  }

  async optimizeRouteWithTimeWindows(
    stops: RouteStop[],
    startLocation?: string
  ): Promise<OptimizedRoute | null> {
    const sortedStops = this.sortStopsByTime(stops);
    
    return this.optimizeRoute(sortedStops, startLocation);
  }
}

export const routeService = new RouteOptimizationService();
