// ignore_for_file: use_build_context_synchronously

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

import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:intl/intl.dart';
import '../../../product/services/api_services.dart';
import '../../../product/services/language_services.dart';
import '../../../product/shared/model/ward_model.dart';
import '../../../product/utils/response_status_utils.dart';

import '../../../product/shared/model/district_model.dart';
import '../../../product/shared/model/province_model.dart';
import '../device_model.dart';
import '../../../product/base/bloc/base_bloc.dart';

class DeviceUpdateBloc extends BlocBase {
  APIServices apiServices = APIServices();

  final deviceInfo = StreamController<Device>.broadcast();
  StreamSink<Device> get sinkDeviceInfo => deviceInfo.sink;
  Stream<Device> get streamDeviceInfo => deviceInfo.stream;

  // DeviceUpdateScreen
  final isChanged = StreamController<bool>.broadcast();
  StreamSink<bool> get sinkIsChanged => isChanged.sink;
  Stream<bool> get streamIsChanged => isChanged.stream;

  final provinceData = StreamController<Map<String, String>>.broadcast();
  StreamSink<Map<String, String>> get sinkProvinceData => provinceData.sink;
  Stream<Map<String, String>> get streamProvinceData => provinceData.stream;

  final listProvinces =
      StreamController<List<DropdownMenuItem<Province>>>.broadcast();
  StreamSink<List<DropdownMenuItem<Province>>> get sinkListProvinces =>
      listProvinces.sink;
  Stream<List<DropdownMenuItem<Province>>> get streamListProvinces =>
      listProvinces.stream;

  final districtData = StreamController<Map<String, String>>.broadcast();
  StreamSink<Map<String, String>> get sinkDistrictData => districtData.sink;
  Stream<Map<String, String>> get streamDistrictData => districtData.stream;

  final listDistricts =
      StreamController<List<DropdownMenuItem<District>>>.broadcast();
  StreamSink<List<DropdownMenuItem<District>>> get sinkListDistricts =>
      listDistricts.sink;
  Stream<List<DropdownMenuItem<District>>> get streamListDistricts =>
      listDistricts.stream;

  final wardData = StreamController<Map<String, String>>.broadcast();
  StreamSink<Map<String, String>> get sinkWardData => wardData.sink;
  Stream<Map<String, String>> get streamWardData => wardData.stream;

  final listWards = StreamController<List<DropdownMenuItem<Ward>>>.broadcast();
  StreamSink<List<DropdownMenuItem<Ward>>> get sinkListWards => listWards.sink;
  Stream<List<DropdownMenuItem<Ward>>> get streamListWards => listWards.stream;

  // Show Maps in DeviceUpdateScreen

  final markers = StreamController<Set<Marker>>.broadcast();
  StreamSink<Set<Marker>> get sinkMarkers => markers.sink;
  Stream<Set<Marker>> get streamMarkers => markers.stream;

  final searchLocation = StreamController<TextEditingController>.broadcast();
  StreamSink<TextEditingController> get sinkSearchLocation =>
      searchLocation.sink;
  Stream<TextEditingController> get streamSearchLocation =>
      searchLocation.stream;

  @override
  void dispose() {
    // deviceInfo.done;
  }

  Future<void> getAllProvinces() async {
    List<DropdownMenuItem<Province>> provincesData = [];
    provincesData.clear();
    sinkListProvinces.add(provincesData);
    final body = await apiServices.getAllProvinces();
    final data = jsonDecode(body);
    List<dynamic> items = data["items"];

    final provinces = Province.fromJsonDynamicList(items);
    for (var province in provinces) {
      provincesData.add(
          DropdownMenuItem(value: province, child: Text(province.fullName!)));
    }
    sinkListProvinces.add(provincesData);
  }

  Future<void> getAllDistricts(String provinceID) async {
    List<DropdownMenuItem<District>> districtsData = [];
    districtsData.clear();
    sinkListDistricts.add(districtsData);
    final body = await apiServices.getAllDistricts(provinceID);
    final data = jsonDecode(body);
    List<dynamic> items = data["items"];
    final districts = District.fromJsonDynamicList(items);
    for (var district in districts) {
      districtsData.add(
          DropdownMenuItem(value: district, child: Text(district.fullName!)));
    }
    sinkListDistricts.add(districtsData);
  }

  Future<void> getAllWards(String districtID) async {
    List<DropdownMenuItem<Ward>> wardsData = [];
    wardsData.clear();
    sinkListWards.add(wardsData);
    final body = await apiServices.getAllWards(districtID);
    final data = jsonDecode(body);
    List<dynamic> items = data["items"];
    final wards = Ward.fromJsonDynamicList(items);
    for (var ward in wards) {
      wardsData.add(DropdownMenuItem(value: ward, child: Text(ward.fullName!)));
    }
    sinkListWards.add(wardsData);
  }

