import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:http/http.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/models/lookup.dart';
import 'package:test_sa/models/service_request/pending_service_request_model.dart';
import 'package:test_sa/models/service_request/service_report.dart';
import 'package:test_sa/models/service_request/service_request.dart';
import 'package:test_sa/models/service_request/service_request_search.dart';
import 'package:test_sa/models/service_request/spare_parts.dart';
import 'package:test_sa/models/service_request/supp_engineer_work_orders.dart';
import 'package:test_sa/models/service_request/supplier_engineer_model.dart';
import 'package:test_sa/models/timer_model.dart';

import '../../../models/service_request/search_work_order.dart';
import '../../../models/service_request/wo_call_request.dart';
import '../../../models/user.dart';
import '../../../new_views/common_widgets/app_lazy_loading.dart';

class ServiceRequestsProvider extends ChangeNotifier {
  // number of items call in each request
  final pageItemNumber = 10;

  //reset provider data
  void reset() {
    workOrders = [];
    serviceRequests = null;
    nextPage = true;
    stateCode = null;
  }

  // state code of current request to defied error message
  // like 400 customer request failed
  // 500 service not available
  int? stateCode;
  bool _isDetialLoading = false;

  bool get isDetialLoading => _isDetialLoading;

  set isDetialLoading(bool value) {
    _isDetialLoading = value;
    notifyListeners();
  } // true if there is next page in product list and false if not

  bool nextPage = true;
  TimeOfDay? _selectedTime;

  TimeOfDay? get selectedTime => _selectedTime;

  set selectedTime(TimeOfDay? value) {
    _selectedTime = value;
    notifyListeners();
  } // list of user requests

  List<ServiceRequest>? serviceRequests;
  List<SearchWorkOrder> workOrders = [];
  List<SparePartsWorkOrders> _sparePartList = [];

  SparePartsWorkOrders _initialSelectedSparePart = SparePartsWorkOrders();
  int _selectedListIndex = 0;

  int get selectedListIndex => _selectedListIndex;

  set selectedListIndex(int value) {
    _selectedListIndex = value;
    notifyListeners();
  }

  ServiceRequest? currentSelectedRequest;

  void updateCurrentSelectedRequest(ServiceRequest? value) {
    currentSelectedRequest = value;
    notifyListeners();
  }

  // when requests in-process _loading = true
  // done _loading = true
  // failed _loading = false
  bool isLoading = false;

  ServiceRequestSearch search = ServiceRequestSearch();

  /// return -2 if request in progress
  /// return -1 if error happen when sending request
  /// return state code if request complete may be 200, 404 or 403
  /// for more details check http state manager
  /// lib\controllers\http_status_manger\http_status_manger.dart
  Future<int> getRequests({required int hospitalId}) async {
    if (isLoading == true) return -2;
    isLoading = true;
    if (serviceRequests?.isEmpty ?? false) notifyListeners();
    Response response;
    try {
      Map<String, dynamic> body = {};
      body.addAll(search.toMap());
      body["pageNumber"] = (serviceRequests?.length ?? 0) ~/ pageItemNumber + 1;
      body["pageSize"] = pageItemNumber;

      response = await ApiManager.instance.post(
        URLs.getServiceRequests,
        body: body,
      );

      stateCode = response.statusCode;
      if (response.statusCode >= 200 && response.statusCode < 300) {
        // client's request was successfully received
        List requestsListJson = json.decode(response.body)["data"];
        List<ServiceRequest> serviceRequestsPage = requestsListJson.map((request) => ServiceRequest.fromJson(request)).toList();
        serviceRequests ??= [];
        serviceRequests!.addAll(serviceRequestsPage);
        notifyListeners();
        if (serviceRequestsPage.length == pageItemNumber) {
          nextPage = true;
        } else {
          nextPage = false;
        }
      }
      isLoading = false;
      notifyListeners();
      return response.statusCode;
    } catch (error) {
      isLoading = false;
      stateCode = -1;
      notifyListeners();
      return -1;
    }
  }

