import {
  Platform,
  TouchableOpacity,
  Image,
  Linking,
  TextInput,
  Dimensions,
  StatusBar,
  ActivityIndicator,
  ScrollView,
  View
} from 'react-native';
import React, { FC, useEffect, useRef, useState } from 'react';
import * as Location from 'expo-location';
import Animated, {
  Easing,
  useSharedValue,
  useAnimatedStyle,
  withTiming
} from 'react-native-reanimated';

import { styles } from './styles';
import { API_HOST, VECTOR_MAP_HOST } from 'src/constants';
import { CommonActions, NavigationProp } from '@react-navigation/native';
import { AvatarWithInitials, LocationPopup } from 'src/components';
import { Colors } from 'src/theme';

import CloseSvg from 'assets/icons/close.svg';
import LocationIcon from 'assets/icons/location.svg';
import SearchIcon from 'assets/icons/search.svg';

import FilterModal from '../../MapScreen/FilterModal';
import SearchModal from '../../MapScreen/UniversalSearch';
import { useGetUniversalSearch } from '@api/search';
import { storage, StoreType } from 'src/storage';
import { NAVIGATION_PAGES } from 'src/types';
import { SafeAreaView } from 'react-native-safe-area-context';
import * as MapLibreRN from '@maplibre/maplibre-react-native';
import {
  usePostGetVisitedCountriesIdsQuery,
  usePostGetVisitedDareIdsQuery,
  usePostGetVisitedRegionsIdsQuery
} from '@api/maps';
import moment from 'moment';

import TravelsIcon from 'assets/icons/bottom-navigation/globe-solid.svg';
import MapButton from 'src/components/MapButton';
import ScaleBar from 'src/components/ScaleBar';
import _ from 'lodash';
const defaultUserAvatar = require('assets/icon-user-share-location-solid.png');

const generateFilter = (ids: number[]) => {
  return ids.length ? ['any', ...ids.map((id) => ['==', 'id', id])] : ['==', 'id', -1];
};

let regions_visited = {
  id: 'regions_visited',
  type: 'fill',
  source: 'regions',
  'source-layer': 'regions',
  style: {
    fillColor: 'rgba(255, 126, 0, 1)',
    fillOpacity: 0.5,
    fillOutlineColor: 'rgba(14, 80, 109, 0)'
  },
  filter: generateFilter([]),
  maxzoom: 12
};

let countries_visited = {
  id: 'countries_visited',
  type: 'fill',
  source: 'countries',
  'source-layer': 'countries',
  style: {
    fillColor: 'rgba(255, 126, 0, 1)',
    fillOpacity: 0.5,
    fillOutlineColor: 'rgba(14, 80, 109, 0)'
  },
  filter: generateFilter([]),
  maxzoom: 12
};

let dare_visited = {
  id: 'dare_visited',
  type: 'fill',
  source: 'dare',
  'source-layer': 'dare',
  style: {
    fillColor: 'rgba(255, 126, 0, 1)',
    fillOpacity: 0.5,
    fillOutlineColor: 'rgba(255, 126, 0, 1)'
  },
  filter: generateFilter([]),
  maxzoom: 12
};

let regions = {
  id: 'regions',
  type: 'fill',
  source: 'regions',
  'source-layer': 'regions',
  style: {
    fillColor: 'rgba(15, 63, 79, 0)',
    fillOutlineColor: 'rgba(14, 80, 109, 0)'
  },
  filter: ['all'],
  maxzoom: 16
};

let countries = {
  id: 'countries',
  type: 'fill',
  source: 'countries',
  'source-layer': 'countries',
  style: {
    fillColor: 'rgba(15, 63, 79, 0)',
    fillOutlineColor: 'rgba(14, 80, 109, 0)'
  },
  filter: ['all'],
  maxzoom: 16
};

let dare = {
  id: 'dare',
  type: 'fill',
  source: 'dare',
  'source-layer': 'dare',
  style: {
    fillColor: 'rgba(14, 80, 109, 0.6)',
    fillOutlineColor: 'rgba(14, 80, 109, 1)'
  },
  filter: ['all'],
  maxzoom: 16
};

type Props = {
  navigation: NavigationProp<any>;
  route: any;
};

