import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { SafeAreaView, View, Text, Platform, TouchableOpacity } from 'react-native';
import MapView, { Geojson, UrlTile } from 'react-native-maps';
import * as turf from '@turf/turf';
import { Feature } from '@turf/turf';
import { useNavigation } from '@react-navigation/native';

import { Header, Modal, FlatList as List } from 'src/components';

import { MAP_HOST } from 'src/constants';
import { Colors } from 'src/theme';
import { findRegionInDataset } from 'src/utils/mapHelpers';
import { calculateMapRegion } from '../utils/calculateRegion';
import { FeatureCollection } from 'src/types/map';
import { NAVIGATION_PAGES } from 'src/types';
import { RegionAddData } from '../utils/types';
import { useGetRegionsForTripsQuery } from '@api/trips';
import { styles } from './styles';

import regionsGeojson from '../../../../../assets/geojson/nm2022.json';
import SearchSvg from '../../../../../assets/icons/search.svg';
import SaveSvg from '../../../../../assets/icons/travels-screens/save.svg';

const AddRegionsScreen = ({ route }: { route: any }) => {
  const { regionsParams }: { regionsParams: RegionAddData[] } = route.params;
  const { data } = useGetRegionsForTripsQuery(true);
  const navigation = useNavigation();

  const [regions, setRegions] = useState<RegionAddData[] | null>(null);
  const [isModalVisible, setIsModalVisible] = useState(false);
  const [selectedRegions, setSelectedRegions] = useState<FeatureCollection[]>([]);
  const [regionsToSave, setRegionsToSave] = useState<RegionAddData[]>([]);
  const [regionData, setRegionData] = useState<RegionAddData | null>(null);
  const [regionPopupVisible, setRegionPopupVisible] = useState(false);
  const mapRef = useRef<MapView>(null);

  useEffect(() => {
    if (data && data.regions) {
      setRegions(data.regions);
    }
  }, [data]);

  useEffect(() => {
    const addRegionsAsync = async () => {
      if (regionsParams) {
        const promises = regionsParams.map((param) => {
          const foundRegion: Feature | undefined = (
            regionsGeojson as FeatureCollection
          ).features.find((region) => region.properties?.id === param.id);
          if (foundRegion) {
            setRegionsToSave((prevRegions) => [...prevRegions, param]);
            return {
              type: 'FeatureCollection',
              features: [
                {
                  geometry: foundRegion.geometry,
                  properties: foundRegion.properties,
                  type: 'Feature'
                }
              ]
            };
          }
          return null;
        });

        const results = await Promise.all(promises);
        const validRegions = results.filter(Boolean);

        setSelectedRegions(
          (prevSelectedRegions) => [...prevSelectedRegions, ...validRegions] as FeatureCollection[]
        );
      }
    };

    addRegionsAsync();
  }, [regionsParams]);

  const addRegionFromSearch = async (searchRegion: RegionAddData) => {
    const foundRegion = (regionsGeojson as FeatureCollection).features.find(
      (region) => region.properties?.id === searchRegion.id
    );

    if (foundRegion) {
      const regionIndex = selectedRegions.findIndex(
        (region) => region.features[0].properties?.id === searchRegion.id
      );
      const regionFromApi = regions?.find((region) => region.id === searchRegion.id);

      if (regionIndex < 0 && regionFromApi) {
        const newRegion = {
          type: 'FeatureCollection',
          features: [
            {
              geometry: foundRegion.geometry,
              properties: foundRegion.properties,
              type: 'Feature'
            }
          ]
        };

        setSelectedRegions([...selectedRegions, newRegion as FeatureCollection]);
        setRegionsToSave((prevRegions) => [...prevRegions, regionFromApi]);
        setRegionPopupVisible(true);

        const bounds = turf.bbox(foundRegion);
        const region = calculateMapRegion(bounds);
        mapRef.current?.animateToRegion(region, 1000);
      }
    }
  };

  const handleSavePress = () => {
    navigation.navigate(
      ...([
        NAVIGATION_PAGES.ADD_TRIP,
        { regionsToSave: regionsToSave, editTripId: route.params?.editId }
      ] as never)
    );
  };

  const handleSetRegionData = (regionId: number) => {
    const foundRegion = regions?.find((region) => region.id === regionId);

    if (foundRegion) {
      setRegionData(foundRegion);
      setRegionsToSave((prevRegions) => [...prevRegions, foundRegion]);
    }
  };

  const handleMapPress = useCallback(
    async (event: {
      nativeEvent: { coordinate: { latitude: any; longitude: any }; action?: string };
    }) => {
      if (event.nativeEvent?.action === 'polygon-press') return;

      const { latitude, longitude } = event.nativeEvent.coordinate;
      const point = turf.point([longitude, latitude]);

      let foundRegion = findRegionInDataset(regionsGeojson, point);

      if (foundRegion) {
        const id = foundRegion.properties?.id;

        const newRegion = {
          type: 'FeatureCollection',
          features: [
            {
              geometry: foundRegion.geometry,
              properties: foundRegion.properties,
              type: 'Feature'
            }
          ]
        };

        const regionIndex = selectedRegions.findIndex(
          (region) => region.features[0].properties?.id === id
        );

        if (regionIndex >= 0) {
          const newSelectedRegions = [...selectedRegions];
          newSelectedRegions.splice(regionIndex, 1);
          setSelectedRegions(newSelectedRegions);
          setRegionsToSave(regionsToSave.filter((region) => region.id !== id));
          setRegionPopupVisible(false);
          return;
        } else {
          setSelectedRegions([...selectedRegions, newRegion] as FeatureCollection[]);
        }

        handleSetRegionData(id);
        setRegionPopupVisible(true);

        const bounds = turf.bbox(foundRegion);
        const region = calculateMapRegion(bounds);

        mapRef.current?.animateToRegion(region, 1000);
      }
    },
    [selectedRegions, regions]
  );

  function renderGeoJSON() {
    if (!selectedRegions || !selectedRegions.length) return null;

    return selectedRegions.map((region, index) => (
      <Geojson
        key={index}
        geojson={region as any}
        fillColor="rgba(237, 147, 52, 0.5)"
        strokeColor={Colors.ORANGE}
        strokeWidth={Platform.OS == 'android' ? 2 : 1}
        zIndex={3}
        tracksViewChanges={false}
      />
    ));
  }

  const renderedGeoJSON = useMemo(() => renderGeoJSON(), [selectedRegions]);

  return (
    <SafeAreaView style={{ height: '100%' }}>
      <View style={styles.wrapper}>
        <Header label={'Add Regions'} />
        <View style={styles.searchContainer}>
          <TouchableOpacity style={[styles.regionSelector]} onPress={() => setIsModalVisible(true)}>
            <SearchSvg fill={Colors.LIGHT_GRAY} />
            <Text style={styles.regionText}>Search</Text>
          </TouchableOpacity>
          <TouchableOpacity
            style={[
              styles.saveBtn,
              selectedRegions.length ? styles.saveBtnActive : styles.saveBtnDisabled
            ]}
            onPress={handleSavePress}
            disabled={!selectedRegions.length}
          >
            <SaveSvg fill={selectedRegions.length ? Colors.WHITE : Colors.LIGHT_GRAY} />
          </TouchableOpacity>
        </View>
      </View>

      <View style={styles.container}>
        <MapView
          ref={mapRef}
          style={styles.map}
          showsMyLocationButton={false}
          showsCompass={false}
          zoomControlEnabled={false}
          mapType={Platform.OS == 'android' ? 'none' : 'standard'}
          maxZoomLevel={15}
          minZoomLevel={0}
          initialRegion={{
            latitude: 0,
            longitude: 0,
            latitudeDelta: 180,
            longitudeDelta: 180
          }}
          onPress={handleMapPress}
        >
          <UrlTile
            urlTemplate={`${MAP_HOST}/tiles_osm/{z}/{x}/{y}`}
            maximumZ={15}
            maximumNativeZ={13}
            shouldReplaceMapContent
            minimumZ={0}
          />
          <UrlTile
            urlTemplate={`${MAP_HOST}/tiles_nm/grid/{z}/{x}/{y}`}
            maximumZ={15}
            maximumNativeZ={13}
            shouldReplaceMapContent
            minimumZ={0}
            opacity={0.3}
          />
          {renderedGeoJSON}
        </MapView>
      </View>
      {regionPopupVisible && regionData && (
        <View style={styles.popupWrapper}>
          <View style={styles.popupContainer}>
            <Text style={styles.popupText}>{regionData.name ?? regionData.region_name}</Text>
          </View>
        </View>
      )}
      <Modal
        onRequestClose={() => setIsModalVisible(false)}
        headerTitle={'Select Regions'}
        visible={isModalVisible}
      >
        <List
          itemObject={(object) => {
            setIsModalVisible(false);
            setRegionData(object);
            addRegionFromSearch(object);
          }}
        />
      </Modal>
    </SafeAreaView>
  );
};

export default AddRegionsScreen;
