import React, { useEffect, useRef, useState } from 'react';
import {
  View,
  StyleSheet,
  StatusBar,
  TouchableOpacity,
  ActivityIndicator,
  Platform,
  Linking
} from 'react-native';
import * as MapLibreRN from '@maplibre/maplibre-react-native';
import * as Location from 'expo-location';
import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
import { useNavigation } from '@react-navigation/native';
import _ from 'lodash';

import { VECTOR_MAP_HOST } from 'src/constants';
import { WarningModal } from 'src/components';
import { Colors } from 'src/theme';
import ScaleBar from 'src/components/ScaleBar';

import ChevronLeft from 'assets/icons/chevron-left.svg';
import LocationIcon from 'assets/icons/location.svg';
import MapSvg from 'assets/icons/travels-screens/map-location.svg';

const FullMapScreen = ({ route }: { route: any }) => {
  const { lat, lng } = route.params;
  const tabBarHeight = useBottomTabBarHeight();
  const insets = useSafeAreaInsets();

  const navigation = useNavigation();
  const mapRef = useRef<MapLibreRN.MapViewRef>(null);
  const cameraRef = useRef<MapLibreRN.CameraRef>(null);
  const [renderCamera, setRenderCamera] = useState(Platform.OS === 'ios');
  const animationTimeoutRef = useRef<NodeJS.Timeout | null>(null);
  const isAnimatingRef = useRef(false);

  const [isLocationLoading, setIsLocationLoading] = useState(false);
  const [location, setLocation] = useState<any | null>(null);

  const [zoom, setZoom] = useState(0);
  const [center, setCenter] = useState<number[] | null>(null);
  const [isZooming, setIsZooming] = useState(true);

  const [askLocationVisible, setAskLocationVisible] = useState<boolean>(false);
  const [openSettingsVisible, setOpenSettingsVisible] = useState<boolean>(false);

  const hideTimer = useRef<ReturnType<typeof setTimeout> | null>(null);

  const cameraController = {
    setCamera: (config: any) => {
      isAnimatingRef.current = true;

      if (animationTimeoutRef.current) {
        clearTimeout(animationTimeoutRef.current);
      }

      if (Platform.OS === 'android') {
        setRenderCamera(true);
        requestAnimationFrame(() => {
          cameraRef.current?.setCamera(config);
        });

        animationTimeoutRef.current = setTimeout(
          () => {
            isAnimatingRef.current = false;
            setRenderCamera(false);
          },
          (config.animationDuration || 1000) + 200
        );
      } else {
        cameraRef.current?.setCamera(config);

        animationTimeoutRef.current = setTimeout(
          () => {
            isAnimatingRef.current = false;
          },
          (config.animationDuration || 1000) + 100
        );
      }
    },

    flyTo: (coordinates: number[], duration: number = 1000) => {
      isAnimatingRef.current = true;

      if (animationTimeoutRef.current) {
        clearTimeout(animationTimeoutRef.current);
      }

      if (Platform.OS === 'android') {
        setRenderCamera(true);

        requestAnimationFrame(() => {
          cameraRef.current?.flyTo(coordinates, duration);
        });

        animationTimeoutRef.current = setTimeout(() => {
          isAnimatingRef.current = false;
          setRenderCamera(false);
        }, duration + 200);
      } else {
        cameraRef.current?.flyTo(coordinates, duration);

        animationTimeoutRef.current = setTimeout(() => {
          isAnimatingRef.current = false;
        }, duration + 100);
      }
    }
  };

  useEffect(() => {
    (async () => {
      let { status } = await Location.getForegroundPermissionsAsync();
      const isServicesEnabled = await Location.hasServicesEnabledAsync();

      if (status !== 'granted' || !isServicesEnabled) {
        return;
      }

      try {
        let currentLocation = await Location.getCurrentPositionAsync({
          accuracy: Location.Accuracy.Balanced
        });
        setLocation(currentLocation.coords);
      } catch (error) {
        console.error('Error fetching user location:', error);
      }
    })();
  }, []);

  useEffect(() => {
    return () => {
      if (animationTimeoutRef.current) {
        clearTimeout(animationTimeoutRef.current);
      }
    };
  }, []);

  const handleMapChange = async () => {
    if (!mapRef.current) return;
    if (hideTimer.current) clearTimeout(hideTimer.current);

    setIsZooming(true);

    const currentZoom = await mapRef.current.getZoom();
    setZoom(currentZoom);

    if (mapRef.current) {
      const currentCenter = await mapRef.current?.getCenter();
      setCenter(currentCenter);
    }
  };

  const handleGetLocation = async () => {
    setIsLocationLoading(true);
    try {
      let { status, canAskAgain } = await Location.getForegroundPermissionsAsync();
      const isServicesEnabled = await Location.hasServicesEnabledAsync();

      if (status === 'granted' && isServicesEnabled) {
        await getLocation();
      } else if (!canAskAgain || !isServicesEnabled) {
        setOpenSettingsVisible(true);
      } else {
        setAskLocationVisible(true);
      }
    } finally {
      setIsLocationLoading(false);
    }
  };

  const getLocation = async () => {
    try {
      let currentLocation = await Location.getCurrentPositionAsync({
        accuracy: Location.Accuracy.Balanced
      });
      setLocation(currentLocation.coords);

      if (currentLocation.coords) {
        cameraController?.flyTo(
          [currentLocation.coords.longitude, currentLocation.coords.latitude],
          1000
        );
      }
    } catch (error) {
      console.error('Error fetching user location:', error);
    }
  };

  const handleAcceptPermission = async () => {
    setAskLocationVisible(false);
    let { status, canAskAgain } = await Location.requestForegroundPermissionsAsync();
    const isServicesEnabled = await Location.hasServicesEnabledAsync();

    if (status === 'granted' && isServicesEnabled) {
      getLocation();
    } else if (!canAskAgain || !isServicesEnabled) {
      setOpenSettingsVisible(true);
    }
  };

  const openInExternalMaps = async (latitude: number, longitude: number) => {
    const appleMapsURL = `http://maps.apple.com/?q=${latitude},${longitude}`;
    const defaultGeoURL = `geo:${latitude},${longitude}?q=${latitude},${longitude}`;

    if (Platform.OS === 'ios') {
      await Linking.openURL(appleMapsURL);
    } else {
      await Linking.openURL(defaultGeoURL);
    }
  };

  return (
    <SafeAreaView style={{ height: '100%' }}>
      <StatusBar translucent backgroundColor="transparent" />

      <MapLibreRN.MapView
        ref={mapRef}
        style={styles.map}
        mapStyle={VECTOR_MAP_HOST + '/nomadmania-maps2025.json'}
        rotateEnabled={false}
        attributionEnabled={false}
        onRegionDidChange={() => {
          hideTimer.current = setTimeout(() => {
            setIsZooming(false);
          }, 2000);
        }}
        // onRegionIsChanging={handleMapChange}
        onRegionWillChange={_.debounce(handleMapChange, 200)}
      >
        {(Platform.OS === 'ios' || renderCamera) && (
          <MapLibreRN.Camera
            ref={cameraRef}
            defaultSettings={{ centerCoordinate: [lng, lat], zoomLevel: 12 }}
          />
        )}
        <MapLibreRN.MarkerView coordinate={[lng, lat]}>
          <View style={styles.marker} />
        </MapLibreRN.MarkerView>

        {location && (
          <MapLibreRN.UserLocation
            animated={true}
            showsUserHeadingIndicator={true}
            onPress={async () => {
              const currentZoom = await mapRef.current?.getZoom();
              const newZoom = (currentZoom || 0) + 2;

              cameraController.setCamera({
                centerCoordinate: [location.longitude, location.latitude],
                zoomLevel: newZoom,
                animationDuration: 500,
                animationMode: 'flyTo'
              });
            }}
          ></MapLibreRN.UserLocation>
        )}
      </MapLibreRN.MapView>
      <TouchableOpacity
        onPress={() => {
          navigation.goBack();
        }}
        style={[
          styles.backButtonContainer,
          { top: Platform.OS === 'android' ? insets.top + 20 : insets.top }
        ]}
      >
        <View style={styles.backButton}>
          <ChevronLeft fill={Colors.WHITE} />
        </View>
      </TouchableOpacity>
      <TouchableOpacity
        onPress={handleGetLocation}
        style={[
          styles.cornerButton,
          styles.bottomButton,
          styles.bottomRightButton,
          { bottom: tabBarHeight + insets.bottom + 20 }
        ]}
      >
        {isLocationLoading ? (
          <ActivityIndicator size="small" color={Colors.DARK_BLUE} />
        ) : (
          <LocationIcon />
        )}
      </TouchableOpacity>

      <TouchableOpacity
        onPress={() => openInExternalMaps(lat, lng)}
        style={[
          styles.cornerButton,
          styles.bottomButton,
          styles.topRightButton,
          { top: Platform.OS === 'android' ? insets.top + 24 : insets.top + 4 }
        ]}
      >
        <MapSvg fill={Colors.DARK_BLUE} />
      </TouchableOpacity>

      {center ? (
        <ScaleBar
          zoom={zoom}
          latitude={center[1]}
          isVisible={isZooming}
          bottom={tabBarHeight + insets.bottom + 38}
        />
      ) : null}

      <WarningModal
        type={'success'}
        isVisible={askLocationVisible}
        onClose={() => setAskLocationVisible(false)}
        action={handleAcceptPermission}
        message="To use this feature we need your permission to access your location. If you press OK your system will ask you to approve location sharing with NomadMania app."
      />
      <WarningModal
        type={'success'}
        isVisible={openSettingsVisible}
        onClose={() => setOpenSettingsVisible(false)}
        action={async () => {
          const isServicesEnabled = await Location.hasServicesEnabledAsync();

          if (!isServicesEnabled) {
            Platform.OS === 'ios'
              ? Linking.openURL('app-settings:')
              : Linking.sendIntent('android.settings.LOCATION_SOURCE_SETTINGS');
          } else {
            Platform.OS === 'ios' ? Linking.openURL('app-settings:') : Linking.openSettings();
          }
        }}
        message="NomadMania app needs location permissions to function properly. Open settings?"
      />
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  map: {
    ...StyleSheet.absoluteFillObject
  },
  backButtonContainer: {
    position: 'absolute',
    width: 50,
    height: 50,
    top: 50,
    left: 12,
    justifyContent: 'center',
    alignItems: 'center',
    zIndex: 2
  },
  backButton: {
    width: 42,
    height: 42,
    borderRadius: 21,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'rgba(0, 0, 0, 0.3)'
  },
  marker: {
    width: 20,
    height: 20,
    borderRadius: 10,
    backgroundColor: Colors.ORANGE,
    borderWidth: 2,
    borderColor: Colors.WHITE
  },
  cornerButton: {
    position: 'absolute',
    backgroundColor: Colors.WHITE,
    padding: 12,
    width: 48,
    height: 48,
    borderRadius: 24,
    alignItems: 'center',
    justifyContent: 'center',
    shadowColor: '#000',
    shadowOffset: {
      width: 0,
      height: 1
    },
    shadowOpacity: 0.25,
    shadowRadius: 1.5,
    elevation: 2
  },
  bottomButton: {
    width: 42,
    height: 42,
    borderRadius: 21
  },
  bottomRightButton: {
    right: 16
  },
  topRightButton: {
    top: 54,
    right: 16
  }
});

export default FullMapScreen;