  // Future<ServiceRequest> getSingleServiceRequest({
  //   required String requestId,
  //   required String host,
  //   required User user,
  //   required AppLocalizations subtitle,
  // }) async {
  //   String userData = '';
  //   if (user != null) {
  //     userData += "&uid=" + user!.id!;
  //     userData += "&token=" + user!.token!;
  //   }
  //
  //   Response response;
  //   try {
  //     response = await get(Uri.parse(
  //       host +
  //           URLs.getSingleServiceRequest +
  //           '?call_nid=$requestId'
  //               '$userData',
  //     ));
  //   } catch (error) {
  //     throw (HttpStatusManger.getStatusMessage(status: -1, subtitle: subtitle));
  //   }
  //
  //   // If the call to the server was successful, parse the JSON.
  //   if (response.statusCode >= 200 && response.statusCode < 300) {
  //     // If the call to the server was successful, parse the JSON.
  //     List jsonList = json.decode(utf8.decode(response.bodyBytes).replaceAll("\\", ""));
  //     List<ServiceRequest> _requests = jsonList.map((i) => ServiceRequest.fromJson(i)).toList();
  //     return _requests[0];
  //   } else {
  //     throw (HttpStatusManger.getStatusMessage(status: response.statusCode, subtitle: subtitle));
  //   }
  // }

  Future<void> createRequest({
    required BuildContext context,
    required String host,
    required User user,
    required ServiceRequest serviceRequest,
  }) async {
    var body = {
      "id": 0,
      "calNo": "",
      "callCreatedBy": {"id": user.userID, "name": user.userName ?? ""},
      "assets": serviceRequest.device?.id == null ? [] : [serviceRequest.device?.id],
      "requestedDate": DateTime.now().toIso8601String(),
      "requestedTime": DateTime.now().toIso8601String(),
      "client": user.clientId,
      "callComments": serviceRequest.callComments,
      if (serviceRequest.devicePhotos?.isNotEmpty ?? false) "attachmentsCallRequest": serviceRequest.devicePhotos!.map((e) => {"name": e}).toList(),
      "priority": serviceRequest.priority?.toJson(),
      "defectType": serviceRequest.defectType?.toJson(),
      "typeofRequest": serviceRequest.type?.toJson(),
      "requestedThrough": serviceRequest.requestedThrough?.toJson(),
      "reviewComment": null,
      if (serviceRequest.audio != null) "voiceNote": serviceRequest.audio,
      "callSiteContactPerson": [
        {
          "id": 0,
          // "employeeCode": user.email,
          "name": user.userName,
          "telephone": user.phoneNumber,
          // "job": "",
          "email": user.email,
          // "land": "",
          "contactUserId": user.userID,
        },
      ],
      "noofFollowup": 0,
      "status": null,
      "callLastSituation": null,
      "firstAction": null,
      "loanAvailablity": null,
      "comments": null,
      "firstActionDate": null,
      "visitDate": null,
      "callReview": null,
    };
    if (serviceRequest.audio != null) {
      body["voiceNote"] = serviceRequest.audio;
    }
    showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
    Response response;
    try {
      response = await ApiManager.instance.post(URLs.createRequest, body: body);
      stateCode = response.statusCode;
      if (response.statusCode >= 200 && response.statusCode < 300) {
        if (serviceRequests != null) {
          var data = json.decode(utf8.decode(response.bodyBytes));
          if (data is List) {
            serviceRequests!.insert(0, ServiceRequest.fromJson(data[0]));
          } else {
            if (data["data"] != null && data["data"] == true) {
              // serviceRequests.insert(0, ServiceRequest.fromJson(data[0]));
            }
          }
        }
        notifyListeners();
        Fluttertoast.showToast(msg: context.translation.successfulRequestMessage);
        Navigator.pop(context);
      } else {
        Fluttertoast.showToast(msg: "${context.translation.failedRequestMessage} :${json.decode(response.body)['message']}");
      }
      Navigator.pop(context);
    } catch (error) {
      print(error);
      Navigator.pop(context);
    }
  }

  // Future<int> createIssueReport({
  //   required String host,
  //   required User user,
  //   required Issue issue,
  // }) async {
  //   Response response;
  //   Map<String, String> body = issue.toMap();
  //   body["uid"] = user.id;
  //   body["token"] = user.token;
  //   try {
  //     response = await post(
  //       Uri.parse(host + URLs.createReport),
  //       body: body,
  //     );
  //
  //     stateCode = response.statusCode;
  //     if (response.statusCode >= 200 && response.statusCode < 300) {}
  //     return response.statusCode;
  //   } catch (error) {
  //     return -1;
  //   }
  // }

