import React, { useEffect } from 'react';
import { StyleSheet, Text, Dimensions, View } from 'react-native';
import Animated, { useSharedValue, useAnimatedStyle, withTiming } from 'react-native-reanimated';
import { Colors } from 'src/theme';

const FEET_PER_METER = 3.28084;
const FEET_PER_MILES = 5280;
const SCALE_SCREEN_RATIO = 0.25;
const TILE_SIZE_METERS_AT_0_ZOOM = 156543.034;

const SCALE_STEPS_IN_METERS = [
  2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000,
  1000000, 2000000, 3000000
];

const SCALE_STEPS_IN_FEET = [
  5,
  10,
  20,
  50,
  100,
  200,
  500,
  1000,
  2000,
  1 * FEET_PER_MILES,
  2 * FEET_PER_MILES,
  5 * FEET_PER_MILES,
  10 * FEET_PER_MILES,
  20 * FEET_PER_MILES,
  50 * FEET_PER_MILES,
  100 * FEET_PER_MILES,
  200 * FEET_PER_MILES,
  500 * FEET_PER_MILES,
  1000 * FEET_PER_MILES,
  2000 * FEET_PER_MILES
];

interface ScaleBarProps {
  zoom: number;
  latitude: number;
  isVisible: boolean;
  bottom?: any;
}

const ScaleBar: React.FC<ScaleBarProps> = ({ zoom, latitude, isVisible, bottom = '21%' }) => {
  const metricWidth = useSharedValue(0);
  const imperialWidth = useSharedValue(0);
  const metricText = useSharedValue('');
  const imperialText = useSharedValue('');
  const screenWidth = Dimensions.get('window').width;
  const opacity = useSharedValue(isVisible ? 1 : 0);

  useEffect(() => {
    if (isVisible) {
      opacity.value = withTiming(1, { duration: 100 });
    } else {
      opacity.value = withTiming(0, { duration: 1500 });
    }
  }, [isVisible]);

  const animatedStyle = useAnimatedStyle(() => ({
    opacity: opacity.value
  }));

  const getResolutionFromZoomAndLatitude = (zoom: number, latitude: number) =>
    (TILE_SIZE_METERS_AT_0_ZOOM * Math.cos((latitude * Math.PI) / 180)) / Math.pow(2, zoom);

  const getBestStepFromResolution = (
    resolution: number,
    steps: number[],
    multiplier: number = 1
  ) => {
    return steps.reduce((bestStep, currentStep) => {
      const scaleSize = (2 * currentStep * multiplier) / resolution;
      return scaleSize / screenWidth < SCALE_SCREEN_RATIO ? currentStep : bestStep;
    });
  };

  const calculateScale = (zoom: number, latitude: number) => {
    const resolution = getResolutionFromZoomAndLatitude(zoom, latitude);

    const metricStep = getBestStepFromResolution(resolution, SCALE_STEPS_IN_METERS);
    const imperialStep = getBestStepFromResolution(resolution, SCALE_STEPS_IN_FEET, 0.4);

    const metricScaleSize = (2 * metricStep) / resolution;
    const imperialScaleSize = (2 * imperialStep) / resolution / FEET_PER_METER;

    metricText.value =
      metricStep >= 1000 ? `${(metricStep / 1000).toFixed(0)} km` : `${metricStep} m`;
    imperialText.value =
      imperialStep >= FEET_PER_MILES
        ? `${(imperialStep / FEET_PER_MILES).toFixed(0)} mi`
        : `${Math.round(imperialStep)} ft`;

    return { metricScaleSize, imperialScaleSize };
  };

  useEffect(() => {
    const { metricScaleSize, imperialScaleSize } = calculateScale(zoom, latitude);
    metricWidth.value = withTiming(metricScaleSize, { duration: 200 });
    imperialWidth.value = withTiming(imperialScaleSize, { duration: 300 });
  }, [zoom, latitude]);

  const animatedMetricLineStyle = useAnimatedStyle(() => ({
    left: metricWidth.value
  }));

  const animatedImperialLineStyle = useAnimatedStyle(() => ({
    left: imperialWidth.value
  }));

  const animatedCombinedStyle = useAnimatedStyle(() => ({
    width: Math.max(metricWidth.value, imperialWidth.value)
  }));

  if (!metricText.value || !imperialText.value) return null;

  return (
    <Animated.View style={[styles.container, { bottom }, animatedStyle]}>
      <Text style={[styles.text, { bottom: 0 }]}>{metricText.value}</Text>

      <Animated.View style={[styles.scaleBar, animatedCombinedStyle]}>
        <Animated.View style={[styles.verticalTick, { bottom: 0 }, animatedMetricLineStyle]} />
        <Animated.View style={[styles.verticalTick, { top: 0 }, animatedImperialLineStyle]} />
      </Animated.View>

      <Text style={[styles.text, { top: 0 }]}>{imperialText.value}</Text>
    </Animated.View>
  );
};

const styles = StyleSheet.create({
  container: {
    position: 'absolute',
    left: 16,
    alignItems: 'center'
  },
  scaleBar: {
    height: 1,
    backgroundColor: Colors.DARK_BLUE,
    position: 'relative',
    width: '100%'
  },
  verticalTick: {
    position: 'absolute',
    width: 1,
    height: 12,
    backgroundColor: Colors.DARK_BLUE
  },
  text: {
    fontSize: 10,
    fontWeight: '500',
    textAlign: 'center',
    color: Colors.DARK_BLUE,
    marginVertical: 4,
    position: 'absolute',
    left: 0
  }
});

export default ScaleBar;
