import React, { createContext, useCallback, useState, useMemo } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { tripPlacesApi, tripsApi } from '@/db/api';
import { useToast } from '@/hooks/use-toast';
import { Trip, TripPlace, TripDataRaw } from '@/types/trip-ui';
import { transformTripData } from '@/lib/trip-transform';

interface TripDataContextType {
  trip: Trip | null;
  loading: boolean;
  error: Error | null;
  loadTrip: (tripId: string) => Promise<void>;
  updateTrip: (updates: Partial<Trip>) => Promise<void>;
  deleteTrip: (tripId: string) => Promise<void>;
  addPlaceToDay: (placeId: string, dayId: string) => Promise<void>;
  removePlaceFromDay: (tripPlaceId: string) => Promise<void>;
}

interface MutationContext {
  previousTrip?: Trip;
}

export const TripDataContext = createContext<TripDataContextType | undefined>(undefined);

export const TripDataProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const [currentTripId, setCurrentTripId] = useState<string | null>(null);
  const { toast } = useToast();
  const queryClient = useQueryClient();

  const { data: trip, isLoading, error } = useQuery({
    queryKey: ['trip', currentTripId],
    queryFn: async () => {
      if (!currentTripId) return null;
      const tripData = await tripsApi.getTripById(currentTripId);
      if (!tripData) throw new Error('Trip not found');
      return transformTripData(tripData);
    },
    enabled: !!currentTripId,
  });

  const loadTrip = useCallback(async (tripId: string) => {
    setCurrentTripId(tripId);
  }, []);

  const updateTripMutation = useMutation({
    mutationFn: async (updates: Partial<Trip>) => {
      if (!currentTripId) throw new Error('No trip selected');
      return await tripsApi.update(currentTripId, updates);
    },
    onMutate: async (updates) => {
      await queryClient.cancelQueries({ queryKey: ['trip', currentTripId] });
      const previousTrip = queryClient.getQueryData<Trip>(['trip', currentTripId]);
      
      queryClient.setQueryData<Trip>(['trip', currentTripId], (old) => {
        if (!old) return old;
        return { ...old, ...updates };
      });

      return { previousTrip };
    },
    onError: (err, updates, context: MutationContext | undefined) => {
      if (context?.previousTrip) {
        queryClient.setQueryData(['trip', currentTripId], context.previousTrip);
      }
      toast({
        title: 'Hata',
        description: 'Güncelleme başarısız: ' + (err instanceof Error ? err.message : 'Bilinmeyen hata'),
        variant: 'destructive',
      });
    },
    onSettled: () => {
      queryClient.invalidateQueries({ queryKey: ['trip', currentTripId] });
    },
    onSuccess: () => {
      toast({
        title: 'Başarılı',
        description: 'Gezi güncellendi.',
      });
    }
  });

  const deleteTrip = useCallback(async (tripId: string) => {
    try {
      await tripsApi.delete(tripId);
      toast({
        title: 'Başarılı',
        description: 'Gezi silindi.',
      });
      if (tripId === currentTripId) {
        setCurrentTripId(null);
        queryClient.removeQueries({ queryKey: ['trip', tripId] });
      }
    } catch (err) {
      toast({
        title: 'Hata',
        description: 'Silme işlemi başarısız: ' + (err instanceof Error ? err.message : 'Bilinmeyen hata'),
        variant: 'destructive',
      });
    }
  }, [currentTripId, queryClient, toast]);

  const addPlaceMutation = useMutation({
    mutationFn: async ({ placeId, dayId }: { placeId: string, dayId: string }) => {
      if (!trip) throw new Error('No trip loaded');
      const day = trip.days.find(d => d.id === dayId);
      if (!day) throw new Error('Gün bulunamadı');
      
      return await tripPlacesApi.addToDay({
        trip_day_id: dayId,
        place_id: placeId,
        order_index: day.places.length,
        duration: '2 hours',
      });
    },
    onMutate: async ({ placeId, dayId }) => {
      await queryClient.cancelQueries({ queryKey: ['trip', currentTripId] });
      const previousTrip = queryClient.getQueryData<Trip>(['trip', currentTripId]);
      
      queryClient.setQueryData<Trip>(['trip', currentTripId], (old) => {
        if (!old) return old;
        return {
          ...old,
          days: old.days.map(day => {
            if (day.id === dayId) {
              return {
                ...day,
                places: [
                  ...day.places,
                  {
                    id: placeId,
                    tripPlaceId: 'temp-' + Date.now(),
                    name: 'Yükleniyor...',
                    type: 'activity',
                    duration: '2 hours',
                    position: { lat: 0, lng: 0 },
                    order_index: day.places.length,
                  } as TripPlace
                ]
              };
            }
            return day;
          })
        };
      });

      return { previousTrip };
    },
    onError: (err, variables, context: MutationContext | undefined) => {
      if (context?.previousTrip) {
        queryClient.setQueryData(['trip', currentTripId], context.previousTrip);
      }
      toast({
        title: 'Hata',
        description: 'Yer eklenemedi: ' + (err instanceof Error ? err.message : 'Bilinmeyen hata'),
        variant: 'destructive',
      });
    },
    onSettled: () => {
      queryClient.invalidateQueries({ queryKey: ['trip', currentTripId] });
    },
    onSuccess: () => {
      toast({
        title: 'Başarılı',
        description: 'Yer geziye eklendi.',
      });
    }
  });

  const removePlaceMutation = useMutation({
    mutationFn: async (tripPlaceId: string) => {
      return await tripPlacesApi.remove(tripPlaceId);
    },
    onMutate: async (tripPlaceId) => {
      await queryClient.cancelQueries({ queryKey: ['trip', currentTripId] });
      const previousTrip = queryClient.getQueryData<Trip>(['trip', currentTripId]);
      
      queryClient.setQueryData<Trip>(['trip', currentTripId], (old) => {
        if (!old) return old;
        return {
          ...old,
          days: old.days.map(day => ({
            ...day,
            places: day.places.filter(p => p.tripPlaceId !== tripPlaceId)
          }))
        };
      });

      return { previousTrip };
    },
    onError: (err, tripPlaceId, context: MutationContext | undefined) => {
      if (context?.previousTrip) {
        queryClient.setQueryData(['trip', currentTripId], context.previousTrip);
      }
      toast({
        title: 'Hata',
        description: 'Yer kaldırılamadı: ' + (err instanceof Error ? err.message : 'Bilinmeyen hata'),
        variant: 'destructive',
      });
    },
    onSettled: () => {
      queryClient.invalidateQueries({ queryKey: ['trip', currentTripId] });
    },
    onSuccess: () => {
      toast({
        title: 'Başarılı',
        description: 'Yer geziden kaldırıldı.',
      });
    }
  });

  const updateTrip = useCallback(async (updates: Partial<Trip>) => {
    await updateTripMutation.mutateAsync(updates);
  }, [updateTripMutation]);

  const addPlaceToDay = useCallback(async (placeId: string, dayId: string) => {
    await addPlaceMutation.mutateAsync({ placeId, dayId });
  }, [addPlaceMutation]);

  const removePlaceFromDay = useCallback(async (tripPlaceId: string) => {
    await removePlaceMutation.mutateAsync(tripPlaceId);
  }, [removePlaceMutation]);

  const contextValue = useMemo(() => ({
    trip: trip || null,
    loading: isLoading,
    error: error as Error | null,
    loadTrip,
    updateTrip,
    deleteTrip,
    addPlaceToDay,
    removePlaceFromDay
  }), [trip, isLoading, error, loadTrip, updateTrip, deleteTrip, addPlaceToDay, removePlaceFromDay]);

  return (
    <TripDataContext.Provider value={contextValue}>
      {children}
    </TripDataContext.Provider>
  );
};

