import 'dart:io';

import 'package:get/get.dart';
import 'package:intaleq_maps/intaleq_maps.dart';
import 'package:get_storage/get_storage.dart';
import 'dart:math' as math;
import '../../main.dart';
import '../print.dart';

class OfflineMapService {
  static final OfflineMapService instance = OfflineMapService._();
  OfflineMapService._();

  final _offlineRegionName = "UserRegion";
  bool _isDownloading = false;
  LatLng? _lastDownloadedCenter;

  /// Calculate bounding box for a given center and radius in km
  LatLngBounds _calculateBounds(LatLng center, double radiusKm) {
    const double earthRadius = 6371.0;

    // Latitude degrees per km
    double latDelta = (radiusKm / earthRadius) * (180 / math.pi);
    // Longitude degrees per km at given latitude
    double lngDelta = (radiusKm / earthRadius) *
        (180 / math.pi) /
        math.cos(center.latitude * math.pi / 180);

    return LatLngBounds(
      southwest:
          LatLng(center.latitude - latDelta, center.longitude - lngDelta),
      northeast:
          LatLng(center.latitude + latDelta, center.longitude + lngDelta),
    );
  }

  /// Downloads a specified radius around a coordinate
  Future<void> downloadRegion(LatLng center,
      {double radiusKm = 10.0,
      double minZoom = 6.0,
      double maxZoom = 15.0}) async {
    if (_isDownloading) return;

    // Avoid re-downloading if the user hasn't moved significantly (e.g. > 5km)
    if (_lastDownloadedCenter != null) {
      double distance = _calculateDistance(center, _lastDownloadedCenter!);
      if (distance < 5.0) return; // skip if close to previously downloaded
    }

    _isDownloading = true;

    try {
      final bounds = _calculateBounds(center, radiusKm);

      // Select style based on current theme
      final String styleStr =
          Get.isDarkMode ? "assets/style_dark.json" : "assets/style.json";

      // iOS native crash guard: MLNTilePyramidOfflineRegion does not support relative asset URLs.
      // We skip native offline registration on iOS if using local assets to ensure stability.
      if (Platform.isIOS && !styleStr.startsWith('http')) {
        Log.print(
            "ℹ️ Skipping native offline registration on iOS for asset-based style to prevent crash.");
        return;
      }

      final regionDefinition = OfflineRegionDefinition(
        bounds: bounds,
        mapStyleUrl: styleStr,
        minZoom: minZoom,
        maxZoom: maxZoom,
      );

      // We'll update the last downloaded center immediately
      _lastDownloadedCenter = center;

      // MapLibre standard API for offline downloads
      await downloadOfflineRegion(regionDefinition, metadata: {
        'name': '$_offlineRegionName-${center.latitude}-${center.longitude}',
        'downloadDate': DateTime.now().toIso8601String(),
      });

      // Reassurance log for the user
      Log.print("📍 Map Ready: Service is utilizing local tile cache.");
      Log.print(
          "✅ Offline Map Cached for Region: $center (radius: ${radiusKm}km, style: $styleStr)");
    } catch (e) {
      Log.print("⚠️ Offline Map Download Failed: $e");
    } finally {
      _isDownloading = false;
    }
  }

  /// Helper to calculate distance in km
  double _calculateDistance(LatLng p1, LatLng p2) {
    var p = 0.017453292519943295;
    var c = math.cos;
    var a = 0.5 -
        c((p2.latitude - p1.latitude) * p) / 2 +
        c(p1.latitude * p) *
            c(p2.latitude * p) *
            (1 - c((p2.longitude - p1.longitude) * p)) /
            2;
    return 12742 * math.asin(math.sqrt(a));
  }

  /// Clears all offline map regions and tiles from local storage
  Future<void> clearCache() async {
    try {
      Log.print("♻️ Purging MapLibre Offline Cache...");
      // In maplibre_gl 0.25.0, we use top-level functions instead of an OfflineManager class
      final List<OfflineRegion> regions = await getListOfRegions();
      for (var region in regions) {
        await deleteOfflineRegion(region.id);
      }
      Log.print("✅ Map cache cleared successfully. ${regions.length} regions removed.");
    } catch (e) {
      Log.print("⚠️ Failed to clear map cache: $e");
    }
  }
}
