import "jsr:@supabase/functions-js/edge-runtime.d.ts";
import { createClient } from 'jsr:@supabase/supabase-js@2';
import { requireAuth, checkRateLimit } from '../_shared/auth.ts';

const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
};

interface Place {
  tripPlaceId: string;
  placeId: string;
  name: string;
  lat: number;
  lng: number;
  duration: string;
  order_index: number;
  is_time_fixed?: boolean; // Sabit saatli etkinlik mi?
  fixed_start_time?: string; // Sabit başlangıç saati
  fixed_end_time?: string; // Sabit bitiş saati
}

interface OptimizeRouteRequest {
  dayId: string;
  date: string;
  places: Place[];
  startLocation?: { lat: number; lng: number };
  startLocationType?: 'balloon' | 'hotel' | 'place' | 'city_center'; // Başlangıç noktası tipi
  travelMode?: string;
  maxDayTime?: string;
}

interface OptimizedPlace {
  tripPlaceId: string;
  placeId: string;
  name: string;
  newOrderIndex: number;
  oldOrderIndex: number;
}

interface OptimizationResult {
  optimizedOrder: OptimizedPlace[];
  distanceBeforeKm: number;
  distanceAfterKm: number;
  estimatedSavings: {
    distanceKm: number;
    timeMinutes: number;
  };
  explanation: string;
}

// Haversine formülü ile iki koordinat arasındaki mesafeyi hesapla (km)
function calculateDistance(lat1: number, lon1: number, lat2: number, lon2: number): number {
  const R = 6371; // Dünya'nın yarıçapı (km)
  const dLat = (lat2 - lat1) * Math.PI / 180;
  const dLon = (lon2 - lon1) * Math.PI / 180;
  const a = 
    Math.sin(dLat / 2) * Math.sin(dLat / 2) +
    Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
    Math.sin(dLon / 2) * Math.sin(dLon / 2);
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  return R * c;
}

// Toplam rota mesafesini hesapla
function calculateTotalDistance(places: Place[]): number {
  let total = 0;
  for (let i = 0; i < places.length - 1; i++) {
    total += calculateDistance(
      places[i].lat,
      places[i].lng,
      places[i + 1].lat,
      places[i + 1].lng
    );
  }
  return total;
}

// Nearest Neighbor algoritması ile rotayı optimize et
// ⚠️ Sabit saatli etkinlikler (balon uçuşu) optimizasyona dahil edilmez
function optimizeRoute(places: Place[], startLocation?: { lat: number; lng: number }): Place[] {
  if (places.length <= 2) {
    return places; // 2 veya daha az yer varsa optimize etmeye gerek yok
  }

  // Sabit saatli ve esnek etkinlikleri ayır
  const fixedTimePlaces = places.filter(p => p.is_time_fixed);
  const flexiblePlaces = places.filter(p => !p.is_time_fixed);

  // Eğer sadece sabit saatli etkinlikler varsa, olduğu gibi döndür
  if (flexiblePlaces.length === 0) {
    return places;
  }

  // Esnek etkinlikleri optimize et
  const unvisited = [...flexiblePlaces];
  const optimized: Place[] = [];

  // Başlangıç noktasını belirle
  let current: { lat: number; lng: number };
  
  // Eğer sabit saatli etkinlik varsa (örn: balon), onun konumundan başla
  if (fixedTimePlaces.length > 0) {
    const lastFixed = fixedTimePlaces[fixedTimePlaces.length - 1];
    current = { lat: lastFixed.lat, lng: lastFixed.lng };
  } else if (startLocation) {
    current = startLocation;
  } else {
    // Başlangıç noktası yoksa ilk esnek yeri kullan
    const first = unvisited.shift()!;
    optimized.push(first);
    current = { lat: first.lat, lng: first.lng };
  }

  // En yakın komşu algoritması (sadece esnek etkinlikler için)
  while (unvisited.length > 0) {
    let nearestIndex = 0;
    let nearestDistance = Infinity;

    // En yakın yeri bul
    for (let i = 0; i < unvisited.length; i++) {
      const distance = calculateDistance(
        current.lat,
        current.lng,
        unvisited[i].lat,
        unvisited[i].lng
      );
      if (distance < nearestDistance) {
        nearestDistance = distance;
        nearestIndex = i;
      }
    }

    // En yakın yeri ekle
    const nearest = unvisited.splice(nearestIndex, 1)[0];
    optimized.push(nearest);
    current = { lat: nearest.lat, lng: nearest.lng };
  }

  // Sabit saatli etkinlikleri başa ekle, optimize edilmiş esnek etkinlikleri sonra ekle
  return [...fixedTimePlaces, ...optimized];
}