  Future<PendingAssetServiceRequest?> checkAssetPendingRequest(int assetId) async {
    Response response;
    try {
      response = await ApiManager.instance.post(URLs.CheckIfAssetHasAnotherServiceRequest + "?assetId=$assetId",body: {});
      stateCode = response.statusCode;
      if (response.statusCode >= 200 && response.statusCode < 300) {}
      return PendingAssetServiceRequest.fromJson(json.decode(response.body)["data"]);
    } catch (error) {
      "Please Try Again\n$error".addTranslation.showToast;
      return null;
    }
  }

  Future<int> updateRequest({required User user, required ServiceRequest request}) async {
    isLoading = true;
    notifyListeners();
    Map<String, dynamic> serviceRequest = await getServiceRequestById(requestId: request.id!);
    final List callSiteContacts = (serviceRequest['callSiteContactPerson'] as List);
    final Map<String, dynamic> callSiteContactPerson = callSiteContacts.isEmpty ? {} : callSiteContacts[0];
    Response response;
    try {
      if ((request.audio ?? "").isNotEmpty) {
        request.audio = request.audio!.substring(request.audio!.indexOf("=") + 1, request.audio!.length);
      }
    } catch (ex) {}

    var body = {
      "id": request.id,
      "callNo": serviceRequest['callNo'],
      "callCreatedBy": serviceRequest['callCreatedBy'],
      "requestedDate": request.date ?? "",
      "requestedTime": request.date ?? "",
      "priority": request.priority?.toJson(),
      "defectType": request.defectType?.toJson(),
      "typeofRequest": request.type?.toJson(),
      "requestedThrough": request.requestedThrough?.toJson(),
      "voiceNote": request.audio,
      "assets": request.deviceId == null ? [] : [request.deviceId],
      "attachmentsCallRequest": (request.devicePhotos?.isNotEmpty ?? false) ? request.devicePhotos?.map((e) => {"name": e.getFileName}).toList() : [],
      "assignedEmployee": {
        "id": request.engineerId,
        "name": request.engineerName,
      },
      "callSiteContactPerson": [
        {
          "id": callSiteContactPerson['id'] ?? 0,
          "employeeCode": callSiteContactPerson['employeeCode'],
          "name": callSiteContactPerson['name'] ?? user.userName,
          "telephone": callSiteContactPerson['telephone'] ?? user.phoneNumber,
          "job": callSiteContactPerson['job'],
          "email": callSiteContactPerson['email'] ?? user.email,
          "land": callSiteContactPerson['land'],
          "contactUserId": user.userID,
        },
      ],
      "callComments": request.callComments,
      "noofFollowup": 0,
      "status": request.statusId == null
          ? null
          : {
              "id": request.statusId,
              "name": request.statusLabel,
              "value": request.statusValue,
            },
      "callLastSituation": null,
      "firstAction": request.firstAction?.toJson(),
      "loanAvailablity": request.loanAvailability?.toJson(),
      "comments": request.comments,
      "firstActionDate": request.visitDate,
      "visitDate": request.visitDate,
      "startDate": request.startDate,
      "endDate": request.endDate,
      "workingHours": request.workingHours,
      "callReview": null,
      "reviewComment": null,
      //"reviewComment": request.reviewComment,
    };
    try {
      response = await ApiManager.instance.put(
        URLs.updateRequestDate,
        body: body,
      );
      stateCode = response.statusCode;
      if (response.statusCode >= 200 && response.statusCode < 300) {
        // request.engineerName = employee.name;
        notifyListeners();
      }
      isLoading = false;
      notifyListeners();
      return response.statusCode;
    } catch (error) {
      isLoading = false;
      notifyListeners();
      return -1;
    }
  }