const UsersMapScreen: FC<Props> = ({ navigation, route }) => {
  const token = storage.get('token', StoreType.STRING) as string;
  const userId = route.params?.userId;
  const data = route.params?.data;

  const [regionsVisitedFilter, setRegionsVisitedFilter] = useState(generateFilter([]));
  const [countriesVisitedFilter, setCountriesVisitedFilter] = useState(generateFilter([]));
  const [dareVisitedFilter, setDareVisitedFilter] = useState(generateFilter([]));

  const [regionsFilter, setRegionsFilter] = useState<any>({
    visitedLabel: 'by',
    year: moment().year()
  });

  const mapRef = useRef<MapLibreRN.MapViewRef>(null);
  const cameraRef = useRef<MapLibreRN.CameraRef>(null);
  const [isFilterVisible, setIsFilterVisible] = useState<string | null>(null);
  const [tilesType, setTilesType] = useState({ label: 'NM regions', value: 0 });
  const tilesTypes = [
    { label: 'NM regions', value: 0 },
    { label: 'UN countries', value: 1 },
    { label: 'DARE places', value: 2 }
  ];
  const [type, setType] = useState('regions');
  const [location, setLocation] = useState<Location.LocationObjectCoords | null>(null);
  const [askLocationVisible, setAskLocationVisible] = useState<boolean>(false);
  const [openSettingsVisible, setOpenSettingsVisible] = useState<boolean>(false);
  const [isExpanded, setIsExpanded] = useState(false);
  const [searchVisible, setSearchVisible] = useState(false);
  const [index, setIndex] = useState<number>(0);
  const width = useSharedValue(48);
  const usableWidth = Dimensions.get('window').width - 32;
  const [search, setSearch] = useState('');
  const [searchInput, setSearchInput] = useState('');
  const { data: searchData } = useGetUniversalSearch(search, search.length > 0);
  const [isLocationLoading, setIsLocationLoading] = useState(false);

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

  const { data: visitedRegionIds } = usePostGetVisitedRegionsIdsQuery(
    token,
    regionsFilter.visitedLabel,
    regionsFilter.year,
    +userId,
    type === 'regions' && !!userId
  );
  const { data: visitedCountryIds } = usePostGetVisitedCountriesIdsQuery(
    token,
    regionsFilter.visitedLabel,
    regionsFilter.year,
    +userId,
    type === 'countries' && !!userId
  );
  const { data: visitedDareIds } = usePostGetVisitedDareIdsQuery(
    token,
    +userId,
    type === 'dare' && !!userId
  );

  useEffect(() => {
    if (visitedRegionIds) {
      setRegionsVisitedFilter(generateFilter(visitedRegionIds.ids));
    } else {
      setRegionsVisitedFilter(['==', 'id', -1]);
    }
  }, [visitedRegionIds]);

  useEffect(() => {
    if (visitedCountryIds) {
      setCountriesVisitedFilter(generateFilter(visitedCountryIds.ids));
    } else {
      setCountriesVisitedFilter(['==', 'id', -1]);
    }
  }, [visitedCountryIds]);

  useEffect(() => {
    if (visitedDareIds) {
      setDareVisitedFilter(generateFilter(visitedDareIds.ids));
    } else {
      setDareVisitedFilter(['==', 'id', -1]);
    }
  }, [visitedDareIds]);

  useEffect(() => {
    if (
      data.location_sharing &&
      data.location_last_seen_location?.lng &&
      data.location_last_seen_location?.lat &&
      cameraRef.current
    ) {
      cameraRef.current.flyTo(
        [data.location_last_seen_location.lng, data.location_last_seen_location.lat],
        1000
      );
    }
  }, [data, cameraRef.current]);

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

    setIsZooming(true);

    const currentZoom = await mapRef.current.getZoom();
    const currentCenter = await mapRef.current.getCenter();

    setZoom(currentZoom);
    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 () => {
    let currentLocation = await Location.getCurrentPositionAsync({
      accuracy: Location.Accuracy.Balanced
    });
    setLocation(currentLocation.coords);

    if (currentLocation.coords) {
      cameraRef.current?.flyTo(
        [currentLocation.coords.longitude, currentLocation.coords.latitude],
        1000
      );
    }
  };

  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 handlePress = () => {
    if (isExpanded) {
      setIndex(0);
      setSearchInput('');
    }
    setIsExpanded((prev) => !prev);
    width.value = withTiming(isExpanded ? 48 : usableWidth, {
      duration: 300,
      easing: Easing.inOut(Easing.ease)
    });
  };

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

  const handleSearch = async () => {
    setSearch(searchInput);
    setSearchVisible(true);
  };

  const handleGoBack = () => {
    navigation.goBack();
  };

  const handleCloseModal = () => {
    setSearchInput('');
    setSearchVisible(false);
    handlePress();
  };

  const handleFindRegion = (id: number, type: string) => {
    navigation.dispatch(
      CommonActions.reset({
        index: 1,
        routes: [
          {
            name: NAVIGATION_PAGES.IN_APP_MAP_TAB,
            state: {
              routes: [
                {
                  name: NAVIGATION_PAGES.MAP_TAB,
                  params: { id, type }
                }
              ]
            }
          }
        ]
      })
    );
  };

  const locationFeature: GeoJSON.Feature<GeoJSON.Point> = {
    type: 'Feature',
    geometry: {
      type: 'Point',
      coordinates: [data.location_last_seen_location?.lng, data.location_last_seen_location?.lat]
    },
    properties: {}
  };

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

      <MapLibreRN.MapView
        ref={mapRef}
        style={styles.map}
        mapStyle={VECTOR_MAP_HOST + '/nomadmania-maps.json'}
        rotateEnabled={false}
        attributionEnabled={false}
        onRegionDidChange={() => {
          hideTimer.current = setTimeout(() => {
            setIsZooming(false);
          }, 2000);
        }}
        onRegionIsChanging={handleMapChange}
        onRegionWillChange={_.debounce(handleMapChange, 200)}
      >
        {type === 'regions' && (
          <>
            <MapLibreRN.LineLayer
              id="nm-regions-line-layer"
              sourceID={regions.source}
              sourceLayerID={regions['source-layer']}
              filter={regions.filter as any}
              maxZoomLevel={regions.maxzoom}
              style={{
                lineColor: 'rgba(14, 80, 109, 1)',
                lineWidth: ['interpolate', ['linear'], ['zoom'], 0, 0.2, 4, 1, 5, 1.5, 12, 3],
                lineWidthTransition: { duration: 300, delay: 0 }
              }}
              belowLayerID="waterway-name"
            />
            <MapLibreRN.FillLayer
              id={regions.id}
              sourceID={regions.source}
              sourceLayerID={regions['source-layer']}
              filter={regions.filter as any}
              style={regions.style}
              maxZoomLevel={regions.maxzoom}
              belowLayerID={regions_visited.id}
            />
            <MapLibreRN.FillLayer
              id={regions_visited.id}
              sourceID={regions_visited.source}
              sourceLayerID={regions_visited['source-layer']}
              filter={regionsVisitedFilter as any}
              style={regions_visited.style}
              maxZoomLevel={regions_visited.maxzoom}
              belowLayerID="waterway-name"
            />
          </>
        )}
        {type === 'countries' && (
          <>
            <MapLibreRN.LineLayer
              id="countries-line-layer"
              sourceID={countries.source}
              sourceLayerID={countries['source-layer']}
              filter={countries.filter as any}
              maxZoomLevel={countries.maxzoom}
              style={{
                lineColor: 'rgba(14, 80, 109, 1)',
                lineWidth: ['interpolate', ['linear'], ['zoom'], 0, 0.2, 4, 1, 5, 1.5, 12, 3],
                lineWidthTransition: { duration: 300, delay: 0 }
              }}
              belowLayerID="waterway-name"
            />
            <MapLibreRN.FillLayer
              id={countries.id}
              sourceID={countries.source}
              sourceLayerID={countries['source-layer']}
              filter={countries.filter as any}
              style={countries.style}
              maxZoomLevel={countries.maxzoom}
              belowLayerID={countries_visited.id}
            />
            <MapLibreRN.FillLayer
              id={countries_visited.id}
              sourceID={countries_visited.source}
              sourceLayerID={countries_visited['source-layer']}
              filter={countriesVisitedFilter as any}
              style={countries_visited.style}
              maxZoomLevel={countries_visited.maxzoom}
              belowLayerID="waterway-name"
            />
          </>
        )}
        {type === 'dare' && (
          <>
            <MapLibreRN.FillLayer
              id={dare.id}
              sourceID={dare.source}
              sourceLayerID={dare['source-layer']}
              filter={dare.filter as any}
              style={dare.style}
              maxZoomLevel={dare.maxzoom}
              belowLayerID={dare_visited.id}
            />
            <MapLibreRN.FillLayer
              id={dare_visited.id}
              sourceID={dare_visited.source}
              sourceLayerID={dare_visited['source-layer']}
              filter={dareVisitedFilter as any}
              style={dare_visited.style}
              maxZoomLevel={dare_visited.maxzoom}
              belowLayerID="waterway-name"
            />
          </>
        )}

        {data.location_sharing && data.location_last_seen_location && data.own_profile !== 1 && (
          <MapLibreRN.ShapeSource id="user_location" shape={locationFeature}>
            <MapLibreRN.SymbolLayer
              id="user_symbol"
              filter={['!', ['has', 'point_count']]}
              aboveLayerID={Platform.OS === 'android' ? 'place-continent' : undefined}
              style={{
                iconImage: defaultUserAvatar,
                iconSize: [
                  'interpolate',
                  ['linear'],
                  ['zoom'],
                  0,
                  0.24,
                  5,
                  0.28,
                  10,
                  0.33,
                  15,
                  0.38,
                  20,
                  0.42
                ],
                iconAllowOverlap: true
              }}
            />
          </MapLibreRN.ShapeSource>
        )}

        <MapLibreRN.Camera ref={cameraRef} />
        {location && (
          <MapLibreRN.UserLocation
            animated={true}
            showsUserHeadingIndicator={true}
          ></MapLibreRN.UserLocation>
        )}
      </MapLibreRN.MapView>

      {center ? (
        <ScaleBar zoom={zoom} latitude={center[1]} isVisible={isZooming} bottom={80} />
      ) : null}

      {!isExpanded ? (
        <TouchableOpacity
          style={[styles.cornerButton, styles.topRightButton]}
          onPress={handleGoBack}
        >
          {data.user_data.avatar ? (
            <Image
              style={styles.avatar}
              source={{ uri: API_HOST + '/img/avatars/' + data.user_data.avatar }}
            />
          ) : (
            <AvatarWithInitials
              text={`${data.user_data.first_name[0] ?? ''}${data.user_data.last_name[0] ?? ''}`}
              flag={API_HOST + '/img/flags_new/' + data.user_data.flag1}
              size={48}
              borderColor={Colors.WHITE}
            />
          )}
        </TouchableOpacity>
      ) : null}

      <View style={styles.tabs}>
        <ScrollView
          horizontal
          showsHorizontalScrollIndicator={false}
          contentContainerStyle={{ marginLeft: 12, gap: 12, flexDirection: 'row' }}
        >
          <MapButton
            onPress={() => {
              setIsFilterVisible('regions');
            }}
            icon={TravelsIcon}
            text="Travels"
          />
        </ScrollView>
      </View>

      <TouchableOpacity
        onPress={handleGetLocation}
        style={[styles.cornerButton, styles.bottomButton, styles.bottomRightButton]}
      >
        {isLocationLoading ? (
          <ActivityIndicator size="small" color={Colors.DARK_BLUE} />
        ) : (
          <LocationIcon />
        )}
      </TouchableOpacity>
      <Animated.View
        style={[
          styles.searchContainer,
          styles.cornerButton,
          styles.topLeftButton,
          animatedStyle,
          { padding: 5 }
        ]}
      >
        {isExpanded ? (
          <>
            <TouchableOpacity onPress={handlePress} style={styles.iconButton}>
              <CloseSvg fill={'#0F3F4F'} />
            </TouchableOpacity>
            <TextInput
              style={styles.input}
              placeholder="Search regions, places, nomads"
              placeholderTextColor={Colors.LIGHT_GRAY}
              value={searchInput}
              onChangeText={(text) => setSearchInput(text)}
              onSubmitEditing={handleSearch}
            />
            <TouchableOpacity onPress={handleSearch} style={styles.iconButton}>
              <SearchIcon fill={'#0F3F4F'} />
            </TouchableOpacity>
          </>
        ) : (
          <TouchableOpacity onPress={handlePress} style={[styles.iconButton]}>
            <SearchIcon fill={'#0F3F4F'} />
          </TouchableOpacity>
        )}
      </Animated.View>
      <FilterModal
        isFilterVisible={isFilterVisible}
        setIsFilterVisible={setIsFilterVisible}
        tilesTypes={tilesTypes}
        tilesType={tilesType}
        setTilesType={setTilesType}
        setType={setType}
        userId={userId}
        setRegionsFilter={setRegionsFilter}
        isPublicView={true}
        isLogged={true}
      />
      <LocationPopup
        visible={askLocationVisible}
        onClose={() => setAskLocationVisible(false)}
        onAccept={handleAcceptPermission}
        modalText="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."
      />
      <LocationPopup
        visible={openSettingsVisible}
        onClose={() => setOpenSettingsVisible(false)}
        onAccept={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();
          }
        }}
        modalText="NomadMania app needs location permissions to function properly. Open settings?"
      />
      <SearchModal
        searchVisible={searchVisible}
        handleCloseModal={handleCloseModal}
        handleFindRegion={handleFindRegion}
        index={index}
        searchData={searchData}
        setIndex={setIndex}
        token={token}
      />
    </SafeAreaView>
  );
};

export default UsersMapScreen;
