import 'dart:convert';
import 'package:geolocator/geolocator.dart';
import 'package:http/http.dart' as http;

/// Why location cannot be captured (used to show the right alert).
enum LocationCheckResult {
  ready,
  serviceDisabled,         // device GPS/location is switched off
  permissionDenied,        // user denied — can ask again
  permissionPermanentlyDenied, // "Don't ask again" was checked
}

/// GPS coordinates + reverse-geocoded details captured at survey submission.
class SurveyLocation {
  final double lat;
  final double lng;
  final String address;
  final String zone;     // suburb / neighbourhood
  final String city;     // detected city / town
  final String state;    // detected state
  final String pincode;  // postal code from reverse-geocode

  const SurveyLocation({
    required this.lat,
    required this.lng,
    required this.address,
    required this.zone,
    this.city = '',
    this.state = '',
    this.pincode = '',
  });

  factory SurveyLocation.empty() =>
      const SurveyLocation(lat: 0.0, lng: 0.0, address: '', zone: '');

  bool get hasFix => lat != 0.0 || lng != 0.0;
}

class LocationService {
  /// Checks service + permission WITHOUT triggering a system prompt.
  /// Use this to decide whether to show an in-app alert before capturing.
  static Future<LocationCheckResult> checkStatus() async {
    if (!await Geolocator.isLocationServiceEnabled()) {
      return LocationCheckResult.serviceDisabled;
    }
    final perm = await Geolocator.checkPermission();
    if (perm == LocationPermission.deniedForever) {
      return LocationCheckResult.permissionPermanentlyDenied;
    }
    if (perm == LocationPermission.denied) {
      return LocationCheckResult.permissionDenied;
    }
    return LocationCheckResult.ready;
  }

  /// Requests permission (one-shot OS prompt) then captures GPS + address.
  /// Never throws — returns [SurveyLocation.empty] on any failure.
  static Future<SurveyLocation> capture() async {
    try {
      if (!await Geolocator.isLocationServiceEnabled()) {
        return SurveyLocation.empty();
      }

      var perm = await Geolocator.checkPermission();
      if (perm == LocationPermission.denied) {
        perm = await Geolocator.requestPermission();
      }
      if (perm == LocationPermission.denied ||
          perm == LocationPermission.deniedForever) {
        return SurveyLocation.empty();
      }

      final position = await Geolocator.getCurrentPosition(
        locationSettings: const LocationSettings(
          accuracy: LocationAccuracy.high,
        ),
      ).timeout(const Duration(seconds: 10));

      final geo = await _reverseGeocode(position.latitude, position.longitude);

      return SurveyLocation(
        lat: position.latitude,
        lng: position.longitude,
        address: geo['display_name'] ?? '',
        zone: geo['zone'] ?? '',
        city: geo['city'] ?? '',
        state: geo['state'] ?? '',
        pincode: geo['pincode'] ?? '',
      );
    } catch (_) {
      return SurveyLocation.empty();
    }
  }

  /// Opens the device's Location / GPS settings page.
  static Future<void> openLocationSettings() =>
      Geolocator.openLocationSettings();

  /// Opens this app's permission settings page (for permanently-denied case).
  static Future<void> openAppSettings() => Geolocator.openAppSettings();

  static Future<Map<String, String>> _reverseGeocode(
      double lat, double lng) async {
    try {
      final uri = Uri.parse(
        'https://nominatim.openstreetmap.org/reverse'
        '?lat=$lat&lon=$lng&format=json&addressdetails=1',
      );
      final res = await http
          .get(uri, headers: {'User-Agent': 'DoorMile-CRM/1.0'})
          .timeout(const Duration(seconds: 6));

      if (res.statusCode != 200) return {};

      final body = jsonDecode(res.body) as Map<String, dynamic>;
      final addr = (body['address'] as Map<String, dynamic>?) ?? {};

      final zone = (addr['suburb'] ??
              addr['neighbourhood'] ??
              addr['quarter'] ??
              addr['village'] ??
              '') as String;

      final city = (addr['city'] ??
              addr['town'] ??
              addr['municipality'] ??
              addr['county'] ??
              addr['state_district'] ??
              '') as String;

      final state = (addr['state'] ?? '') as String;

      final pincode = (addr['postcode'] ?? '') as String;

      return {
        'display_name': (body['display_name'] as String?) ?? '',
        'zone': zone,
        'city': city,
        'state': state,
        'pincode': pincode,
      };
    } catch (_) {
      return {};
    }
  }
}