// Optimizasyon açıklaması oluştur
function generateExplanation(original: Place[], optimized: Place[]): string {
  const changes: string[] = [];
  
  // Sabit saatli etkinlikleri kontrol et
  const hasFixedTime = original.some(p => p.is_time_fixed);
  if (hasFixedTime) {
    changes.push('Sabit saatli etkinlikler (balon uçuşu) korundu');
  }
  
  for (let i = 0; i < optimized.length; i++) {
    const newPlace = optimized[i];
    const oldIndex = original.findIndex(p => p.tripPlaceId === newPlace.tripPlaceId);
    
    if (oldIndex !== i && !newPlace.is_time_fixed) {
      changes.push(`${newPlace.name} ${oldIndex + 1}. sıradan ${i + 1}. sıraya taşındı`);
    }
  }

  if (changes.length === 0) {
    return "Mevcut sıralama zaten optimal görünüyor.";
  }

  return changes.slice(0, 3).join(', ') + (changes.length > 3 ? ' ve diğer değişiklikler' : '') + 
    '. Bu değişiklikler geriye dönüşleri azaltarak daha verimli bir rota oluşturur.';
}

Deno.serve(async (req) => {
  // CORS preflight
  if (req.method === 'OPTIONS') {
    return new Response('ok', { headers: corsHeaders });
  }

  try {
    // Auth check
    const auth = await requireAuth(req);
    if (auth.error) return auth.error;

    // Rate limit check (20 AI suggestions per hour)
    const supabaseService = createClient(
      Deno.env.get('SUPABASE_URL')!,
      Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
    );
    const rateLimitResponse = await checkRateLimit(auth.userId, 'ai_suggest', supabaseService);
    if (rateLimitResponse) return rateLimitResponse;

    const { places, startLocation }: OptimizeRouteRequest = await req.json();

    // Validasyon
    if (!places || places.length < 2) {
      return new Response(
        JSON.stringify({ 
          error: 'En az 2 yer gerekli',
          optimizedOrder: [],
          distanceBeforeKm: 0,
          distanceAfterKm: 0,
          estimatedSavings: { distanceKm: 0, timeMinutes: 0 },
          explanation: 'Optimizasyon için yeterli yer yok.'
        }),
        { 
          status: 400, 
          headers: { ...corsHeaders, 'Content-Type': 'application/json' } 
        }
      );
    }

    // Tüm yerlerin koordinatları var mı kontrol et
    const missingCoords = places.filter(p => !p.lat || !p.lng);
    if (missingCoords.length > 0) {
      return new Response(
        JSON.stringify({ 
          error: 'Bazı yerlerin koordinatları eksik',
          optimizedOrder: [],
          distanceBeforeKm: 0,
          distanceAfterKm: 0,
          estimatedSavings: { distanceKm: 0, timeMinutes: 0 },
          explanation: 'Tüm yerlerin koordinatları olmalı.'
        }),
        { 
          status: 400, 
          headers: { ...corsHeaders, 'Content-Type': 'application/json' } 
        }
      );
    }

    // Orijinal toplam mesafe
    const originalDistance = calculateTotalDistance(places);

    // Rotayı optimize et
    const optimizedPlaces = optimizeRoute(places, startLocation);

    // Optimize edilmiş toplam mesafe
    const optimizedDistance = calculateTotalDistance(optimizedPlaces);

    // Tasarruf hesapla
    const distanceSaved = Math.max(0, originalDistance - optimizedDistance);
    const timeSaved = Math.round(distanceSaved / 50 * 60); // 50 km/h ortalama hız varsayımı

    // Sonuç oluştur
    const result: OptimizationResult = {
      optimizedOrder: optimizedPlaces.map((place, index) => ({
        tripPlaceId: place.tripPlaceId,
        placeId: place.placeId,
        name: place.name,
        newOrderIndex: index,
        oldOrderIndex: place.order_index,
      })),
      distanceBeforeKm: originalDistance,
      distanceAfterKm: optimizedDistance,
      estimatedSavings: {
        distanceKm: distanceSaved,
        timeMinutes: timeSaved,
      },
      explanation: generateExplanation(places, optimizedPlaces),
    };

    return new Response(
      JSON.stringify(result),
      { 
        headers: { ...corsHeaders, 'Content-Type': 'application/json' } 
      }
    );

  } catch (error) {
    console.error('Optimize route error:', error);
    return new Response(
      JSON.stringify({ 
        error: error.message,
        optimizedOrder: [],
        distanceBeforeKm: 0,
        distanceAfterKm: 0,
        estimatedSavings: { distanceKm: 0, timeMinutes: 0 },
        explanation: 'Optimizasyon sırasında bir hata oluştu.'
      }),
      { 
        status: 500, 
        headers: { ...corsHeaders, 'Content-Type': 'application/json' } 
      }
    );
  }
});