  Future<int> createServiceReport(BuildContext context, {required ServiceReport report, required User user, required ServiceRequest request}) async {
    Response response;
    try {
      showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
      final body = report.toJson();
      final callRequest = CallRequest(id: num.tryParse(request.id ?? "")).toJson();
      final contactPerson = [
        {
          "id": 0,
          // "employeeCode": "",
          "name": user.userName,
          "telephone": user.phoneNumber,
          // "job": "",
          "email": user.email,
          // "land": "",
          "contactUserId": user.userID,
        }
      ];
      body.update("contactPersonWorkOrders", (value) => contactPerson, ifAbsent: () => contactPerson);
      body.update("callRequest", (value) => callRequest, ifAbsent: () => callRequest);
      response = await ApiManager.instance.post(URLs.createServiceReport, body: body);
      stateCode = response.statusCode;
      if (response.statusCode >= 200 && response.statusCode < 300) {
        reset();
        notifyListeners();
        Fluttertoast.showToast(msg: context.translation.successfulRequestMessage);
        Navigator.of(context).pop();
      } else {
        Fluttertoast.showToast(msg: "${context.translation.failedToCompleteRequest}: ${json.decode(response.body)['message']}");
      }
      Navigator.pop(context);
      return response.statusCode;
    } catch (error) {
      Navigator.pop(context);
      print(error);
      return -1;
    }
  }

  Future<int> createSubWorkOrder({required SearchWorkOrder workOrder, bool makeSuppPersonsEmpty = false}) async {
    Response response;
    try {
      if (makeSuppPersonsEmpty) workOrder.supplier?.suppPersons = [];
      Map<String, dynamic> body = workOrder.toJson();
      response = await ApiManager.instance.post(URLs.createServiceReport, body: body);
      stateCode = response.statusCode;
      if (response.statusCode >= 200 && response.statusCode < 300) {
        reset();
        notifyListeners();
      }
      return response.statusCode;
    } catch (error) {
      print(error);
      return -1;
    }
  }

  CallRequest? callRequestForWorkOrder;

  Future<CallRequest?> getCallRequestForWorkOrder({required String callId}) async {
    Response response;
    print('call id i got is ${callId}');
    try {
      response = await ApiManager.instance.get(URLs.getCallRequestForWorkOrder + "?callId=$callId");
      stateCode = response.statusCode;
      if (response.statusCode >= 200 && response.statusCode < 300) {
        // client's request was successfully received
        Map<String, dynamic> listJson = json.decode(response.body)["data"];
        //  log(listJson?.toString());
        callRequestForWorkOrder = CallRequest.fromJson(listJson);
      }

      notifyListeners();
      return callRequestForWorkOrder;
    } catch (error) {
      print(error);
      return null;
    }
  }

  Future<List<SearchWorkOrder>> searchWorkOrders({required String callId}) async {
    Response response;

    try {
      var body = {
        "pageSize": pageItemNumber,
        "pageNumber": ((workOrders.length ?? 0) ~/ pageItemNumber) + 1,
        "callId": callId,
      };
      response = await ApiManager.instance.post(URLs.searchWorkOrders, body: body);
      stateCode = response.statusCode;
      if (response.statusCode >= 200 && response.statusCode < 300) {
        // client's request was successfully received
        List workOrdersJson = json.decode(response.body)["data"];
        workOrders = workOrdersJson.map<SearchWorkOrder>((request) => SearchWorkOrder.fromJson(request)).toList();
        if (workOrders.length == pageItemNumber) {
          nextPage = true;
        } else {
          nextPage = false;
        }
      }
      return workOrders;
    } catch (e) {
      return [];
    }
  }

  Future<ServiceReport?> getSubWorkOrderDetails({required String parentId}) async {
    Response response;
    try {
      response = await ApiManager.instance.get(URLs.getSubWorkerInfoAccordingToPreviousStep + "?parentId=$parentId");
      stateCode = response.statusCode;
      if (response.statusCode >= 200 && response.statusCode < 300) {
        // client's request was successfully received
        final workOrderJson = json.decode(response.body)["data"];
        return ServiceReport.fromJson(workOrderJson);
      }
      return null;
    } catch (e) {
      print("getSubWorkOrderDetails [error] : $e");
      return null;
    }
  }

