// ignore_for_file: use_build_context_synchronously

import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:http/http.dart' as http;
import 'package:sfm_app/product/shared/model/province_model.dart';
import '../../feature/device_log/device_logs_model.dart';
import '../../feature/devices/device_model.dart';
import '../../feature/home/device_alias_model.dart';
import '../../feature/inter_family/group_detail/group_detail_model.dart';
import '../../feature/inter_family/groups/groups_model.dart';
import '../../feature/settings/device_notification_settings/device_notification_settings_model.dart';
import '../../feature/settings/profile/profile_model.dart';
import '../constant/app/api_path_constant.dart';
import '../shared/model/district_model.dart';
import '../shared/model/ward_model.dart';
import '../shared/shared_snack_bar.dart';
import '../constant/enums/app_route_enums.dart';
import 'language_services.dart';
import '../../feature/bell/bell_model.dart';
import '../cache/local_manager.dart';
import '../constant/app/app_constants.dart';
import '../constant/enums/local_keys_enums.dart';
import '../network/network_manager.dart';

class APIServices {
  Map<String, String> headers = {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
    "Access-Control-Allow-Credentials": "false",
    "Access-Control-Allow-Headers":
        "Origin,Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,locale",
    'Access-Control-Allow-Origin': "*",
    'Access-Control-Allow-Methods': 'GET, POST, OPTIONS, PUT, PATCH, DELETE',
  };

  Future<Map<String, String>> getHeaders() async {
    String? token =
        LocaleManager.instance.getStringValue(PreferencesKeys.TOKEN);
    Map<String, String> headers = {
      'Accept': 'application/json',
      'Content-Type': 'application/json',
      "Access-Control-Allow-Credentials": "false",
      "Access-Control-Allow-Headers":
          "Origin,Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,locale",
      'Access-Control-Allow-Origin': "*",
      'Access-Control-Allow-Methods': 'GET, POST, OPTIONS, PUT, PATCH, DELETE',
      'Authorization': token,
    };
    return headers;
  }

  Future<T> executeApiCall<T>(
    Future<dynamic> Function() apiCall, {
    T Function(dynamic)? parser,
    String errorMessage = 'Lỗi khi gọi API',
    T Function(int)? statusCodeHandler, // Thêm handler cho statusCode
  }) async {
    try {
      final response = await apiCall().timeout(
        Duration(seconds: ApplicationConstants.CALL_API_TIMEOUT),
        onTimeout: () => throw TimeoutException('Yêu cầu hết thời gian'),
      );

      if (statusCodeHandler != null && response is int) {
        return statusCodeHandler(response);
      }

      if (response is String && response != "") {
        if (parser != null) {
          try {
            return parser(jsonDecode(response));
          } catch (e) {
            throw Exception('Lỗi parsing dữ liệu: $e');
          }
        }
        return response as T;
      } else {
        throw Exception('Dữ liệu trả về rỗng');
      }
    } catch (e, stackTrace) {
      // log('Lỗi API: $e, StackTrace: $stackTrace');
      throw Exception('$errorMessage: $e');
    }
  }

  Future<String> login(String path, Map<String, dynamic> loginRequest) async {
    final url = Uri.https(ApplicationConstants.DOMAIN, path);
    final headers = await getHeaders();
    final response =
        await http.post(url, headers: headers, body: jsonEncode(loginRequest));
    return response.body;
  }

  Future<int> sendNotificationToken(String token) async {
    String uid = await getUID();
    Map<String, dynamic> body = {"user_id": uid, "app_token": token};
    int statusCode = await NetworkManager.instance!
        .updateDataInServer(APIPathConstants.NOTIFICATION_TOKEN_PATH, body);
    return statusCode;
  }

