"use client";

import { useEffect, useRef, useState } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { createClient } from "@/lib/supabase/client";
import Minimap from "@/app/components/Minimap";
import StopsMapModal from "@/app/components/StopsMapModal";
import { toast } from "@/components/ui/use-toast";
import GameStepsMap from "@/app/components/GameStepsMap";
import { Button } from "@/components/ui/button";

// Replace with your actual Google Maps API key
const GOOGLE_MAPS_API_KEY = process.env.NEXT_PUBLIC_GOOGLE_API_KEY || "YOUR_API_KEY_HERE";

// Add distance threshold constant
const distanceThreshold = 50; // meters

// Helper function to calculate distance between two lat/lng points (Haversine formula)
const haversineDistance = (coords1: { lat: number; lng: number }, coords2: { lat: number; lng: number }) => {
  const toRad = (x: number) => (x * Math.PI) / 180;
  const R = 6371e3; // Earth radius in metres

  const dLat = toRad(coords2.lat - coords1.lat);
  const dLng = toRad(coords2.lng - coords1.lng);
  const lat1 = toRad(coords1.lat);
  const lat2 = toRad(coords2.lat);

  const a =
    Math.sin(dLat / 2) * Math.sin(dLat / 2) +
    Math.sin(dLng / 2) * Math.sin(dLng / 2) * Math.cos(lat1) * Math.cos(lat2);
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  return R * c; // in metres
};

// Helper function to handle end game
const handleEndGame = async (
  gameId: string,
  supabase: any,
  setEndGameScore: (score: number) => void,
  setEndGameDuration: (duration: string) => void,
  setShowEndGameModal: (show: boolean) => void
) => {
  try {
    const { data: endGameData, error: endGameError } = await supabase.functions.invoke('end-game', {
      body: { game_id: gameId },
    });

    if (endGameError) {
      console.error("Error calling end-game function:", endGameError.message);
      toast({
        title: "Error",
        description: "Failed to end game. Please try again.",
        variant: "destructive",
      });
    } else if (endGameData) {
      setEndGameScore(endGameData.score);
      setEndGameDuration(endGameData.duration);
      setShowEndGameModal(true);
    } else {
      toast({
        title: "Warning",
        description: "Game ended but no score was recorded.",
        variant: "destructive",
      });
    }
  } catch (e: any) {
    console.error("Exception calling end-game function:", e.message);
    toast({
      title: "Error",
      description: "An unexpected error occurred while ending the game.",
      variant: "destructive",
    });
  }
};

// Helper function to check if end game condition is met
const checkAndHandleEndGame = async (
  currentPoint: { lat: number; lng: number },
  endPoint: { lat: number; lng: number },
  gameId: string,
  supabase: any,
  setEndGameScore: (score: number) => void,
  setEndGameDuration: (duration: string) => void,
  setShowEndGameModal: (show: boolean) => void
) => {
  const distance = haversineDistance(currentPoint, endPoint);

  if (distance < distanceThreshold) {
    await handleEndGame(gameId, supabase, setEndGameScore, setEndGameDuration, setShowEndGameModal);
  }
};

// Define basic Google Maps types
type GoogleMapsStreetViewStatus = {
  OK: string;
};

type GoogleMapsStreetViewPanoramaData = {
  location: { latLng: { lat: () => number; lng: () => number } };
};

