import {Position} from '@rnmapbox/maps/src/types/Position';
import {getDistance} from 'geolib';
import { PA_Point, PA_Point_Cluster, PA_Point_Event } from '../types';



const createChecksum = (ids: (number | string)[]) => {
  let checksum = 0;
  for (const id of ids.sort()) {
    const value = typeof id === 'string' ? parseInt(id, 36) : id;
    checksum ^= value & 0xffff;
  }
  return checksum;
};

const clusterMarkers = (markers: PA_Point[], threshold: number) => {
  const clusters = [];

  for (const marker of markers) {
    let added = false;

    for (const cluster of clusters) {
      const [center] = cluster;
      const distance = Math.sqrt(
        Math.pow(center.latitude - marker.latitude, 2) +
          Math.pow(center.longitude - marker.longitude, 2),
      );

      if (distance < threshold) {
        cluster.push(marker);
        added = true;
        break;
      }
    }

    if (!added) {
      clusters.push([marker]);
    }
  }

  // Convert clusters to center points
  const centerPoints = clusters.map(cluster => {
    let isEvent = 0;

    const latitudes = cluster.map(marker => marker.latitude);
    const longitudes = cluster.map(marker => marker.longitude);
    const centerLatitude =
      latitudes.reduce((a, b) => a + b, 0) / latitudes.length;
    const centerLongitude =
      longitudes.reduce((a, b) => a + b, 0) / longitudes.length;
    const sumValues = cluster.reduce((sum, marker) => {
      if (marker.type === 'event') {
        if (isEvent === 0) isEvent = 1;
        else if (isEvent === 1) isEvent = -1;

        return sum + 1;
      }

      isEvent = -1;

      marker = marker as PA_Point_Cluster;

      return sum + (marker.cluster || 0);
    }, 0);

    if (isEvent === 1) {
      return cluster[0] as PA_Point_Event;
    }

    const ids = cluster.map(marker => marker.id);
    const idChecksum = createChecksum(ids);

    return {
      latitude: centerLatitude,
      longitude: centerLongitude,
      type: 'cluster',
      cluster: sumValues,
      id: idChecksum.toString(),
    } as PA_Point_Cluster;
  });

  return centerPoints;
};

/*const calculateThreshold = (bounds: [Position, Position]) => {
  const latDiff = bounds[0][0] - bounds[1][0];
  const lonDiff = bounds[0][1] - bounds[1][1];
  const maxDiff = Math.max(latDiff, lonDiff);
  const zoomLevel = Math.floor(Math.log2(360 / maxDiff));
  return 1 / Math.pow(2, zoomLevel);
};*/

const calculateRadius = (bounds: [Position, Position]) => {
  const distanceInMeters = getDistance(
    {latitude: bounds[0][0], longitude: bounds[0][1]},
    {latitude: bounds[1][0], longitude: bounds[1][1]},
  );
  return distanceInMeters / 600000 / 1.5 /*android bug fix for roteration*/;
};

function getLocationData(
  bounds: [Position, Position],
  zoomLevel: number,
): Promise<{locations: PA_Point[]} | undefined> {
  if (bounds === undefined) return Promise.resolve(undefined);

  return new Promise(resolve => {
    // Simulating an asynchronous operation, such as an API call
    setTimeout(() => {
      const rawData: {locations: PA_Point[]} = {
        locations: [
          /*{"latitude": 51.1657, "longitude": 10.4515, "cluster": 27, "type": "cluster", "id": "398742"},
          {"latitude": 51.1045, "longitude": 13.2017, "cluster": 19, "type": "cluster", "id": "519274"},
          {"latitude": 49.3988, "longitude": 8.6724, "cluster": 42, "type": "cluster", "id": "815926"},
          {"latitude": 51.3404, "longitude": 12.3743, "cluster": 5, "type": "cluster", "id": "105473"},
          {"latitude": 52.52, "longitude": 13.405, "cluster": 31, "type": "cluster", "id": "267351"},
          {"latitude": 48.8566, "longitude": 9.2725, "cluster": 14, "type": "cluster", "id": "845723"},
          {"latitude": 53.5511, "longitude": 9.9937, "cluster": 37, "type": "cluster", "id": "921864"},
          {"latitude": 50.1109, "longitude": 8.6821, "cluster": 23, "type": "cluster", "id": "467132"},
          {"latitude": 51.0493, "longitude": 13.7384, "cluster": 8, "type": "cluster", "id": "842906"},
          {"latitude": 49.0069, "longitude": 8.4037, "cluster": 46, "type": "cluster", "id": "346708"},*/
          {
            latitude: 51.9674,
            longitude: 7.6197,
            type: 'event',
            id: "203868",
            theme: 1,
          },
          {
            latitude: 51.9674,
            longitude: 7.6196,
            type: 'event',
            id: "203866",
            theme: 1,
          },
          {latitude: 51.9674, longitude: 7.6194, type: 'event', id: "203867"},
          {latitude: 50.7753, longitude: 6.0839, type: 'event', id: "501298"},
          {latitude: 53.0793, longitude: 8.8017, type: 'event', id: "763159"},
          {latitude: 48.7758, longitude: 9.1829, type: 'event', id: "917425"},
          {latitude: 52.3759, longitude: 9.732, type: 'event', id: "635028"},
          {latitude: 51.512, longitude: 7.4653, type: 'event', id: "841592"},
          {latitude: 49.4875, longitude: 8.466, type: 'event', id: "180356"},
          {latitude: 51.3611, longitude: 7.0119, type: 'event', id: "592874"},
          {latitude: 54.3227, longitude: 10.1356, type: 'event', id: "384791"},
          {latitude: 51.8049, longitude: 10.3351, type: 'event', id: "273495"},
          {latitude: 50.3213, longitude: 11.8676, type: 'event', id: "699318"},
          {latitude: 49.8765, longitude: 6.6695, type: 'event', id: "159627"},
          {latitude: 52.2651, longitude: 7.3085, type: 'event', id: "903716"},
          {latitude: 53.9638, longitude: 12.413, type: 'event', id: "487612"},
          {latitude: 50.9321, longitude: 9.1847, type: 'event', id: "827464"},
          {latitude: 52.4378, longitude: 13.2847, type: 'event', id: "931845"},
          {latitude: 49.4644, longitude: 11.0168, type: 'event', id: "674132"},
          {latitude: 51.1983, longitude: 8.8998, type: 'event', id: "298473"},
        ],
      };

      const zoomLevelChanged = calculateRadius(bounds);

      //console.log(zoomLevelChanged);

      const data = {
        locations: clusterMarkers(rawData.locations, zoomLevelChanged), //calculateThreshold(bounds)
      };

      resolve(data);
    }, 2); // Simulating a delay of 1 second for the asynchronous operation
  });
}

export default getLocationData;