  Future<void> logOut(BuildContext context) async {
    showDialog(
        context: context,
        builder: (context) => AlertDialog(
              title: Text(appLocalization(context).log_out_content,
                  textAlign: TextAlign.center),
              actions: [
                TextButton(
                  onPressed: () async {
                    var url = Uri.https(ApplicationConstants.DOMAIN,
                        APIPathConstants.LOGOUT_PATH);
                    final headers = await NetworkManager.instance!.getHeaders();
                    final response = await http.post(url, headers: headers);
                    if (response.statusCode == 200) {
                      LocaleManager.instance
                          .deleteStringValue(PreferencesKeys.UID);
                      LocaleManager.instance
                          .deleteStringValue(PreferencesKeys.TOKEN);
                      LocaleManager.instance
                          .deleteStringValue(PreferencesKeys.EXP);
                      LocaleManager.instance
                          .deleteStringValue(PreferencesKeys.ROLE);
                      context.goNamed(AppRoutes.LOGIN.name);
                    } else {
                      showErrorTopSnackBarCustom(
                          context, "Error: ${response.statusCode}");
                    }
                  },
                  child: Text(appLocalization(context).log_out,
                      style: const TextStyle(color: Colors.red)),
                ),
                TextButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  child: Text(appLocalization(context).cancel_button_content),
                ),
              ],
            ));
  }

  Future<String> getUID() async {
    String uid = LocaleManager.instance.getStringValue(PreferencesKeys.UID);
    return uid;
  }

  Future<String> getUserRole() async {
    String role = LocaleManager.instance.getStringValue(PreferencesKeys.ROLE);
    return role;
  }

  Future<String> checkTheme() async {
    String theme = LocaleManager.instance.getStringValue(PreferencesKeys.THEME);
    return theme;
  }

  Future<String> checkLanguage() async {
    String language =
        LocaleManager.instance.getStringValue(PreferencesKeys.LANGUAGE_CODE);
    return language;
  }

  Future<Bell> getBellNotifications(String offset, String pageSize) async {
    final params = {"offset": offset, "page_size": pageSize};
    return executeApiCall(
      () => NetworkManager.instance!.getDataFromServerWithParams(
          APIPathConstants.BELL_NOTIFICATIONS_PATH, params),
      parser: (json) => Bell.fromJson(json),
      errorMessage: 'Lỗi khi GET /${APIPathConstants.BELL_NOTIFICATIONS_PATH}',
    );
  }

  Future<int> updateStatusOfNotification(List<String> notificationID) async {
    Map<String, dynamic> body = {
      "event_ids": notificationID,
    };
    return executeApiCall(
      () => NetworkManager.instance!.updateDataInServer(
          APIPathConstants.BELL_UPDATE_READ_NOTIFICATIONS_PATH, body),
      statusCodeHandler: (statusCode) => statusCode,
      errorMessage: 'Lỗi khi PUT /${APIPathConstants.BELL_NOTIFICATIONS_PATH}',
    );
  }

  Future<User> getUserDetail() async {
    String uid = await getUID();
    return executeApiCall(
      () => NetworkManager.instance!
          .getDataFromServer('${APIPathConstants.USER_PATH}/$uid'),
      parser: (json) => User.fromJson(json),
      errorMessage: 'Lỗi khi GET /${APIPathConstants.USER_PATH}',
    );
  }

  Future<int> updateUserProfile(Map<String, dynamic> body) async {
    String uid = await getUID();
    return executeApiCall(
      () => NetworkManager.instance!.updateDataInServer(
          "${APIPathConstants.USER_PROFILE_PATH}/$uid", body),
      statusCodeHandler: (statusCode) => statusCode,
      errorMessage: 'Lỗi khi PUT /${APIPathConstants.USER_PROFILE_PATH}',
    );
  }

  Future<int> updateUserPassword(Map<String, dynamic> body) async {
    String uid = await getUID();
    // int statusCode = await NetworkManager.instance!.updateDataInServer(
    //     "${APIPathConstants.USER_PATH}/$uid/password", body);
    return executeApiCall(
        () => NetworkManager.instance!.updateDataInServer(
            "${APIPathConstants.USER_PATH}/$uid/password", body),
        statusCodeHandler: (statusCode) => statusCode,
        errorMessage: 'Lỗi khi PUT /${APIPathConstants.USER_PATH}');
  }

  Future<List<DeviceNotificationSettings>>
      getAllSettingsNotificationOfDevices() async {
    return executeApiCall(
      () => NetworkManager.instance!
          .getDataFromServer(APIPathConstants.DEVICE_NOTIFICATION_SETTINGS),
      parser: (json) =>
          DeviceNotificationSettings.mapFromJson(json['data']).values.toList(),
      errorMessage:
          'Lỗi khi GET /${APIPathConstants.DEVICE_NOTIFICATION_SETTINGS}',
    );
  }

  Future<int> updateDeviceNotificationSettings(String thingID, Map<String, int> data) async {
    Map<String, dynamic> body = {"thing_id": thingID, "notifi_settings": data};
    return executeApiCall(
        () => NetworkManager.instance!.updateDataInServer(
            APIPathConstants.DEVICE_NOTIFICATION_SETTINGS, body),
        statusCodeHandler: (statusCode) => statusCode,
        errorMessage:
            'Lỗi khi PUT /${APIPathConstants.DEVICE_NOTIFICATION_SETTINGS}');
  }

  Future<List<DeviceWithAlias>> getDashBoardDevices() async {
    return executeApiCall(
      () => NetworkManager.instance!
          .getDataFromServer(APIPathConstants.DASHBOARD_DEVICES),
      parser: (json) => DeviceWithAlias.fromJsonDynamicList(json['items']),
      errorMessage: 'Lỗi khi GET /${APIPathConstants.DASHBOARD_DEVICES}',
    );
  }

  Future<int> setupDeviceNotification(String thingID, String deviceName) async {
    Map<String, dynamic> body = {
      "thing_id": thingID,
      "alias": deviceName,
      "notifi_settings": {
        "001": 1,
        "002": 1,
        "003": 1,
        "004": 1,
        "005": 1,
        "006": 1,
        "101": 1,
        "102": 1,
        "103": 1,
        "104": 1,
      }
    };
    return executeApiCall(
        () => NetworkManager.instance!.updateDataInServer(
            APIPathConstants.DEVICE_NOTIFICATION_SETTINGS, body),
        statusCodeHandler: (statusCode) => statusCode,
        errorMessage:
            'Lỗi khi PUT /${APIPathConstants.DEVICE_NOTIFICATION_SETTINGS}');
  }

  Future<List<Province>> getAllProvinces() async {
    return executeApiCall(
        () => NetworkManager.instance!
            .getDataFromServer(APIPathConstants.PROVINCES_PATH),
        parser: (json) => Province.fromJsonDynamicList(json['items']),
        errorMessage: 'Lỗi khi GET /${APIPathConstants.PROVINCES_PATH}');
    ;
  }

  Future<List<Province>> getProvincesByName(String name) async {
    final params = {'name': name};
    return executeApiCall(
      () => NetworkManager.instance!
          .getDataFromServerWithParams(APIPathConstants.PROVINCES_PATH, params),
      parser: (json) => Province.fromJsonDynamicList(json['items']),
      errorMessage: 'Lỗi khi GET /${APIPathConstants.PROVINCES_PATH}/$name',
    );
    ;
  }

  Future<Province> getProvinceByID(String provinceID) async {
    return executeApiCall(
      () => NetworkManager.instance!
          .getDataFromServer("${APIPathConstants.PROVINCES_PATH}/$provinceID"),
      parser: (json) => Province.fromJson(json['data']),
      errorMessage:
          'Lỗi khi GET /${APIPathConstants.PROVINCES_PATH}/$provinceID}',
    );
  }

  Future<List<District>> getAllDistricts(String provinceID) async {
    final params = {"parent": provinceID};
    return executeApiCall(
      () => NetworkManager.instance!
          .getDataFromServerWithParams(APIPathConstants.DISTRICTS_PATH, params),
      parser: (json) => District.fromJsonDynamicList(json['items']),
      errorMessage:
          'Lỗi khi GET /${APIPathConstants.DISTRICTS_PATH} by parentCode $provinceID',
    );
  }

  Future<List<District>> getDistrictsByName(String districtName) async {
    final params = {"name": districtName};
    return executeApiCall(
      () => NetworkManager.instance!
          .getDataFromServerWithParams(APIPathConstants.DISTRICTS_PATH, params),
      parser: (json) => District.fromJsonDynamicList(json['items']),
      errorMessage:
          'Lỗi khi GET /${APIPathConstants.DISTRICTS_PATH} by name $districtName',
    );
  }

  Future<District> getDistrictByID(String districtID) async {
    return executeApiCall(
      () => NetworkManager.instance!
          .getDataFromServer("${APIPathConstants.DISTRICTS_PATH}/$districtID"),
      parser: (json) => District.fromJson(json['data']),
      errorMessage:
          'Lỗi khi GET /${APIPathConstants.DISTRICTS_PATH}/$districtID',
    );
  }

  Future<List<Ward>> getAllWards(String districtID) async {
    final params = {'parent': districtID};
    return executeApiCall(
      () => NetworkManager.instance!
          .getDataFromServerWithParams(APIPathConstants.WARDS_PATH, params),
      parser: (json) => Ward.fromJsonDynamicList(json['items']),
      errorMessage:
          'Lỗi khi GET /${APIPathConstants.WARDS_PATH} by parent $districtID',
    );
  }

  Future<List<Ward>> getWardsByName(String wardName) async {
    final params = {"name": wardName};
    return executeApiCall(
      () => NetworkManager.instance!
          .getDataFromServerWithParams(APIPathConstants.WARDS_PATH, params),
      parser: (json) => Ward.fromJsonDynamicList(json['items']),
      errorMessage:
          'Lỗi khi GET /${APIPathConstants.WARDS_PATH} by name $wardName',
    );
  }

  Future<Ward> getWardByID(String wardID) async {
    return executeApiCall(
      () => NetworkManager.instance!
          .getDataFromServer("${APIPathConstants.WARDS_PATH}/$wardID"),
      parser: (json) => Ward.fromJson(json['data']),
      errorMessage: 'Lỗi khi GET /${APIPathConstants.WARDS_PATH}/$wardID',
    );
  }

  Future<int> confirmFakeFireByUser(String thingID) async {
    Map<String, dynamic> body = {
      "state": 3,
      "note": "Người dùng xác nhận cháy giả!"
    };
    return executeApiCall(
        () => NetworkManager.instance!.updateDataInServer(
            "${APIPathConstants.DEVICE_PATH}/$thingID", body),
        statusCodeHandler: (statusCode) => statusCode,
        errorMessage: 'Lỗi khi PUT /${APIPathConstants.DEVICE_PATH}/$thingID');
  }

  Future<List<Device>> getOwnerDevices() async {
    return executeApiCall(
      () => NetworkManager.instance!
          .getDataFromServer(APIPathConstants.DEVICE_PATH),
      parser: (json) => Device.fromJsonDynamicList(json['items']),
      errorMessage: 'Lỗi khi GET /${APIPathConstants.DEVICE_PATH}',
    );
  }

  Future<List<Device>> getOwnerDeviceByState(
      Map<String, dynamic> params) async {
    return executeApiCall(
      () => NetworkManager.instance!
          .getDataFromServerWithParams(APIPathConstants.DEVICE_PATH, params),
      parser: (json) => Device.fromJsonDynamicList(json['items']),
      errorMessage: 'Lỗi khi GET /${APIPathConstants.DEVICE_PATH}',
    );
  }

  Future<int> createDeviceByAdmin(Map<String, dynamic> body) async {
    return executeApiCall(
        () => NetworkManager.instance!
            .createDataInServer(APIPathConstants.DEVICE_PATH, body),
        statusCodeHandler: (statusCode) => statusCode,
        errorMessage: 'Lỗi khi POST /${APIPathConstants.DEVICE_PATH}');
  }

  Future<int> registerDevice(Map<String, dynamic> body) async {
    return executeApiCall(
        () => NetworkManager.instance!
            .createDataInServer(APIPathConstants.DEVICE_REGISTER_PATH, body),
        statusCodeHandler: (statusCode) => statusCode,
        errorMessage: 'Lỗi khi POST /${APIPathConstants.DEVICE_REGISTER_PATH}');
  }

  Future<int> deleteDeviceByAdmin(String thingID) async {
    return executeApiCall(
        () => NetworkManager.instance!
            .deleteDataInServer("${APIPathConstants.DEVICE_PATH}/$thingID"),
        statusCodeHandler: (statusCode) => statusCode,
        errorMessage:
            'Lỗi khi DELETE /${APIPathConstants.DEVICE_PATH}/$thingID');
  }

  Future<int> unregisterDevice(Map<String, dynamic> body) async {
    return executeApiCall(
        () => NetworkManager.instance!
            .createDataInServer(APIPathConstants.DEVICE_UNREGISTER_PATH, body),
        statusCodeHandler: (statusCode) => statusCode,
        errorMessage:
            'Lỗi khi DELETE /${APIPathConstants.DEVICE_UNREGISTER_PATH} by USER');
  }

  Future<Device> getDeviceInformation(String thingID) async {
    return executeApiCall(
      () => NetworkManager.instance!
          .getDataFromServer("${APIPathConstants.DEVICE_PATH}/$thingID"),
      parser: (json) => Device.fromJson(json),
      errorMessage: 'Lỗi khi GET /${APIPathConstants.DEVICE_PATH}/$thingID',
    );
  }

  Future<List<Group>> getAllGroups() async {
    return executeApiCall(
      () => NetworkManager.instance!
          .getDataFromServer(APIPathConstants.ALL_GROUPS_PATH),
      parser: (json) => Group.fromJsonDynamicList(json['items']),
      errorMessage: 'Lỗi khi GET /${APIPathConstants.USER_PATH}',
    );
  }

  Future<int> createGroup(Map<String, dynamic> body) async {
    return executeApiCall(
        () => NetworkManager.instance!
            .createDataInServer(APIPathConstants.GROUPS_PATH, body),
        statusCodeHandler: (statusCode) => statusCode,
        errorMessage: 'Lỗi khi POST /${APIPathConstants.GROUPS_PATH}');
  }

  Future<int> updateGroup(Map<String, dynamic> body, String groupID) async {
    return executeApiCall(
        () => NetworkManager.instance!.updateDataInServer(
            "${APIPathConstants.GROUPS_PATH}/$groupID", body),
        statusCodeHandler: (statusCode) => statusCode,
        errorMessage: 'Lỗi khi PUT /${APIPathConstants.GROUPS_PATH}/$groupID');
  }

  Future<int> joinGroup(String groupID, Map<String, dynamic> body) async {
    return executeApiCall(
        () => NetworkManager.instance!
            .createDataInServer(APIPathConstants.JOIN_GROUP_PATH, body),
        statusCodeHandler: (statusCode) => statusCode,
        errorMessage: 'Lỗi khi POST /${APIPathConstants.JOIN_GROUP_PATH}');
  }

  Future<int> deleteGroup(String groupID) async {
    return executeApiCall(
        () => NetworkManager.instance!
            .deleteDataInServer("${APIPathConstants.GROUPS_PATH}/$groupID"),
        statusCodeHandler: (statusCode) => statusCode,
        errorMessage:
            'Lỗi khi DELETE /${APIPathConstants.GROUPS_PATH}/$groupID');
  }

  Future<GroupDetail> getGroupDetail(String groupID) async {
    return executeApiCall(
      () => NetworkManager.instance!
          .getDataFromServer("${APIPathConstants.GROUPS_PATH}/$groupID"),
      parser: (json) => GroupDetail.fromJson(json),
      errorMessage: 'Lỗi khi GET /${APIPathConstants.GROUPS_PATH}/$groupID',
    );
  }

  Future<int> approveGroup(Map<String, dynamic> body) async {
    return executeApiCall(
        () => NetworkManager.instance!
            .createDataInServer(APIPathConstants.APPROVE_GROUP_PATH, body),
        statusCodeHandler: (statusCode) => statusCode,
        errorMessage: 'Lỗi khi POST /${APIPathConstants.APPROVE_GROUP_PATH}');
  }

  Future<int> deleteUserInGroup(String groupID, String userID) async {
    return executeApiCall(
        () => NetworkManager.instance!.deleteDataInServer(
            "${APIPathConstants.GROUPS_PATH}/$groupID/users/$userID"),
        statusCodeHandler: (statusCode) => statusCode,
        errorMessage:
            'Lỗi khi DELETE /${APIPathConstants.GROUPS_PATH}/$groupID/users/$userID');
  }

  Future<int> deleteDeviceInGroup(String groupID, String thingID) async {
    return executeApiCall(
        () => NetworkManager.instance!.deleteDataInServer(
            "${APIPathConstants.GROUPS_PATH}/$groupID/devices/$thingID"),
        statusCodeHandler: (statusCode) => statusCode,
        errorMessage:
            'Lỗi khi DELETE /${APIPathConstants.GROUPS_PATH}/$groupID/devices/$thingID');
  }

  Future<int> updateDeviceAlias(Map<String, dynamic> body) async {
    return executeApiCall(
        () => NetworkManager.instance!.updateDataInServer(
            APIPathConstants.DEVICE_NOTIFICATION_SETTINGS, body),
        statusCodeHandler: (statusCode) => statusCode,
        errorMessage:
            'Lỗi khi PUT /${APIPathConstants.DEVICE_NOTIFICATION_SETTINGS}');
  }

  Future<int> addDeviceToGroup(
      String groupID, Map<String, dynamic> body) async {
    return executeApiCall(
        () => NetworkManager.instance!.createDataInServer(
            "${APIPathConstants.GROUPS_PATH}/$groupID/things", body),
        statusCodeHandler: (statusCode) => statusCode,
        errorMessage:
            'Lỗi khi PUT /${APIPathConstants.GROUPS_PATH}/$groupID/things');
  }

  Future<int> updateOwnerDevice(
      String thingID, Map<String, dynamic> body) async {
    return executeApiCall(
        () => NetworkManager.instance!.updateDataInServer(
            "${APIPathConstants.DEVICE_PATH}/$thingID", body),
        statusCodeHandler: (statusCode) => statusCode,
        errorMessage: 'Lỗi khi PUT /${APIPathConstants.DEVICE_PATH}/$thingID');
  }

  Future<DeviceLog> getLogsOfDevice(
      String thingID, Map<String, dynamic> params) async {
    return executeApiCall(
      () => NetworkManager.instance!.getDataFromServerWithParams(
          APIPathConstants.DEVICE_LOGS_PATH, params),
      parser: (json) => DeviceLog.fromJson(json),
      errorMessage: 'Lỗi khi GET /${APIPathConstants.DEVICE_LOGS_PATH}',
    );
  }
}