export default function GameNewPage({ params }: { params: { gameId: string } }) {
  const { gameId } = params;
  const [game, setGame] = useState<any>(null);
  const [loading, setLoading] = useState(true);
  const panoramaRef = useRef<HTMLDivElement>(null);
  const [error, setError] = useState<string | null>(null);
  const supabase = createClient();
  const [currentPosition, setCurrentPosition] = useState<{lat: number, lng: number, heading?: number}>({lat: 0, lng: 0});
  
  // State for displayed public transport routes
  const [displayedRoutes, setDisplayedRoutes] = useState<any[]>([]);
  const [hasAttemptedStopFetch, setHasAttemptedStopFetch] = useState(false);
  
  // State for StopsMapModal
  const [selectedRoute, setSelectedRoute] = useState<string | null>(null);
  const [routeStops, setRouteStops] = useState<any[]>([]);
  const [showStopsMap, setShowStopsMap] = useState(false);
  const [routeDirections, setRouteDirections] = useState<any[]>([]);

  // State for end game modal
  const [showEndGameModal, setShowEndGameModal] = useState(false);
  const [endGameScore, setEndGameScore] = useState<number | null>(null);
  const [endGameDuration, setEndGameDuration] = useState<string | null>(null);
  
  // State for give up modal
  const [showGiveUpModal, setShowGiveUpModal] = useState(false);
  const [finalDistance, setFinalDistance] = useState<number | null>(null);

  // Replace the Google Maps API loading
  useEffect(() => {
    if (typeof window === "undefined") return;
    
    // Check if script is already added
    const scriptId = 'google-maps-api-script';
    if (document.getElementById(scriptId)) return;
    
    // Standard way to load Google Maps API
    const script = document.createElement("script");
    script.id = scriptId;
    script.src = `https://maps.googleapis.com/maps/api/js?key=${GOOGLE_MAPS_API_KEY}`;
    script.async = true;
    script.defer = true;

    
    // Add the script to document
    document.head.appendChild(script);
    
    return () => {
      // Clean up when component unmounts
      const scriptElement = document.getElementById(scriptId);
      if (scriptElement) {
        document.head.removeChild(scriptElement);
      }
    };
  }, []);

  // Fetch game data
  useEffect(() => {
    async function fetchGame() {
      setLoading(true);
      setError(null);
      try {
        const { data, error } = await supabase
          .from("games")
          .select("id, start_point, end_point, current_point, city_id")
          .eq("id", gameId)
          .single();
        if (error) throw error;
        setGame(data);
      } catch (err: any) {
        setError(err.message || "Failed to fetch game data");
      } finally {
        setLoading(false);
      }
    }
    fetchGame();
  }, [gameId, supabase]);

  // Function to fetch nearby stops
  async function getNearbyStops(lat: number, lng: number) {
    const { data: stops, error } = await supabase.rpc("get_nearby_stops", {
      p_lat: lat,
      p_lng: lng,
      p_radius_meters: 30, 
    });
    setHasAttemptedStopFetch(true);

    if (error) {
      console.error("Error fetching nearby stops:", error.message);
      return [];
    }
    
    if (stops && stops.length > 0) {
      let uniqueRoutes: any[] = [];
      const numberRoutes: any[] = [];
      const letterRoutes: any[] = [];
      
      for (const stop of stops) {
        if (stop.routes) {
          for (const route of stop.routes) {
            if (!uniqueRoutes.includes(route.route_short_name) && 
                route.route_short_name !== '' && 
                route.route_short_name[0] !== 'N') {
              uniqueRoutes.push(route.route_short_name);
              if (route.route_short_name[0] == 'M') {
                letterRoutes.push({
                  ...route,
                  stop_id: stop.stop_id
                });
              } else {
                numberRoutes.push({
                  ...route,
                  stop_id: stop.stop_id
                });
              }
            }
          }
        }
      }
      
      numberRoutes.sort((a, b) => Number(a.route_short_name) - Number(b.route_short_name));
      letterRoutes.sort((a, b) => a.route_short_name.localeCompare(b.route_short_name));
      uniqueRoutes = [...letterRoutes, ...numberRoutes];
      setDisplayedRoutes(uniqueRoutes);
    } else {
      setDisplayedRoutes([]);
    }
    
    return stops;
  }

  // Function to fetch stops by route
  async function getStopsByRoute(route: any) {
    const { data: stops, error } = await supabase
      .rpc("get_stops_by_route", { p_route_id: route.route_id });

    const { data: directions, error: directionsError } = await supabase
      .from("route_stop_orders").select("*").eq("route_id", route.route_id);

    if (directionsError) {
      console.error("Error fetching directions:", directionsError.message);
    }
    
    if (error) {
      console.error("Error fetching stops by route:", error.message);
      return [];
    }
    
    const uniqueStops = stops.map((el: any) => {
      return {
        ...el,
        current_stop: el.stop_id == route.stop_id
      }
    });
    
    setRouteStops(uniqueStops);
    setRouteDirections(directions || []);
    setSelectedRoute(route.route_short_name);
    setShowStopsMap(true);
    return uniqueStops;
  }

  async function updateGameCurrentPoint(lat: number, lng: number) {
    const { error } = await supabase
      .from("games")
      .update({ current_point: { lat, lng } })
      .eq("id", gameId);
      
  }

  async function addGameStep(lat: number, lng: number, type: number) {
    const { error: stepError } = await supabase
    .from("game_steps")
    .insert({
      game_id: gameId,
      start_lat: currentPosition.lat,
      start_lng: currentPosition.lng,
      end_lat: lat,
      end_lng: lng,
      step_type: type
    });



    if (stepError) {
      console.error("Error inserting step:", stepError);
    }
      
  }

  // Function to update game status
  async function updateGameStatus(status: string) {
    const { error } = await supabase
      .from("games")
      .update({ status })
      .eq("id", gameId);
      
    if (error) {
      console.error("Error updating game status:", error);
      toast({
        title: "Error",
        description: "Failed to update game status. Please try again.",
        variant: "destructive",
      });
    } else {
      // Update local game state
      setGame((prev: any) => prev ? { ...prev, status } : prev);
    }
  }

  // Fix the Street View initialization useEffect
  useEffect(() => {
    if (!game || typeof window === "undefined") return;
    
    // Function to check if Google Maps is fully loaded and initialized
    const checkGoogleMaps = () => {
      return window.google && 
             window.google.maps && 
             window.google.maps.StreetViewPanorama &&
             window.google.maps.StreetViewService;
    };
    
    if (!checkGoogleMaps()) {
      // Wait for Google Maps to load
      console.log("Google Maps API not loaded yet, waiting...");
      const checkGoogleMapsLoaded = setInterval(() => {
        if (checkGoogleMaps()) {
          clearInterval(checkGoogleMapsLoaded);
          initializeStreetView();
        }
      }, 500);
      
      return () => clearInterval(checkGoogleMapsLoaded);
    } else {
      initializeStreetView();
    }
    
    function initializeStreetView() {
      if (!panoramaRef.current) return;
      console.log("Initializing Street View...");
      
      const { current_point } = game;
      
      try {
        // Create a StreetViewPanorama directly first without checking availability
        const panorama = new window.google!.maps!.StreetViewPanorama(
          panoramaRef.current,
          {
            position: { lat: current_point.lat, lng: current_point.lng },
            pov: { heading: 165, pitch: 0 },
            zoom: 1,
            // Disable UI controls
            addressControl: false,
            fullscreenControl: false,
            linksControl: true,
            panControl: false,
            enableCloseButton: false,
            motionTracking: false,
            motionTrackingControl: false,
            showRoadLabels: false,
            zoomControl: false,
            clickToGo: true,
            disableDefaultUI: true,
          }
        );
        
        // Set initial position
        setCurrentPosition({
          lat: current_point.lat,
          lng: current_point.lng,
          heading: 165
        });
        
        // Fetch nearby stops for initial position
        getNearbyStops(current_point.lat, current_point.lng);
        
        // Check if initial position is close to end point
        if (game.end_point) {
          checkAndHandleEndGame(
            current_point,
            game.end_point,
            gameId,
            supabase,
            setEndGameScore,
            setEndGameDuration,
            setShowEndGameModal
          );
        }
        
        // Add position change listener
        panorama.addListener("position_changed", () => {
          const position = panorama.getPosition().toJSON();
          
          // Update current position state
          setCurrentPosition({
            lat: position.lat,
            lng: position.lng,
            heading: panorama.getPov().heading
          });
          
          // Fetch nearby stops for new position
          getNearbyStops(position.lat, position.lng);
          
          // Update game's current_point in Supabase
          updateGameCurrentPoint(position.lat, position.lng);
          addGameStep(position.lat, position.lng, -1);
          
          // Check if end point is reached
          if (game.end_point) {
            checkAndHandleEndGame(
              position,
              game.end_point,
              gameId,
              supabase,
              setEndGameScore,
              setEndGameDuration,
              setShowEndGameModal
            );
          }
        });
        
        // Add heading change listener
        panorama.addListener("pov_changed", () => {
          const pov = panorama.getPov();
          setCurrentPosition(prev => ({
            ...prev,
            heading: pov.heading
          }));
        });
      } catch (err) {
        console.error("Error initializing Street View:", err);
        setError(`Failed to initialize Street View: ${err instanceof Error ? err.message : 'Unknown error'}`);
      }
    }
  }, [game]);

  // Fix handleNavigateToStop similarly
  const handleNavigateToStop = (lat: number, lng: number) => {
    if (!panoramaRef.current || 
        !window.google || 
        !window.google.maps || 
        !window.google.maps.StreetViewPanorama) {
      console.error("Google Maps not loaded or panorama ref not available");
      return;
    }
    
    try {
      // Create a new StreetViewPanorama instance directly
      const panorama = new window.google!.maps!.StreetViewPanorama(
        panoramaRef.current,
        {
          position: { lat, lng },
          pov: { heading: currentPosition.heading || 165, pitch: 0 },
          zoom: 1,
          addressControl: false,
          fullscreenControl: false,
          linksControl: true,
          panControl: false,
          enableCloseButton: false,
          motionTracking: false,
          motionTrackingControl: false,
          showRoadLabels: false,
          zoomControl: false,
          clickToGo: true,
          disableDefaultUI: true,
        }
      );
      
      // Update current position
      setCurrentPosition({
        lat,
        lng,
        heading: currentPosition.heading
      });
      
      // Manually update game's current_point in Supabase
      updateGameCurrentPoint(lat, lng);
      
      // Add a game step for this navigation
      addGameStep(lat, lng, -1);
      
      // Fetch nearby stops for new position
      getNearbyStops(lat, lng);
      
      // Close the stops map modal
      setShowStopsMap(false);
      
      // Check if end point is reached
      if (game && game.end_point) {
        checkAndHandleEndGame(
          { lat, lng },
          game.end_point,
          gameId,
          supabase,
          setEndGameScore,
          setEndGameDuration,
          setShowEndGameModal
        );
      }
      
      // Add position change and POV change listeners
      panorama.addListener("position_changed", () => {
        const position = panorama.getPosition().toJSON();
        
        // Update current position state
        setCurrentPosition({
          lat: position.lat,
          lng: position.lng,
          heading: panorama.getPov().heading
        });
        
        // Fetch nearby stops for new position
        getNearbyStops(position.lat, position.lng);
        
        // Update game's current_point in Supabase
        updateGameCurrentPoint(position.lat, position.lng);
        addGameStep(position.lat, position.lng, -1);
        
        // Check if end point is reached
        if (game && game.end_point) {
          checkAndHandleEndGame(
            position,
            game.end_point,
            gameId,
            supabase,
            setEndGameScore,
            setEndGameDuration,
            setShowEndGameModal
          );
        }
      });
      
      panorama.addListener("pov_changed", () => {
        const pov = panorama.getPov();
        setCurrentPosition(prev => ({
          ...prev,
          heading: pov.heading
        }));
      });
    } catch (err) {
      console.error("Error navigating to stop:", err);
      toast({
        title: "Error",
        description: `Failed to navigate to this location: ${err instanceof Error ? err.message : 'Unknown error'}`,
        variant: "destructive",
      });
    }
  };

  if (loading) return <div>Loading...</div>;
  if (error) return <div className="text-red-500">{error}</div>;
  if (!game) return <div>No game found.</div>;

  // Compass directions
  const compassLabels = [
    { label: 'N', angle: 0 },
    { label: 'NE', angle: 45 },
    { label: 'E', angle: 90 },
    { label: 'SE', angle: 135 },
    { label: 'S', angle: 180 },
    { label: 'SW', angle: 225 },
    { label: 'W', angle: 270 },
    { label: 'NW', angle: 315 },
  ];

  // Find the current compass direction
  const heading = currentPosition.heading || 0;
  const normalizedHeading = ((heading % 360) + 360) % 360;

  return (
    <div className="fixed inset-0 z-50">
      <div
        ref={panoramaRef}
        id="street-view"
        style={{ width: "100vw", height: "100vh" }}
        className=""
      ></div>
      
      {/* Compass in top left */}
      <div className="fixed top-4 left-4 z-40">
        <div className="bg-gray-800/70 rounded-full p-1 shadow-lg">
          <div className="relative w-16 h-16">
            {/* Compass circle */}
            <svg viewBox="0 0 100 100" className="w-full h-full">
              {/* Outer circle */}
              <circle cx="50" cy="50" r="48" fill="none" stroke="white" strokeWidth="1" />
              
              {/* Compass directions */}
              {compassLabels.map(({ label, angle }) => (
                <text
                  key={label}
                  x="50"
                  y="20"
                  fill="white"
                  fontSize="12"
                  fontWeight={label === 'N' ? 'bold' : 'normal'}
                  textAnchor="middle"
                  transform={`rotate(${angle} 50 50)`}
                >
                  {label}
                </text>
              ))}
              
              {/* Inner circle */}
              <circle cx="50" cy="50" r="5" fill="white" />
              
              {/* Pointer */}
              <path
                d="M 50 50 L 50 10"
                stroke="red"
                strokeWidth="2"
                transform={`rotate(${normalizedHeading} 50 50)`}
              />
            </svg>
          </div>
        </div>
      </div>
      
      {/* Add Give Up button */}
      <div className="fixed top-4 right-4 z-40">
        <Button
          variant="destructive"
          size="sm"
          onClick={() => {
            if (game && game.current_point && game.end_point) {
              const distance = haversineDistance(game.current_point, game.end_point);
              setFinalDistance(distance);
              setShowGiveUpModal(true);
            }
          }}
        >
          Give Up
        </Button>
      </div>
      
      {currentPosition.lat !== 0 && game && (
        <>
          {!showEndGameModal && (
            <Minimap 
              lat={currentPosition.lat}
              lng={currentPosition.lng}
              heading={currentPosition.heading}
              endLat={game.end_point.lat}
              endLng={game.end_point.lng}
              cityId={game.city_id}
            />
          )}
        </>
      )}
      
      {/* Display Public Transport Routes or "No Nearby Stops" message */}
      {hasAttemptedStopFetch && (
        <div style={{
          position: 'fixed',
          bottom: '20px',
          left: '50px',
          backgroundColor: 'rgba(0, 0, 0, 0.4)',
          color: '#1a1a1a',
          padding: '10px 15px',
          borderRadius: '8px',
          zIndex: 100,
          maxWidth: 'calc(100vw - 40px)',
          maxHeight: '30vh',
          overflowY: 'auto',
          boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)'
        }}>
          {displayedRoutes.length > 0 ? (
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: '5px 10px' }}>
              {displayedRoutes.map((route, index) => (
                <span 
                  key={index} 
                  style={{
                    backgroundColor: 'rgba(255, 255, 255, 0.9)',
                    padding: '5px 10px',
                    borderRadius: '4px',
                    fontSize: '1.1rem',
                    fontWeight: '600',
                    cursor: 'pointer',
                    display: 'flex',
                    alignItems: 'center',
                    gap: '5px',
                    color: '#1a1a1a',
                    transition: 'background-color 0.2s ease'
                  }}
                  onClick={() => getStopsByRoute(route)}
                >
                  {route.type !== undefined && (
                    <img 
                      src={`/${route.type}.png`} 
                      alt={`Route type ${route.type}`}
                      style={{ width: '20px', height: '20px', objectFit: 'contain' }}
                    />
                  )}
                  {route.route_short_name}
                </span>
              ))}
            </div>
          ) : (
            <p style={{ margin: 0, fontSize: '1rem', color: '#1a1a1a' }}>No nearby stops</p>
          )}
        </div>
      )}
      
      {/* StopsMapModal component */}
      <StopsMapModal
        isOpen={showStopsMap}
        onClose={() => setShowStopsMap(false)}
        stops={routeStops}
        routeName={selectedRoute || ''}
        game={game}
        directions={routeDirections}
        onNavigate={handleNavigateToStop}
        endLat={game.end_point.lat}
        endLng={game.end_point.lng}
      />
      
      {/* End Game Modal */}
      {showEndGameModal && endGameScore !== null && endGameDuration !== null && (
        <div style={{
          position: 'fixed',
          top: '0',
          left: '0',
          right: '0',
          bottom: '0',
          backgroundColor: 'rgba(0, 0, 0, 0.5)',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          zIndex: 100,
        }}>
          <div style={{
            backgroundColor: 'white',
            padding: '2rem',
            borderRadius: '0.5rem',
            boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)',
            textAlign: 'center',
            color: 'black',
            minWidth: '300px',
            maxWidth: '800px',
            width: '90%',
          }}>
            <h2 style={{ fontSize: '1.5rem', fontWeight: 'bold', marginBottom: '1rem' }}>🎉 Congratulations! 🎉</h2>
            <p style={{ marginBottom: '0.5rem' }}>You've reached your destination!</p>
            <p style={{ marginBottom: '0.5rem' }}><strong>Score:</strong> {endGameScore}</p>
            <p style={{ marginBottom: '1.5rem' }}><strong>Time:</strong> {endGameDuration}</p>
            
            {/* Add Game Steps Map */}
            <div style={{ marginBottom: '1.5rem' }}>
              <h3 style={{ marginBottom: '1rem' }}>Your Journey</h3>
              <GameStepsMap gameId={gameId} />
            </div>

            <div style={{ display: 'flex', justifyContent: 'space-around' }}>
              <Button variant="outline" onClick={() => {
                window.location.href = "/"; // Exit
              }}>Exit</Button>
              <Button onClick={() => {
                window.location.href = "/"; // New Game
              }}>New Game</Button>
            </div>
          </div>
        </div>
      )}
      
      {/* Give Up Modal */}
      {showGiveUpModal && finalDistance !== null && (
        <div style={{
          position: 'fixed',
          top: '0',
          left: '0',
          right: '0',
          bottom: '0',
          backgroundColor: 'rgba(0, 0, 0, 0.5)',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          zIndex: 100,
        }}>
          <div style={{
            backgroundColor: 'white',
            padding: '2rem',
            borderRadius: '0.5rem',
            boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)',
            textAlign: 'center',
            color: 'black',
            minWidth: '300px',
          }}>
            <h2 style={{ fontSize: '1.5rem', fontWeight: 'bold', marginBottom: '1rem' }}>Game Over</h2>
            <p style={{ marginBottom: '1.5rem' }}>
              Final distance to destination: {Math.round(finalDistance)} meters
            </p>
            <div style={{ display: 'flex', justifyContent: 'space-around' }}>
              <Button variant="outline" onClick={async () => {
                await updateGameStatus('cancelled');
                setShowGiveUpModal(false);
                window.location.href = "/"; // Exit
              }}>Exit</Button>
              <Button onClick={() => {
                setShowGiveUpModal(false);
                window.location.href = "/"; // New Game
              }}>New Game</Button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

// Update the Window type definition to be more accurate
declare global {
  interface Window {
    google?: {
      maps?: {
        StreetViewPanorama: new (container: Element, options: any) => any;
        StreetViewService: new () => any;
        StreetViewStatus: {
          OK: string;
        };
      };
    };
  }
} 