import 'dart:convert';

import 'package:flutter/cupertino.dart';
import 'package:http/http.dart';

import '../../../models/issue.dart';
import '../../../models/lookup.dart';
import '../../../models/service_report.dart';
import '../../../models/service_request/service_request.dart';
import '../../../models/service_request/service_request_search.dart';
import '../../../models/subtitle.dart';
import '../../../models/timer_model.dart';
import '../../../models/user.dart';
import '../../api_routes/urls.dart';
import '../../http_status_manger/http_status_manger.dart';

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

  //reset provider data
  void reset() {
    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;

  // true if there is next page in product list and false if not
  bool? nextPage = true;

  // list of user requests
  List<ServiceRequest>? serviceRequests;

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

  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 String host,
    required User? user,
    required String? hospitalId,
  }) async {
    if (isLoading == true) {
      return -2;
    }
    isLoading = true;
    Response response;
    try {
      response = await get(
        Uri.parse(
          "$host${URLs.getServiceRequests}?uid=${user?.id}${hospitalId == null ? "" : "&client_nid=$hospitalId"}&token=${user?.token}&page=${(serviceRequests?.length ?? 0) ~/ pageItemNumber}${search?.toSearchString()}",
        ),
        headers: {"Content-Type": "application/json; charset=utf-8"},
      );
      stateCode = response.statusCode;
      if (response.statusCode >= 200 && response.statusCode < 300) {
        // client's request was successfully received
        List requestsListJson = json.decode(utf8.decode(response.bodyBytes).replaceAll("\\", ""));
        List<ServiceRequest> _serviceRequestsPage = requestsListJson.map((request) => ServiceRequest.fromJson(request)).toList();
        serviceRequests ??= [];
        serviceRequests?.addAll(_serviceRequestsPage);
        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 Subtitle subtitle,
  }) async {
    String userData = '';
    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<int> createRequest({
    required String host,
    required User user,
    required ServiceRequest serviceRequest,
  }) async {
    var body = {
      "uid": user.id,
      "token": user.token ?? "",
      "sn_id": serviceRequest.deviceId ?? "",
      "date": (DateTime.now().millisecondsSinceEpoch).toString(),
      "client": user.hospital?.id ?? '',
      "complaint": serviceRequest.maintenanceIssue,
      "image": json.encode(serviceRequest.devicePhotos),
      "priority": (serviceRequest.priority?.id).toString(),
      "defect_types": (serviceRequest.defectType?.id).toString(),
    };
    body["audio"] = serviceRequest.audio;
    Response response;
    try {
      response = await post(
        Uri.parse(host + URLs.createRequest),
        body: body,
      );
      stateCode = response.statusCode;
      if (response.statusCode >= 200 && response.statusCode < 300) {
        final serviceRequests = this.serviceRequests;
        if (serviceRequests != null) {
          serviceRequests.insert(
            0,
            ServiceRequest.fromJson(
              json.decode(utf8.decode(response.bodyBytes))[0],
            ),
          );
        }
        notifyListeners();
      }
      return response.statusCode;
    } catch (error) {
      return -1;
    }
  }

  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<int> updateDate({
    required String? host,
    required User? user,
    required String? newDate,
    required Lookup? employee,
    required ServiceRequest? request,
  }) async {
    Response response;
    Map<String, String> body = {};
    body["uid"] = user?.id ?? '';
    body["token"] = user?.token ?? '';
    body["nid"] = request?.id ?? '';
    body["date"] = newDate ?? '';
    body["ass_emp"] = employee?.id.toString() ?? '';
    try {
      response = await post(
        Uri.parse((host ?? '') + URLs.updateRequestDate),
        body: body,
      );
      stateCode = response.statusCode;
      if (response.statusCode >= 200 && response.statusCode < 300) {
        request?.engineerName = employee?.label;
        notifyListeners();
      }
      return response.statusCode;
    } catch (error) {
      return -1;
    }
  }

  Future<int> createServiceReport({
    required String host,
    required User user,
    required ServiceReport report,
    required ServiceRequest request,
  }) async {
    Response response;
    Map<String, String> body = report.toMap();
    body["uid"] = user.id ?? "";
    body["token"] = user.token ?? "";
    body["job_id"] = request.id ?? '';
    try {
      response = await post(
        Uri.parse(host + URLs.createServiceReport),
        body: body,
      );

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

  Future<int> createDuplicatedReport({
    required String host,
    required User user,
    required ServiceRequest request,
  }) async {
    Response response;
    String userData = '';
    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({
    required String host,
    required User user,
    required ServiceReport report,
    required ServiceRequest request,
  }) async {
    Response response;
    Map<String, String> body = report.toMap();
    body["uid"] = user.id ?? "";
    body["token"] = user.token ?? "";
    body["job_id"] = request.id ?? '';
    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<int> updateServiceReportTimer({
    required String host,
    required User user,
    required TimerModel timer,
    required ServiceRequest request,
  }) async {
    Response response;
    Map<String, String> body = {};
    body["uid"] = user.id ?? "";
    body["token"] = user.token ?? "";
    body["job_id"] = request.id ?? '';
    body["start_time"] = ((timer.startAt?.millisecondsSinceEpoch ?? 0) / 1000).toStringAsFixed(0);
    body["end_time"] = ((timer.endAt?.millisecondsSinceEpoch ?? 0) / 1000).toStringAsFixed(0);
    body["working_hours"] = ((timer.durationInSecond ?? 0) / 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({
    required String reportId,
    required String host,
    required User user,
    required Subtitle subtitle,
  }) async {
    String userData = '';
    userData += "&uid=${user.id}";
    userData += "&token=${user.token}";

    Response response;
    try {
      response = await get(Uri.parse(
        '$host${URLs.getServiceReport}?report_id=$reportId$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.
      return ServiceReport.fromJson(json.decode(utf8.decode(response.bodyBytes)), reportId);
    } else {
      throw (HttpStatusManger.getStatusMessage(
            status: response.statusCode,
            subtitle: subtitle,
          ) ??
          '');
    }
  }
}
