import 'dart:async';
import 'dart:convert';
import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_cluster_manager/google_maps_cluster_manager.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:sfm_app/feature/devices/device_model.dart';
import 'package:sfm_app/feature/map/map_bloc.dart';
import 'package:sfm_app/feature/map/widget/on_tap_marker_widget.dart';
import 'package:sfm_app/product/base/bloc/base_bloc.dart';
import 'package:sfm_app/product/constant/icon/icon_constants.dart';
import 'package:sfm_app/product/permission/location_permission.dart';
import 'package:sfm_app/product/services/api_services.dart';

class MapScreen extends StatefulWidget {
  const MapScreen({super.key});

  @override
  State<MapScreen> createState() => _MapScreenState();
}

class _MapScreenState extends State<MapScreen> with WidgetsBindingObserver {
  late BitmapDescriptor normalIcon;
  late BitmapDescriptor offlineIcon;
  late BitmapDescriptor abnormalIcon;
  late BitmapDescriptor flameIcon;
  late BitmapDescriptor hospitalIcon;
  late BitmapDescriptor fireStationIcon;
  late MapBloc mapBloc;
  late ClusterManager clusterManager;
  MapType mapType = MapType.terrain;
  APIServices apiServices = APIServices();
  final streamController = StreamController<GoogleMapController>.broadcast();
  List<Device> devices = [];
  Completer<GoogleMapController> _controller = Completer();
  List<String> imageAssets = [
    IconConstants.instance.getIcon("normal_icon"),
    IconConstants.instance.getIcon("offline_icon"),
    IconConstants.instance.getIcon("flame_icon"),
    IconConstants.instance.getIcon("hospital_marker"),
    IconConstants.instance.getIcon("fire_station_marker"),
  ];
  static const CameraPosition _myPosition = CameraPosition(
    target: LatLng(20.976108, 105.791666),
    zoom: 12,
  );
  Set<Marker> markersAll = {};
  List<Marker> markers = [];
  LatLng myLocation = const LatLng(213761, 123123);
  Position? position;
  bool isAllowLocationPermission = false;
  @override
  void initState() {
    super.initState();
    mapBloc = BlocProvider.of(context);
    _loadIcons();
    getAllMarkers();
    clusterManager = _initClusterManager();
  }

  @override
  void dispose() {
    streamController.close();
    _controller = Completer();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          StreamBuilder<Set<Marker>>(
            stream: mapBloc.streamAllMarker,
            builder: (context, markerSnapshot) {
              return StreamBuilder<List<LatLng>>(
                stream: mapBloc.streamPolylines,
                builder: (context, polylinesSnapshot) {
                  return GoogleMap(
                    initialCameraPosition: _myPosition,
                    mapType: mapType,
                    onMapCreated: (GoogleMapController controller) {
                      if (!_controller.isCompleted) {
                        _controller.complete(controller);
                      }
                      streamController.sink.add(controller);
                      clusterManager.setMapId(controller.mapId);
                    },
                    markers: markerSnapshot.data ?? markersAll
                      ..addAll(markers),
                    zoomControlsEnabled: true,
                    myLocationEnabled: true,
                    mapToolbarEnabled: false,
                    onCameraMove: (position) {
                      clusterManager.onCameraMove(position);
                    },
                    onCameraIdle: () {
                      clusterManager.updateMap();
                    },
                    polylines: {
                      Polyline(
                        polylineId: const PolylineId('router'),
                        points: polylinesSnapshot.data ?? [],
                        color: Colors.deepPurpleAccent,
                        width: 8,
                      ),
                    },
                  );
                },
              );
            },
          ),
        ],
      ),
    );
  }

  Future<void> _loadIcons() async {
    List<Future<BitmapDescriptor>> iconFutures = imageAssets.map((asset) {
      return BitmapDescriptor.fromAssetImage(const ImageConfiguration(), asset);
    }).toList();

    List<BitmapDescriptor> icons = await Future.wait(iconFutures);

    normalIcon = icons[0];
    offlineIcon = icons[1];
    flameIcon = icons[2];
    hospitalIcon = icons[3];
    fireStationIcon = icons[4];
  }

  ClusterManager _initClusterManager() {
    return ClusterManager<Device>(
      devices,
      _updateMarkers,
      markerBuilder: _getmarkerBuilder(),
    );
  }

  Future<Marker> Function(Cluster<Device>) _getmarkerBuilder() =>
      (cluster) async {
        return Marker(
          markerId: MarkerId(
            cluster.getId(),
          ),
          position: cluster.location,
          onTap: () async {
            bool check = await checkLocationPermission(context);
            if (check == true) {
              Position position = await Geolocator.getCurrentPosition();
              // ignore: use_build_context_synchronously
              onTapMarker(
                context,
                _controller,
                mapBloc,
                LatLng(position.latitude, position.longitude),
                cluster.items,
                imageAssets,
                markers,
                hospitalIcon,
                fireStationIcon,
              );
            } else {
              // ignore: use_build_context_synchronously
              ScaffoldMessenger.of(context).showSnackBar(
                  const SnackBar(content: Text("Cannot get your Location")));
            }
          },
          icon: getMarkerIcon(cluster),
        );
      };

  BitmapDescriptor getMarkerIcon(Cluster<Device> cluster) {
    if (cluster.items.length == 1) {
      Device item = cluster.items.first;
      if (item.state == 0) {
        return normalIcon;
      } else if (item.state == 1) {
        return flameIcon;
      } else {
        return offlineIcon;
      }
    }
    bool hasStateOne = false;
    bool hasOtherState = false;

    for (var item in cluster.items) {
      if (item.state == 1) {
        hasStateOne = true;
        break;
      } else if (item.state != 0) {
        hasOtherState = true;
      }
    }

    // log("Has state = 1: $hasStateOne, Has other state: $hasOtherState");

    if (hasStateOne) {
      return flameIcon; // flameIcon
    } else if (hasOtherState) {
      return normalIcon; // normalIcon
    } else {
      return offlineIcon; // offlineIcon
    }
  }

  bool checkStateMarker(Cluster<Device> cluster) {
    bool hasStateOne = false;
    bool hasOtherState = false;

    for (var item in cluster.items) {
      if (item.state == 1) {
        hasStateOne = true;
        break;
      } else if (item.state != 0) {
        hasOtherState = true;
      }
    }

    // log("Has state = 1: $hasStateOne, Has other state: $hasOtherState");

    if (hasStateOne) {
      return true; // flameIcon
    } else if (hasOtherState) {
      return false; // normalIcon
    } else {
      return true; // offlineIcon
    }
  }

  void _updateMarkers(Set<Marker> marker) {
    log("Update Marker");
    markersAll = marker;
    mapBloc.sinkAllMarker.add(marker);
  }

  void getAllMarkers() async {
    String response = await apiServices.getOwnerDevices();
    if (response != "") {
      final data = jsonDecode(response);
      List<dynamic> result = data['items'];
      final devicesList = Device.fromJsonDynamicList(result);
      for (var device in devicesList) {
        devices.add(device);
      }
    }
  }

  Future<bool> checkLocationPermission(context) async {
    bool check = await LocationPermissionRequest.instance
        .checkLocationPermission(context);
    return check;
  }
}
