import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:sliding_up_panel/sliding_up_panel.dart';
import 'package:latlong2/latlong.dart';
import 'package:geocoding/geocoding.dart';
import 'package:geocode/geocode.dart';
import 'dart:async';

import 'package:fast_network_navigation/modules/navigation.dart';

class MapPage extends StatefulWidget {
  @override
  _MapPageState createState() => _MapPageState();
}
class Debounce {
  Duration delay;
  Timer? _timer;

  Debounce(
    this.delay,
  );

  call(void Function() callback) {
    _timer?.cancel();
    _timer = Timer(delay, callback);
  }

  dispose() {
    _timer?.cancel();
  }
}


class _MapPageState extends State<MapPage> {
  GeoCode geoCode = GeoCode();
  final mapController = MapController();
  String _currentCityName = "...";
  final Debounce _debounce = Debounce(Duration(seconds: 3));

  void _setCurrentCityName() async {
    if (mapController.camera.zoom < 9) {
      return; // Don't bother if the view is too wide
    }
    var currentCoordinates = mapController.camera.center;
    String? city;
    
    try{
      List<Placemark> placemarks = await placemarkFromCoordinates(currentCoordinates.latitude, currentCoordinates.longitude);
      city = placemarks[0].locality.toString();
    } catch (e) {
      debugPrint("Error: $e");
      try {
        Address address = await geoCode.reverseGeocoding(latitude: currentCoordinates.latitude, longitude: currentCoordinates.longitude);
        
        if (address.city == null || address.city.toString().contains("Throttled!")){
          throw Exception("Probably rate limited");
        }
        city = address.city.toString();
      } catch (e) {
        debugPrint("Error: $e");

      }
    }
    if (city != null) {
      setState(() {
        _currentCityName = city!;
      });
    } else {
      _debounce(() async {_setCurrentCityName();});
    }
  }

  @override
  Widget build(BuildContext context) {
    final ThemeData theme = Theme.of(context);
    return SlidingUpPanel(
        renderPanelSheet: false,
        panel: _floatingPanel(theme),
        collapsed: _floatingCollapsed(theme),
        body: FlutterMap(
          mapController: mapController,
          options: MapOptions(
            initialZoom: 11,
            initialCenter: LatLng(51.509364, -0.128928),
            onMapReady: () {
                mapController.mapEventStream.listen((evt) {_debounce(() async {_setCurrentCityName();});});
                // And any other `MapController` dependent non-movement methods
            },

          ),
          children: [
            openStreetMapTileLayer,
          ],
        ),
    );
  }

  Widget _floatingCollapsed(ThemeData theme){
    return Container(
      decoration: BoxDecoration(
        color: theme.canvasColor,
        borderRadius: BorderRadius.only(topLeft: Radius.circular(24.0), topRight: Radius.circular(24.0)),
      ),
      
      child: Greeting(theme)
    );
  }

  Widget _floatingPanel(ThemeData theme){
    return Container(
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.all(Radius.circular(24.0)),
        boxShadow: [
          BoxShadow(
            blurRadius: 20.0,
            color: theme.shadowColor,
          ),
        ]
      ),
      child: Center(
        child: Padding(
        padding: EdgeInsets.all(8.0),
        child: SingleChildScrollView(
          child: Column(
            children: <Widget>[
              Greeting(theme),
              Text("Got a lot to do today! Here is a rundown:"),
              ...loadDestinations(),
            ],
          ),
        ),
      ),
    ),
    );
  }

  Widget Greeting (ThemeData theme) {
    return Center(
        child: Text(
            "Explore ${_currentCityName}",
          style: TextStyle(color: theme.primaryColor, fontSize: 24.0, fontWeight: FontWeight.bold),
        ),
      );
  }
}

TileLayer get openStreetMapTileLayer => TileLayer(
  urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
  userAgentPackageName: 'flutter_map',
);

// Add a pin to the map