import * as FileSystem from 'expo-file-system/legacy';
import * as MapLibreRN from '@maplibre/maplibre-react-native';

import { VECTOR_MAP_HOST } from 'src/constants';
import { fetchLastMapTilesUpdate } from '@api/app';
import { storage, StoreType } from 'src/storage';

const baseTilesDir = `${FileSystem.cacheDirectory}tiles/`;
const STYLE_URL = `${VECTOR_MAP_HOST}/nomadmania-maps2025.json`;
const PACK_NAME = 'vector-map-pack';

async function deleteCachedTilesIfExist(): Promise<void> {
  try {
    const dirInfo = await FileSystem.getInfoAsync(baseTilesDir, { size: true });
    if (dirInfo.exists) {
      await FileSystem.deleteAsync(baseTilesDir, { idempotent: true });
    }
  } catch (error) {
    console.error('Error deleting cached tiles:', error);
  }
}

function getPackName(p: any): string | undefined {
  if (p?.name) return p.name;

  const metaStr = p?.pack?.metadata;
  if (!metaStr) return undefined;

  try {
    return JSON.parse(metaStr)?.name;
  } catch {
    return undefined;
  }
}

async function setupOfflineRegion(): Promise<void> {
  try {
    const bounds: [GeoJSON.Position, GeoJSON.Position] = [
      [-180, -85],
      [180, 85]
    ];
    const minZoom = 0;
    const maxZoom = 6;

    const existingPacks = await MapLibreRN.OfflineManager.getPacks();
    const pack = existingPacks.find((pack) => getPackName(pack) === PACK_NAME);

    if (pack) {
      const status = await pack.status();
      if (status.percentage < 100) {
        pack.resume();
      }
    } else {
      await MapLibreRN.OfflineManager.createPack(
        {
          name: PACK_NAME,
          bounds,
          minZoom,
          maxZoom,
          styleURL: STYLE_URL
        },
        () => {},
        (error) => {
          if (error) {
            console.error('Error creating offline pack:', error);
          }
        }
      );
    }
  } catch (error) {
    console.error('Error setting up offline pack:', error);
  }
}

export async function initOfflineSetup(): Promise<void> {
  await deleteCachedTilesIfExist();
  await updateMapsCache();
  await setupOfflineRegion();
}

export async function updateMapsCache() {
  const localLastDate =
    (storage.get('lastMapTilesUpdate', StoreType.STRING) as string) || '1990-01-01';
  const lastUpdate = await fetchLastMapTilesUpdate();

  if (lastUpdate && lastUpdate.date !== localLastDate) {
    const packs = await MapLibreRN.OfflineManager.getPacks();

    for (const pack of packs) {
      const name = getPackName(pack);
      if (!name) continue;
      try {
        await MapLibreRN.OfflineManager.invalidatePack(name);
      } catch {}
    }
    try {
      await MapLibreRN.OfflineManager.invalidateAmbientCache();
    } catch {}

    storage.set('lastMapTilesUpdate', lastUpdate.date);
  }
}