  Future<void> getDeviceInfomation(
      String thingID,
      List<DropdownMenuItem<District>> districtsData,
      List<DropdownMenuItem<Ward>> wardsData,
      TextEditingController deviceNameController,
      TextEditingController latitudeController,
      TextEditingController longitudeController) async {
    String body = await apiServices.getDeviceInfomation(thingID);
    final data = jsonDecode(body);
    Device device = Device.fromJson(data);
    sinkDeviceInfo.add(device);
    deviceNameController.text = device.name ?? "";
    latitudeController.text = device.settings!.latitude ?? "";
    longitudeController.text = device.settings!.longitude ?? "";
    if (device.areaPath != "") {
      List<String> areaPath = device.areaPath!.split('_');
      String provinceCode = areaPath[0];
      String districtCode = areaPath[1];
      String wardCode = areaPath[2];
      getAllDistricts(provinceCode);
      getAllWards(districtCode);
      final provinceResponse = await apiServices.getProvinceByID(provinceCode);
      final provincesData = jsonDecode(provinceResponse);
      Province province = Province.fromJson(provincesData['data']);
      final districtResponse = await apiServices.getDistrictByID(districtCode);
      final districtData = jsonDecode(districtResponse);
      District district = District.fromJson(districtData['data']);
      final wardResponse = await apiServices.getWardByID(wardCode);
      final wardData = jsonDecode(wardResponse);
      Ward ward = Ward.fromJson(wardData['data']);
      Map<String, String> provinceData = {
        "name": province.fullName!,
        "code": province.code!
      };
      sinkProvinceData.add(provinceData);
      Map<String, String> districData = {
        "name": district.fullName!,
        "code": district.code!,
      };
      sinkDistrictData.add(districData);
      Map<String, String> wardMap = {
        "name": ward.fullName!,
        "code": ward.code!,
      };
      sinkWardData.add(wardMap);
    }
  }

  Future<Province> getProvinceByName(String name) async {
    final response = await apiServices.getProvincesByName(name);
    final data = jsonDecode(response);
    if (data != null &&
        data.containsKey('items') &&
        data['items'] != null &&
        data['items'].isNotEmpty) {
      List<dynamic> items = data['items'];
      List<Province> provinces = Province.fromJsonDynamicList(items);
      if (provinces.isNotEmpty) {
        return provinces[0];
      }
    }
    return Province(name: "null");
  }

  Future<District> getDistrictByName(String name, String provinceCode) async {
    final response = await apiServices.getDistrictsByName(name);
    if (response != "") {
      final data = jsonDecode(response);
      List<dynamic> items = data['items'];
      if (items.isNotEmpty) {
        List<District> districts = District.fromJsonDynamicList(items);
        if (districts.isNotEmpty) {
          for (var district in districts) {
            if (district.provinceCode == provinceCode) {
              return district;
            }
          }
        }
      }
    }
    return District(name: "null");
  }

  Future<Ward> getWardByName(String name, String districtCode) async {
    final response = await apiServices.getWarsdByName(name);
    final data = jsonDecode(response);
    if (data != null && data['items'] != null) {
      List<dynamic> items = data['items'];
      if (items.isNotEmpty) {
        List<Ward> wards = Ward.fromJsonDynamicList(items);
        if (wards.isNotEmpty) {
          for (var ward in wards) {
            if (ward.districtCode == districtCode) {
              return ward;
            }
          }
        }
      }
    }
    return Ward(name: "null");
  }

  Future<void> updateDevice(
    BuildContext context,
    String thingID,
    String name,
    String latitude,
    String longitude,
    String provinceCode,
    String districtCode,
    String wardCode,
  ) async {
    DateTime dateTime = DateTime.now();
    String formattedDateTime =
        DateFormat('yyyy-MM-dd HH:mm:ss').format(dateTime);
    Map<String, dynamic> body = {
      "name": name,
      "area_province": provinceCode,
      "area_district": districtCode,
      "area_ward": wardCode,
      "latitude": latitude,
      "longitude": longitude,
      "note": "User updated device infomation at $formattedDateTime",
    };
    int statusCode = await apiServices.updateOwnerDevice(thingID, body);
    showSnackBarResponseByStatusCodeNoIcon(
      context,
      statusCode,
      appLocalization(context).notification_update_device_success,
      appLocalization(context).notification_update_device_failed,
    );
  }
}