  // Future<int> createDuplicatedReport({
  //   required String host,
  //   required User user,
  //   required ServiceRequest request,
  // }) async {
  //   Response response;
  //   String userData = '';
  //   if (user != null) {
  //     userData += "&uid=" + user.id;
  //     userData += "&token=" + user.token;
  //   }
  //
  //   try {
  //     response = await get(
  //       Uri.parse(host + URLs.createDuplicatedReport + "?nid=${request.id}" + userData),
  //     );
  //
  //     stateCode = response.statusCode;
  //
  //     if (response.statusCode >= 200 && response.statusCode < 300) {
  //       reset();
  //       notifyListeners();
  //     }
  //     return response.statusCode;
  //   } catch (error) {
  //     return -1;
  //   }
  // }

  Future<int> updateServiceReport(BuildContext context, {required ServiceReport report}) async {
    Response response;
    report.callRequest = CallRequest(id: report.callRequest!.id!);
    Map<String, dynamic> body = report.toJson();
    try {
      showDialog(context: context, barrierDismissible: false, builder: (context) => const AppLazyLoading());
      response = await ApiManager.instance.put(URLs.updateServiceReport, body: body);
      if (response.statusCode >= 200 && response.statusCode < 300) {
        reset();
        notifyListeners();
        Fluttertoast.showToast(msg: context.translation.successfulRequestMessage);
        Navigator.of(context).pop();
      } else {
        Fluttertoast.showToast(msg: context.translation.failedToCompleteRequest);
      }
      Navigator.of(context).pop();
      return response.statusCode;
    } catch (e) {
      print(e);
      Navigator.of(context).pop();
      return -1;
    }
  }

  Future<int> updateWorkOrderDetails({required SearchWorkOrder workOrder}) async {
    Response response;
    //Map<String,dynamic> body = report.toMap(request);
    // body["uid"] = user.id;
    // body["token"] = user.token;
    // body["job_id"] = request.id;
    // body["report_id"] = request.reportID;
    try {
      Map<String, dynamic> body = workOrder.toJson();
      // body["uid"] = user.id;
      // body["token"] = user.token;
      response = await ApiManager.instance.put(URLs.updateServiceReport, body: body);
      // response = await post(
      //   Uri.parse(
      //       host+URLs.updateServiceReport),
      //   body: body,
      // );
      // stateCode = response.statusCode;

      if (response.statusCode >= 200 && response.statusCode < 300) {
        reset();
        notifyListeners();
      }
      return response.statusCode;
    } catch (error) {
      return -1;
    }
  }

  Future<int> updateServiceReportTimer({required String host, required User user, required TimerModel timer, required ServiceRequest request}) async {
    Response response;
    Map<String, dynamic> body = {};
    body["uid"] = user.id;
    body["token"] = user.token;
    body["job_id"] = request.id;
    body["start_time"] = (timer.startAt!.millisecondsSinceEpoch / 1000).toStringAsFixed(0);
    body["end_time"] = (timer.endAt!.millisecondsSinceEpoch / 1000).toStringAsFixed(0);
    body["working_hours"] = (timer.durationInSecond! / 60 / 60).toStringAsFixed(5);
    body["report_id"] = request.reportID;
    try {
      response = await post(
        Uri.parse(host + URLs.updateServiceReport),
        body: body,
      );
      //stateCode = response.statusCode;

      if (response.statusCode >= 200 && response.statusCode < 300) {
        // reset();
        // notifyListeners();
      }
      return response.statusCode;
    } catch (error) {
      return -1;
    }
  }

  Future<ServiceReport> getSingleServiceReport(BuildContext context, {required int reportId}) async {
    Response response;
    try {
      response = await ApiManager.instance.get(URLs.getServiceReport + "?workOrderId=$reportId");
    } catch (error) {
      throw (context.translation.failedToCompleteRequest);
    }

    // If the call to the server was successful, parse the JSON.
    if (response.statusCode >= 200 && response.statusCode < 300) {
      // If the call to the server was successful, parse the JSON.
      return ServiceReport.fromJson(json.decode(response.body)["data"]);
    } else {
      throw (("${context.translation.failedToCompleteRequest} ${jsonDecode(response.body)["message"]}"));
    }
  }

