import 'dart:async';

import 'package:diplomaticquarterapp/config/config.dart';
import 'package:diplomaticquarterapp/core/model/pharmacies/order_detail.dart';
import 'package:diplomaticquarterapp/core/model/pharmacies/order_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_polyline_points/flutter_polyline_points.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:location/location.dart';


class TrackDriver extends StatefulWidget {
  final OrderDetailModel order;
  TrackDriver({this.order});

  @override
  State<TrackDriver> createState() => _TrackDriverState();
}

class _TrackDriverState extends State<TrackDriver> {
  OrderDetailModel _order;

  Completer<GoogleMapController> _controller = Completer();


  double CAMERA_ZOOM = 16;
  double CAMERA_TILT = 0;
  double CAMERA_BEARING = 30;
  LatLng SOURCE_LOCATION = null;
  LatLng DEST_LOCATION = null;

  // for my drawn routes on the map
  Set<Polyline> _polylines = Set<Polyline>();
  List<LatLng> polylineCoordinates = [];
  PolylinePoints polylinePoints;

  Set<Marker> _markers = Set<Marker>();

  BitmapDescriptor sourceIcon; // for my custom marker pins
  BitmapDescriptor destinationIcon; // for my custom marker pins
  Location location;// wrapper around the location API

  @override
  void initState() {
    _order = widget.order;
    DEST_LOCATION = _order.shippingAddress.getLocation();
    location = new Location();
    polylinePoints = PolylinePoints();
    setSourceAndDestinationIcons();
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: GoogleMap(
        myLocationEnabled: true,
        compassEnabled: true,
        markers:  _markers,
        polylines: _polylines,
        mapType: MapType.normal,
        initialCameraPosition: _orderDeliveryLocationCamera(),
        onMapCreated: (GoogleMapController controller) {
          _controller.complete(controller);
          showPinsOnMap();
        },
      ),
      floatingActionButton: FloatingActionButton.extended(
        onPressed: _goToDriver,
        label: Text('To the lake!'),
        icon: Icon(Icons.directions_boat),
      ),
    );
  }


  void setSourceAndDestinationIcons() async {
    sourceIcon = await BitmapDescriptor.fromAssetImage(
        ImageConfiguration(devicePixelRatio: 2.5),
        'assets/images/map_markers/source_map_marker.png');

    destinationIcon = await BitmapDescriptor.fromAssetImage(
        ImageConfiguration(devicePixelRatio: 2.5),
        'assets/images/map_markers/destination_map_marker.png');
  }

  CameraPosition _orderDeliveryLocationCamera(){

    final CameraPosition orderDeliveryLocCamera = CameraPosition(
        bearing: CAMERA_BEARING,
        target: DEST_LOCATION,
        tilt: CAMERA_TILT,
        zoom: CAMERA_ZOOM);
    return orderDeliveryLocCamera;
  }

  CameraPosition _driverLocationCamera(){
    final CameraPosition driverLocCamera = CameraPosition(
        bearing: CAMERA_BEARING,
        target: SOURCE_LOCATION,
        tilt: CAMERA_TILT,
        zoom: CAMERA_ZOOM);
    return driverLocCamera;
  }


  Future<void> _goToOrderDeliveryLocation() async {
    final GoogleMapController controller = await _controller.future;
    final CameraPosition orderDeliveryLocCamera = _orderDeliveryLocationCamera();
    controller.animateCamera(CameraUpdate.newCameraPosition(orderDeliveryLocCamera));
  }

  Future<void> _goToDriver() async {
    final GoogleMapController controller = await _controller.future;
    final CameraPosition driverLocCamera = _driverLocationCamera();
    controller.animateCamera(CameraUpdate.newCameraPosition(driverLocCamera));
  }


  Future<void> _fitCameraBetweenBothPoints() async {
    final GoogleMapController controller = await _controller.future;
    final CameraPosition driverLocCamera = CameraPosition(
        bearing: CAMERA_BEARING,
        target: SOURCE_LOCATION,
        tilt: CAMERA_TILT,
        zoom: CAMERA_ZOOM);
    controller.animateCamera(CameraUpdate.newCameraPosition(driverLocCamera));
  }

  void showPinsOnMap() {
    // source pin
    if(SOURCE_LOCATION != null){
      setState(() {
        var pinPosition = SOURCE_LOCATION;
        _markers.add(Marker(
            markerId: MarkerId('sourcePin'),
            position: pinPosition,
            icon: sourceIcon
        ));
      });
    }

    // destination pin
    if(DEST_LOCATION != null){
      setState(() {
        var destPosition = DEST_LOCATION;
        _markers.add(Marker(
            markerId: MarkerId('destPin'),
            position: destPosition,
            icon: destinationIcon
        ));
      });
    }
    // set the route lines on the map from source to destination
    // for more info follow this tutorial
    // drawRoute();
  }

  void updatePinOnMap() async {
    // create a new CameraPosition instance
    // every time the location changes, so the camera
    // follows the pin as it moves with an animation
    CameraPosition cPosition = CameraPosition(
      zoom: CAMERA_ZOOM,
      tilt: CAMERA_TILT,
      bearing: CAMERA_BEARING,
      target: SOURCE_LOCATION,
    );
    final GoogleMapController controller = await _controller.future;
    controller.animateCamera(CameraUpdate.newCameraPosition(cPosition));
    // do this inside the setState() so Flutter gets notified
    // that a widget update is due
    setState(() {
      // updated position
      var pinPosition = SOURCE_LOCATION;

      // the trick is to remove the marker (by id)
      // and add it again at the updated location
      _markers.removeWhere((m) => m.markerId.value == 'sourcePin');
      _markers.add(Marker(
          markerId: MarkerId('sourcePin'),
          position: pinPosition, // updated position
          icon: sourceIcon
      ));
    });
  }

  void drawRoute() async {
    return; // Ignore draw Route
    
    List<PointLatLng> result = await polylinePoints.getRouteBetweenCoordinates(
        GOOGLE_API_KEY,
        SOURCE_LOCATION.latitude,
        SOURCE_LOCATION.longitude,
        DEST_LOCATION.latitude,
        DEST_LOCATION.longitude);
    if(result.isNotEmpty){
      result.forEach((PointLatLng point){
        polylineCoordinates.add(
            LatLng(point.latitude,point.longitude)
        );
      });
      setState(() {
        _polylines.add(Polyline(
            width: 5, // set the width of the polylines
            polylineId: PolylineId('poly'),
            color: Color.fromARGB(255, 40, 122, 198),
            points: polylineCoordinates
        ));
      });
    }
  }
}