import React, { useState, useRef, useEffect } from 'react';
import {
  View,
  Text,
  StyleSheet,
  TouchableOpacity,
  Alert,
  TextInput,
  Dimensions,
  ActivityIndicator,
  KeyboardAvoidingView,
  Platform
} from 'react-native';
import * as MapLibreGL from '@maplibre/maplibre-react-native';
import { Ionicons } from '@expo/vector-icons';
import { MMKV } from 'react-native-mmkv';
import NetInfo from '@react-native-community/netinfo';
import { VECTOR_MAP_HOST } from 'src/constants';
import { offlineMapManager } from '../OfflineMapManager';
import { useSubscription } from '../useSubscription';
import { formatBytes } from '../formatters';
import { Header, PageWrapper } from 'src/components';
import { SafeAreaView } from 'react-native-safe-area-context';

const storage = new MMKV();
const OFFLINE_MAPS_KEY = 'offline_maps';
const { width, height } = Dimensions.get('window');

const MAX_SELECTOR_WIDTH_RATIO = 0.08;
const MAX_SELECTOR_HEIGHT_RATIO = 0.06;
const MIN_SELECTOR_WIDTH_RATIO = 0.9;
const MIN_SELECTOR_HEIGHT_RATIO = 0.6;
const ZOOM_THRESHOLD_START = 3;
const ZOOM_THRESHOLD_END = 7;

const AVERAGE_VECTOR_TILE_SIZE_BYTES = 500;
const TILE_SIZE_MULTIPLIER_BY_ZOOM = {
  10: 0.5,
  11: 0.7,
  12: 0.9,
  13: 1.1,
  14: 1.3,
  15: 1.6,
  16: 1.9,
  17: 2.2,
  18: 2.2,
  19: 2.2,
  20: 2.2
};