  Future<ServiceRequest?> getServiceRequestObjectById({required String requestId}) async {
    try {
      isDetialLoading = true;
      Response response = await ApiManager.instance.get(URLs.getServiceRequestById + "?callRequestId=$requestId");
      if (response.statusCode >= 200 && response.statusCode < 300) {
        isDetialLoading = false;
        return ServiceRequest.fromJson(json.decode(response.body)["data"]);
      } else {
        isDetialLoading = false;
        return null;
      }
    } catch (error) {
      isDetialLoading = false;
      return null;
    }
  }

  Future<Map<String, dynamic>> getServiceRequestById({required String requestId}) async {
    Response response;
    try {
      response = await ApiManager.instance.get(URLs.getServiceRequestById + "?callRequestId=$requestId");
    } catch (error) {
      print(error);
      return {};
    }

    // If the call to the server was successful, parse the JSON.
    if (response.statusCode >= 200 && response.statusCode < 300) {
      // If the call to the server was successful, parse the JSON.
      return {
        "callNo": json.decode(response.body)["data"]["callNo"],
        "callCreatedBy": json.decode(response.body)["data"]["callCreatedBy"],
        "callSiteContactPerson": json.decode(response.body)["data"]["callSiteContactPerson"],
        "firstActionDate": json.decode(response.body)["data"]["firstActionDate"],
      };
    } else {
      return {};
    }
  }

  Future<List<SearchWorkOrder>> searchForWorkOrders(
    SearchWorkOrder search,
    String callerId,
    Lookup dateOperator,
    String site,
  ) async {
    Response response;
    try {
      var body = {
        "pageSize": pageItemNumber,
        "pageNumber": ((workOrders.length ?? 0) ~/ pageItemNumber) + 1,
        if (callerId.isNotEmpty ?? false) "callId": callerId,
        if (search.assetType != null) "assetSerialNo": search.assetType?.name,
        if (search.workOrderNo != null) "workOrderNo": search.workOrderNo,
        if (search.id != null) "workOrderNo": search.id.toString(),
        if (search.calllastSituation != null) "callslastSituationWO": search.calllastSituation!.toJson(),
        if (search.assignedEmployee != null) "assignedEmployees": [search.assignedEmployee!.id],
        // "statusWO": [],
        if (site.isNotEmpty ?? false) "site": site,
        if (search.visitDate != null) "visitDateSymbol": dateOperator.toJson(),
        if (search.visitDate != null) "visitDateFrom": search.visitDate,
      };
      print(body);
      response = await ApiManager.instance.post(URLs.searchWorkOrders, body: body);
      stateCode = response.statusCode;
      if (response.statusCode >= 200 && response.statusCode < 300) {
        // client's request was successfully received
        List workOrdersJson = json.decode(response.body)["data"];
        workOrders ??= [];
        workOrders.addAll(workOrdersJson.map<SearchWorkOrder>((request) => SearchWorkOrder.fromJson(request)).toList());
        if (workOrders.length == pageItemNumber) {
          nextPage = true;
        } else {
          nextPage = false;
        }
      }
      return workOrders;
    } catch (e) {
      print(e);
      return [];
    }
  }

  Future<SuppEngineerWorkOrders?> addSupplierEngineer(SupplierEngineer supplierEngineer) async {
    isLoading = true;
    notifyListeners();
    Response response;
    SuppEngineerWorkOrders? res;
    try {
      response = await ApiManager.instance.post(URLs.addSupplierEngineer, body: supplierEngineer.toJson());
      stateCode = response.statusCode;
      if (response.statusCode >= 200 && response.statusCode < 300) {
        res = SuppEngineerWorkOrders.fromJson(json.decode(response.body)["data"]);
      }
      isLoading = false;
      notifyListeners();
      return res;
    } catch (error) {
      isLoading = false;
      notifyListeners();
      return res;
    }
  }

  SparePartsWorkOrders get initialSelectedSparePart => _initialSelectedSparePart;

  set initialSelectedSparePart(SparePartsWorkOrders value) {
    _initialSelectedSparePart = value;
    notifyListeners();
  }

  List<SparePartsWorkOrders> get sparePartList => _sparePartList;

  set sparePartList(List<SparePartsWorkOrders> value) {
    _sparePartList = value;
    notifyListeners();
  }
}
