// 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/shared/shared_snack_bar.dart';
import '../product/utils/response_status_utils.dart';

import '../product/shared/model/district_model.dart';
import '../product/shared/model/province_model.dart';
import '../feature/devices/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(BuildContext context) async {
    List<DropdownMenuItem<Province>> provincesData = [];
    provincesData.clear();
    sinkListProvinces.add(provincesData);
    try {
      List<Province> provinces =  await apiServices.getAllProvinces();
      for (var province in provinces) {
        provincesData.add(
            DropdownMenuItem(value: province, child: Text(province.fullName!)));
      }
      sinkListProvinces.add(provincesData);
    } catch (e) {
      if (!context.mounted) return;
      showErrorTopSnackBarCustom(
          context, e.toString());
    }

  }

  Future<void> getAllDistricts(BuildContext context, String provinceID) async {
    List<DropdownMenuItem<District>> districtsData = [];
    districtsData.clear();
    sinkListDistricts.add(districtsData);
    try {
      final districts = await apiServices.getAllDistricts(provinceID);
      for (var district in districts) {
        districtsData.add(
            DropdownMenuItem(value: district, child: Text(district.fullName!)));
      }
      sinkListDistricts.add(districtsData);
    } catch (e) {
      if (!context.mounted) return;
      showErrorTopSnackBarCustom(
          context, e.toString());
    }

  }

  Future<void> getAllWards(BuildContext context, String districtID) async {
    List<DropdownMenuItem<Ward>> wardsData = [];
    wardsData.clear();
    sinkListWards.add(wardsData);
    try {
      final wards = await apiServices.getAllWards(districtID);
      for (var ward in wards) {
        wardsData.add(DropdownMenuItem(value: ward, child: Text(ward.fullName!)));
      }
      sinkListWards.add(wardsData);
    } catch (e) {
      if (!context.mounted) return;
      showErrorTopSnackBarCustom(
          context, e.toString());
    }

  }

  Future<void> getDeviceInformation(
      BuildContext context,
      String thingID,
      TextEditingController deviceNameController,
      TextEditingController latitudeController,
      TextEditingController longitudeController) async {
    try {
      Device device = await apiServices.getDeviceInformation(thingID);
      sinkDeviceInfo.add(device);
      deviceNameController.text = device.name ?? "";
      latitudeController.text = device.settings!.latitude ?? "";
      longitudeController.text = device.settings!.longitude ?? "";

      if (device.areaPath != null && device.areaPath!.isNotEmpty) {
        List<String> areaPath = device.areaPath!.split('_');

        // Kiểm tra độ dài của areaPath
        if (areaPath.length >= 3) {
          String provinceCode = areaPath[0];
          String districtCode = areaPath[1];
          String wardCode = areaPath[2];

          // Kiểm tra các mã có hợp lệ không (không rỗng)
          if (provinceCode.isNotEmpty && districtCode.isNotEmpty && wardCode.isNotEmpty) {
            try {
              // Lấy danh sách districts và wards
              await getAllDistricts(context,provinceCode);
              await getAllWards(context,districtCode);

              // Xử lý Province
              try {
                  Province province = await apiServices.getProvinceByID(provinceCode);
                  Map<String, String> provinceData = {
                    "name": province.fullName ?? "Unknown Province",
                    "code": province.code ?? provinceCode
                  };
                  sinkProvinceData.add(provinceData);

              } catch (e) {

                // Thêm dữ liệu mặc định khi lỗi
                Map<String, String> provinceData = {
                  "name": "Error Loading Province",
                  "code": provinceCode
                };
                sinkProvinceData.add(provinceData);
                if (!context.mounted) return;
                showErrorTopSnackBarCustom(
                    context, e.toString());
              }

              // Xử lý District
              try {
                  District district = await apiServices.getDistrictByID(districtCode);
                  Map<String, String> districData = {
                    "name": district.fullName ?? "Unknown District",
                    "code": district.code ?? districtCode,
                  };
                  sinkDistrictData.add(districData);
              } catch (e) {
                print("Lỗi khi lấy thông tin district ($districtCode): $e");
                Map<String, String> districData = {
                  "name": "Error Loading District",
                  "code": districtCode,
                };
                sinkDistrictData.add(districData);
              }

              // Xử lý Ward
              try {
                  Ward ward = await apiServices.getWardByID(wardCode);
                  Map<String, String> wardMap = {
                    "name": ward.fullName ?? "Unknown Ward",
                    "code": ward.code ?? wardCode,
                  };
                  sinkWardData.add(wardMap);
              } catch (e) {
                print("Lỗi khi lấy thông tin ward ($wardCode): $e");
                Map<String, String> wardMap = {
                  "name": "Error Loading Ward",
                  "code": wardCode,
                };
                sinkWardData.add(wardMap);
              }

            } catch (e) {
              print("Lỗi khi gọi getAllDistricts hoặc getAllWards: $e");
            }
          } else {
            await getAllProvinces(context);
            print("Một hoặc nhiều mã địa phương trống: Province: $provinceCode, District: $districtCode, Ward: $wardCode");
          }
        } else {
          showNoIconTopSnackBar(context,"AreaPath không đủ thông tin: ${device.areaPath}",Colors.orangeAccent, Colors.white);
        }
      }
    } catch (e) {
      showNoIconTopSnackBar(context,"Lỗi trong getDeviceInfomation: $e",Colors.orangeAccent, Colors.white);
    }
  }

  Future<Province> getProvinceByName(BuildContext context, String name) async {
    try {
      List<Province> provinces = await apiServices.getProvincesByName(name);
      if (provinces.isNotEmpty) {
        return provinces[0];
      } else {
        return Province(name: "null");
      }
    } catch (e) {
      if (context.mounted) {
        showErrorTopSnackBarCustom(context, e.toString());
      }
      return Province(name: "null");
    }
  }


  Future<District> getDistrictByName(
      BuildContext context, String name, String provinceCode) async {
    try {
      final districts = await apiServices.getDistrictsByName(name);
      return districts.firstWhere(
            (district) => district.provinceCode == provinceCode,
        orElse: () => District(name: "null"),
      );
    } catch (e) {
      if (context.mounted) {
        showErrorTopSnackBarCustom(context, e.toString());
      }
      return District(name: "null");
    }
  }

  Future<Ward> getWardByName(
      BuildContext context, String name, String districtCode) async {
    try {
      final wards = await apiServices.getWardsByName(name);
      return wards.firstWhere(
            (ward) => ward.districtCode == districtCode,
        orElse: () => Ward(name: "null"),
      );
    } catch (e) {
      if (context.mounted) {
        showErrorTopSnackBarCustom(context, e.toString());
      }
      return Ward(name: "null");
    }
  }

  Future<void> updateDevice(
    BuildContext context,
    String thingID,
    String name,
    String latitude,
    String longitude,
    String provinceCode,
    String districtCode,
    String wardCode,
  ) async {
    try {
      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,
      );
    } catch (e) {
      if (!context.mounted) return;
      showErrorTopSnackBarCustom(
          context, e.toString());
    }

  }
}