export default function SelectOwnMapScreen({ navigation, route }) {
  const map = useRef(null);
  const [mapLoaded, setMapLoaded] = useState(false);
  const [currentZoom, setCurrentZoom] = useState(1);
  const [selectorBounds, setSelectorBounds] = useState({
    north: 0,
    south: 0,
    east: 0,
    west: 0
  });
  const [name, setName] = useState('');
  const [estimatedSize, setEstimatedSize] = useState(0);
  const [isConnectedToWifi, setIsConnectedToWifi] = useState(true);
  const { isPremium } = useSubscription();
  const [selectorSize, setSelectorSize] = useState({
    width: width * MAX_SELECTOR_WIDTH_RATIO,
    height: height * MAX_SELECTOR_HEIGHT_RATIO
  });
  const [mapCenter, setMapCenter] = useState([0, 0]);
  const [tilesCount, setTilesCount] = useState(0);

  const updateMap = route.params?.updateMap;

  useEffect(() => {
    if (updateMap) {
      setName(updateMap.name);
    } else {
      const now = new Date();
      setName(`Offline Map ${now.toLocaleDateString()}`);
    }

    checkConnectionType();
  }, [updateMap]);

  useEffect(() => {
    setSelectorSize(getSelectorSize());
  }, [currentZoom]);

  const getSelectorSize = () => {
    if (currentZoom <= ZOOM_THRESHOLD_START) {
      return {
        width: width * MAX_SELECTOR_WIDTH_RATIO,
        height: height * MAX_SELECTOR_HEIGHT_RATIO
      };
    } else if (currentZoom >= ZOOM_THRESHOLD_END) {
      return {
        width: width * MIN_SELECTOR_WIDTH_RATIO,
        height: height * MIN_SELECTOR_HEIGHT_RATIO
      };
    } else {
      const zoomRatio =
        (currentZoom - ZOOM_THRESHOLD_START) / (ZOOM_THRESHOLD_END - ZOOM_THRESHOLD_START);
      const widthRatio =
        MAX_SELECTOR_WIDTH_RATIO -
        zoomRatio * (MAX_SELECTOR_WIDTH_RATIO - MIN_SELECTOR_WIDTH_RATIO);
      const heightRatio =
        MAX_SELECTOR_HEIGHT_RATIO -
        zoomRatio * (MAX_SELECTOR_HEIGHT_RATIO - MIN_SELECTOR_HEIGHT_RATIO);

      return {
        width: width * widthRatio,
        height: height * heightRatio
      };
    }
  };

  const checkConnectionType = async () => {
    try {
      const connectionInfo = await NetInfo.fetch();
      setIsConnectedToWifi(connectionInfo.type === 'wifi');
    } catch (error) {
      console.error('Error checking network connection:', error);
      setIsConnectedToWifi(true);
    }
  };

  const onMapLoad = () => {
    setMapLoaded(true);

    if (updateMap && updateMap.bounds) {
      try {
        const bounds = JSON.parse(updateMap.bounds);

        setSelectorBounds({
          north: bounds.north,
          south: bounds.south,
          east: bounds.east,
          west: bounds.west
        });

        map.current.fitBounds([bounds.west, bounds.south], [bounds.east, bounds.north], 50, 500);

        calculateEstimatedSizeFromSelector(bounds);
      } catch (error) {
        console.error('Error centering map on bounds:', error);
      }
    }
  };

  const onRegionDidChange = async (feature) => {
    if (!map.current) return;
    try {
      const zoom = feature.properties.zoomLevel;
      setCurrentZoom(zoom || 1);

      if (feature.geometry && feature.geometry.coordinates) {
        setMapCenter(feature.geometry.coordinates);
      }

      const newSelectorBounds = calculateSelectorBounds(
        feature.geometry.coordinates,
        selectorSize,
        zoom
      );
      setSelectorBounds(newSelectorBounds);

      calculateEstimatedSizeFromSelector(newSelectorBounds);
    } catch (error) {
      console.error('Error updating selector bounds:', error);
    }
  };

  const calculateSelectorBounds = (center, size, zoom) => {
    const EARTH_CIRCUMFERENCE = 40075016.686;
    const TILE_SIZE = 512;

    const metersPerPixel =
      (EARTH_CIRCUMFERENCE * Math.cos((center[1] * Math.PI) / 180)) /
      Math.pow(2, zoom + 1) /
      TILE_SIZE;

    const widthMeters = size.width * metersPerPixel;
    const heightMeters = size.height * metersPerPixel;

    const lonOffsetDegrees = widthMeters / 2 / (EARTH_CIRCUMFERENCE / 360);
    const latOffsetDegrees = heightMeters / 2 / (EARTH_CIRCUMFERENCE / 360);

    return {
      west: center[0] - lonOffsetDegrees,
      east: center[0] + lonOffsetDegrees,
      south: center[1] - latOffsetDegrees,
      north: center[1] + latOffsetDegrees
    };
  };

  const calculateEstimatedSizeFromSelector = async (bounds) => {
    try {
      const options = {
        styleURL: `${VECTOR_MAP_HOST}/nomadmania-maps2025.json`,
        bounds: [
          [bounds.west, bounds.south],
          [bounds.east, bounds.north]
        ],
        minZoom: 10,
        maxZoom: 20
      };

      let totalTilesCount = 0;
      let totalSizeBytes = 0;

      for (let zoom = 10; zoom <= 20; zoom++) {
        const tilesAtZoom = calculateTilesInBounds(
          bounds.west,
          bounds.south,
          bounds.east,
          bounds.north,
          zoom
        );

        totalTilesCount += tilesAtZoom;

        const tileSizeBytes =
          AVERAGE_VECTOR_TILE_SIZE_BYTES * (TILE_SIZE_MULTIPLIER_BY_ZOOM[zoom] || 1.0);
        const zoomLevelSizeBytes = tilesAtZoom * tileSizeBytes;

        totalSizeBytes += zoomLevelSizeBytes;
      }

      setTilesCount(totalTilesCount);

      totalSizeBytes = totalSizeBytes * 1.1;

      setEstimatedSize(totalSizeBytes);
    } catch (error) {
      console.error('Error estimating tile size:', error);
      const area = Math.abs((bounds.north - bounds.south) * (bounds.east - bounds.west));
      const estimatedBytes = Math.round(area * 100000);
      setEstimatedSize(estimatedBytes);
    }
  };

  const calculateTilesInBounds = (west, south, east, north, zoom) => {
    const nwTile = latLonToTile(north, west, zoom);
    const seTile = latLonToTile(south, east, zoom);

    const xTiles = Math.abs(seTile.x - nwTile.x) + 1;
    const yTiles = Math.abs(seTile.y - nwTile.y) + 1;

    return xTiles * yTiles;
  };

  const latLonToTile = (lat, lon, zoom) => {
    const n = 2.0 ** zoom;
    const x = Math.floor(((lon + 180.0) / 360.0) * n);
    const y = Math.floor(
      ((1.0 -
        Math.log(Math.tan((lat * Math.PI) / 180.0) + 1.0 / Math.cos((lat * Math.PI) / 180.0)) /
          Math.PI) /
        2.0) *
        n
    );

    return { x, y };
  };

  const downloadMap = async () => {
    if (!isPremium) {
      Alert.alert('Premium Required', 'Offline maps are available only with premium subscription.');
      return;
    }

    if (!name.trim()) {
      Alert.alert('Error', 'Please enter a name for this offline map');
      return;
    }

    if (tilesCount > 5000) {
      Alert.alert(
        'Large Area Selected',
        `You've selected an area with ${tilesCount} tiles. This may take a long time to download and use a lot of storage. Would you like to continue?`,
        [
          { text: 'Cancel', style: 'cancel' },
          { text: 'Continue', onPress: () => checkConnectionAndDownload() }
        ]
      );
    } else {
      checkConnectionAndDownload();
    }
  };

  const checkConnectionAndDownload = () => {
    if (!isConnectedToWifi) {
      Alert.alert(
        'Mobile Data Connection',
        'You are not connected to WiFi. Downloading map tiles may use a significant amount of data. Do you want to continue?',
        [
          { text: 'Cancel', style: 'cancel' },
          { text: 'Download', onPress: () => startDownload() }
        ]
      );
    } else {
      startDownload();
    }
  };

  const startDownload = async () => {
    try {
      const packId = updateMap ? updateMap.id : `map_${Date.now()}`;

      const offlinePackOptions = {
        name: packId,
        styleURL: `${VECTOR_MAP_HOST}/nomadmania-maps2025.json`,
        bounds: [
          [selectorBounds.west, selectorBounds.south],
          [selectorBounds.east, selectorBounds.north]
        ],
        minZoom: 10,
        maxZoom: 20
      };

      if (updateMap) {
        try {
          await offlineMapManager.deletePack(packId);
        } catch (error) {
          console.log('Error deleting existing pack:', error);
        }
      }

      const savedMapsString = storage.getString(OFFLINE_MAPS_KEY);
      const savedMaps = savedMapsString ? JSON.parse(savedMapsString) : [];

      const mapIndex = savedMaps.findIndex((map) => map.id === packId);

      const mapData = {
        id: packId,
        name: name,
        bounds: JSON.stringify(selectorBounds),
        size: estimatedSize,
        updatedAt: Date.now(),
        status: 'downloading',
        progress: 0,
        styleURL: `${VECTOR_MAP_HOST}/nomadmania-maps2025.json`,
        minZoom: 10,
        maxZoom: 20,
        tilesCount: tilesCount
      };

      if (mapIndex !== -1) {
        savedMaps[mapIndex] = { ...savedMaps[mapIndex], ...mapData };
      } else {
        savedMaps.push(mapData);
      }

      storage.set(OFFLINE_MAPS_KEY, JSON.stringify(savedMaps));

      offlineMapManager.createPack(
        offlinePackOptions,
        (progress) => {
          const mapsString = storage.getString(OFFLINE_MAPS_KEY);
          const maps = mapsString ? JSON.parse(mapsString) : [];
          const mapIndex = maps.findIndex((map) => map.id === packId);
          console.log('Download progress:', progress);

          if (mapIndex >= 0) {
            maps[mapIndex].progress = progress.percentage;

            if (progress.percentage === 100) {
              maps[mapIndex].status = 'valid';
              maps[mapIndex].size = progress.completedSize || maps[mapIndex].size;
              maps[mapIndex].updatedAt = Date.now();
            }

            storage.set(OFFLINE_MAPS_KEY, JSON.stringify(maps));
          }
        },
        (error) => {
          console.error('Download error:', error);

          const mapsString = storage.getString(OFFLINE_MAPS_KEY);
          const maps = mapsString ? JSON.parse(mapsString) : [];
          const mapIndex = maps.findIndex((map) => map.id === packId);

          if (mapIndex >= 0) {
            maps[mapIndex].status = 'invalid';
            storage.set(OFFLINE_MAPS_KEY, JSON.stringify(maps));
          }
        }
      );

      navigation.goBack();
    } catch (error) {
      console.error('Error starting download:', error);
      Alert.alert('Error', 'Failed to start download');
    }
  };

  return (
    <KeyboardAvoidingView
      style={styles.container}
      behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
    >
      <SafeAreaView style={{ height: '100%' }} edges={['top']}>
        <View style={styles.header}>
          <Header label="Select Area to Download" />
        </View>

        <View style={styles.mapContainer}>
          <MapLibreGL.MapView
            ref={map}
            style={styles.map}
            mapStyle={`${VECTOR_MAP_HOST}/nomadmania-maps2025.json`}
            onDidFinishLoadingMap={onMapLoad}
            onRegionDidChange={(feature) => onRegionDidChange(feature)}
          >
            <MapLibreGL.Camera
              defaultSettings={{
                centerCoordinate: [0, 0],
                zoomLevel: 1
              }}
            />

            {mapLoaded && (
              <View style={styles.selectorOverlay}>
                <View
                  style={[
                    styles.selector,
                    {
                      width: selectorSize.width,
                      height: selectorSize.height
                    }
                  ]}
                >
                  <Text style={styles.selectorText}>Selected Area</Text>
                </View>
              </View>
            )}
          </MapLibreGL.MapView>
        </View>

        <View style={styles.infoContainer}>
          <TextInput
            style={styles.nameInput}
            placeholder="Enter map name"
            value={name}
            onChangeText={setName}
          />

          {estimatedSize > 0 && (
            <View style={styles.infoRow}>
              <Text style={styles.sizeText}>Estimated size: {formatBytes(estimatedSize)}</Text>
              <Text style={styles.tilesText}>Tiles: {tilesCount}</Text>
            </View>
          )}

          <TouchableOpacity
            style={[styles.downloadButton, !isPremium && styles.disabledButton]}
            onPress={downloadMap}
            disabled={!isPremium}
          >
            <Text style={styles.downloadButtonText}>
              {updateMap ? 'Update Offline Map' : 'Download Offline Map'}
            </Text>
          </TouchableOpacity>
        </View>
      </SafeAreaView>
    </KeyboardAvoidingView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff'
  },
  header: {
    marginHorizontal: '5%'
  },
  title: {
    fontSize: 20,
    fontWeight: 'bold'
  },
  mapContainer: {
    flex: 1,
    position: 'relative'
  },
  map: {
    flex: 1
  },
  selectorOverlay: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    justifyContent: 'center',
    alignItems: 'center',
    pointerEvents: 'none'
  },
  selector: {
    borderWidth: 2,
    borderColor: '#0F67FE',
    borderRadius: 8,
    backgroundColor: 'rgba(15, 103, 254, 0.1)',
    justifyContent: 'center',
    alignItems: 'center'
  },
  selectorText: {
    color: '#0F67FE',
    fontWeight: '600',
    textAlign: 'center',
    padding: 8,
    backgroundColor: 'rgba(255,255,255,0.8)',
    borderRadius: 4,
    fontSize: 12
  },
  infoContainer: {
    marginHorizontal: '5%',
    borderTopWidth: 1,
    borderTopColor: '#eee'
  },
  infoRow: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    marginBottom: 16
  },
  nameInput: {
    borderWidth: 1,
    borderColor: '#ddd',
    borderRadius: 8,
    padding: 12,
    fontSize: 16,
    marginBottom: 12
  },
  sizeText: {
    fontSize: 14,
    color: '#555'
  },
  tilesText: {
    fontSize: 14,
    color: '#555'
  },
  downloadButton: {
    backgroundColor: '#0F67FE',
    paddingVertical: 12,
    borderRadius: 8,
    alignItems: 'center'
  },
  disabledButton: {
    backgroundColor: '#aaa'
  },
  downloadButtonText: {
    color: '#fff',
    fontSize: 16,
    fontWeight: '600'
  }
});
