import 'dart:convert';
import 'dart:io' show Platform;

import 'package:doctor_app_flutter/config/config.dart';
import 'package:doctor_app_flutter/config/shared_pref_kay.dart';
import 'package:doctor_app_flutter/core/model/doctor/doctor_profile_model.dart';
import 'package:doctor_app_flutter/core/model/patient/patiant_info_model.dart';
import 'package:doctor_app_flutter/core/service/NavigationService.dart';
import 'package:doctor_app_flutter/core/service/hospitals/hospitals_service.dart';
import 'package:doctor_app_flutter/core/viewModel/authentication_view_model.dart';
import 'package:doctor_app_flutter/utils/dr_app_shared_pref.dart';
import 'package:doctor_app_flutter/utils/dr_app_toast_msg.dart';
import 'package:doctor_app_flutter/utils/exception_report.dart';
import 'package:doctor_app_flutter/utils/utils.dart';
import 'package:flutter/cupertino.dart';
import 'package:http/http.dart' as http;
import 'package:logger/logger.dart';
import 'package:provider/provider.dart';

import '../locator.dart';
import '../routes.dart';
import 'dart:developer';
DrAppSharedPreferances sharedPref = new DrAppSharedPreferances();
Utils helpers = new Utils();

class BaseAppClient {
  //TODO change the post fun to nun static when you change all service
  post(String endPoint,
      {Map<String, dynamic>? body,
      required Function(dynamic response, int statusCode) onSuccess,
      required Function(String error, int statusCode) onFailure,
      bool isAllowAny = false,
      bool isLiveCare = false,
      bool isFallLanguage = false,
      bool isCustomRequest = false
      }) async {
    String url;
    if (isLiveCare)
      url = BASE_URL_LIVE_CARE + endPoint;
    else
      url = BASE_URL + endPoint;

    bool callLog = true;
    try {
      Map<String, dynamic>? profile = await sharedPref.getObj(DOCTOR_PROFILE);

      if (profile != null) {
        DoctorProfileModel doctorProfile = DoctorProfileModel.fromJson(profile);
        if (body?['MemberID'] == null)
          body?['MemberID'] = HospitalsService.memberId.isNotEmpty ? HospitalsService.memberId : doctorProfile.doctorID; // changed from null; because create update episode not working
      }

      // if (body?['MemberID'] == null) body?['MemberID'] = HospitalsService.memberId; // changed from null; because create update episode not working

      String? token = await sharedPref.getString(TOKEN);
      if(!isCustomRequest) {
        if (profile != null) {
          DoctorProfileModel doctorProfile = DoctorProfileModel.fromJson(profile);
          if (body == null || body['DoctorID'] == null) {
            body!['DoctorID'] = doctorProfile.doctorID.toString();
          }
          if (body['DoctorID'] == "") body['DoctorID'] = doctorProfile.doctorID; // changed from null; because create update episode not working
          if (body['EditedBy'] == null) body['EditedBy'] = doctorProfile.doctorID.toString();
          if (body['ProjectID'] == null) {
            body['ProjectID'] = doctorProfile.projectID.toString();
          }

          if (body['ClinicID'] == null) body['ClinicID'] = doctorProfile.clinicID.toString();
        } else {
          String? doctorID = await sharedPref.getString(DOCTOR_ID);
          if (body!['DoctorID'] == '') {
            body['DoctorID'] = null;
          } else if (doctorID != null) body['DoctorID'] = int.parse(doctorID);
        }

        body['SetupID'] = body.containsKey('SetupID')
            ? body['SetupID'] != null
            ? body['SetupID']
            : await sharedPref.getString(DOCTOR_SETUP_ID)
            : await sharedPref.getString(DOCTOR_SETUP_ID);

        if (body['EditedBy'] == '') {
          body.remove("EditedBy");
        }
        if (body['TokenID'] == null) {
          body['TokenID'] = token ?? '';
        }

        if (!isFallLanguage) {
          String? lang = await sharedPref.getString(APP_Language);
          if (lang != null && lang == 'ar')
            body['LanguageID'] = '1';
          else
            body['LanguageID'] = '2';
        }
        body['stamp'] = DateTime.now().toIso8601String();
        body['IPAdress'] = IP_ADDRESS.toString();
        if (body['VersionID'] == null) {
          body['VersionID'] = VERSION_ID.toString();
        }
        if (body['Channel'] == null) {
          body['Channel'] = CHANNEL.toString();
        }
        body['SessionID'] = SESSION_ID.toString();
        body['IsLoginForDoctorApp'] = IS_LOGIN_FOR_DOCTOR_APP.toString();
        body['PatientOutSA'] = body['PatientOutSA'] ?? '0'; // PATIENT_OUT_SA;
        if (body['VidaAuthTokenID'] == null) {
          body['VidaAuthTokenID'] = await sharedPref.getString(VIDA_AUTH_TOKEN_ID);
        }
        if (body['VidaRefreshTokenID'] == null) {
          body['VidaRefreshTokenID'] = await sharedPref.getString(VIDA_REFRESH_TOKEN_ID);
        }

        int? projectID = await sharedPref.getInt(PROJECT_ID);
        if (projectID == 2 || projectID == 3)
          body['PatientOutSA'] = true;
        else if ((body.containsKey('facilityId') && body['facilityId'] == 2 || body['facilityId'] == 3) || body['ProjectID'] == 2 || body['ProjectID'] == 3)
          body['PatientOutSA'] = 'true';
        else
          body['PatientOutSA'] = 'false';

        // if (!body.containsKey('ProjectID')) {
        //   if (projectID != null) {
        //     body['ProjectID'] = projectID;
        //   } else {
        //     body['ProjectID'] = 0;
        //   }
        // }

        body['DeviceTypeID'] = Platform.isAndroid ? '1' : '2';
        if (body['SetupID'] != null) {
          body['SetupID'] = body['SetupID'].trim();
        }
      }
      // body['ClinicID'] = 501;
      // body['ProjectID'] = 12;

      // body['DoctorID'] = 1002; //3844083
      // body['TokenID'] = "@dm!n";

      // print("ProjectID :");
      // print(body['ProjectID']);
      Logger logger = Logger(
        printer: PrettyPrinter(
          methodCount: 2,
          errorMethodCount: 5,
          lineLength: 1000,
          colors: true,
          printEmojis: true,
        ),
      );
      print("URL : $url");
      logger.d("URL : $url");
      print("Body : ${json.encode(body)}");
      logger.d("Body : ${json.encode(body)}");
      var asd = json.encode(body);
      var asd2;
      if (await Utils.checkConnection()) {
        final response = await http.post(Uri.parse(url), body: json.encode(body), headers: {'Content-Type': 'application/json', 'Accept': 'application/json'});
        final int statusCode = response.statusCode;

        if (body!['DoctorID'] != null) {
          postRequestAndResponse(
              doctorId: body['DoctorID'],
              completeUrl: url,
              request: json.encode(body),
              response: response.body,
              urlSuffix: endPoint,
              statusCode: statusCode.toString());
        }
        if (statusCode < 200 || statusCode >= 400) {
          onFailure(Utils.generateContactAdminMsg(), statusCode);
          if (body['DoctorID'] != null) postFailureResponse(doctorId: body['DoctorID'], url: url, request: json.encode(body), response: response.body, exception: "$statusCode");
        } else {
          var parsed = json.decode(response.body.toString());
          if (parsed['ErrorType'] == 4) {
            helpers.navigateToUpdatePage(parsed['ErrorEndUserMessage'], parsed['AndroidLink'], parsed['IOSLink']);
          }

          if (parsed['IsAuthenticated'] != null && !parsed['IsAuthenticated']) {

            if (body['OTP_SendType'] != null) {
              if (parsed['ErrorCode'] == '699') {
                onSuccess(parsed, statusCode);
              } else {
                if (body['DoctorID'] != null) postFailureResponse(doctorId: body['DoctorID'], url: url, request: json.encode(body), response: response.body, exception: getError(parsed));
                onFailure(getError(parsed), statusCode);
              }
            } else if (!isAllowAny) {
              await Provider.of<AuthenticationViewModel>(AppGlobal.CONTEX, listen: false).logout();
              //todo nofailure is placed here and but have to handle the response here as well
              Utils.showErrorToast('Your session expired Please login again');
              locator<NavigationService>().pushNamedAndRemoveUntil(ROOT);
            }
            if (isAllowAny) {
              onFailure(getError(parsed), statusCode);
            }
          } else if (parsed['MessageStatus'] == 1) {
            if (!parsed['IsAuthenticated']) {
              if (body['DoctorID'] != null) postFailureResponse(doctorId: body['DoctorID'], url: url, request: json.encode(body), response: response.body, exception: getError(parsed));
              onFailure(getError(parsed), statusCode);
            } else
              onSuccess(parsed, statusCode);
          } else {
            final validations = parsed['ValidationErrorsCSI']?['errors']?['Validations'];

            if (validations is List && validations.isNotEmpty) {
              final error = validations.first['Error'];
              if (error != null) {
                onFailure(error, statusCode);
                return;
              }
            }
            if (body['DoctorID'] != null) {
              postFailureResponse(doctorId: body['DoctorID'], url: url, request: json.encode(body), response: response.body, exception: getError(parsed));
            }
            onFailure(getError(parsed), statusCode);
          }
        }
      } else {
        onFailure('Please Check The Internet Connection', -1);
      }
    } catch (e) {
      print(e);
      onFailure(e.toString(), -1);
    }
  }

  postPatient(String endPoint,
      {Map<String, dynamic>? body,
      required Function(dynamic response, int statusCode) onSuccess,
      required Function(String error, int statusCode) onFailure,
      PatiantInformtion? patient,
      bool isExternal = false}) async {
    String url = BASE_URL + endPoint;

    try {
      Map<String, String> headers = {'Content-Type': 'application/json', 'Accept': 'application/json'};

      String? token = await sharedPref.getString(TOKEN);
      Map<String, dynamic>? profile = await sharedPref.getObj(DOCTOR_PROFILE);

      // if (body?['MemberID'] == null) body?['MemberID'] = HospitalsService.memberId;

      if (profile != null) {
        DoctorProfileModel doctorProfile = DoctorProfileModel.fromJson(profile);
        if (body?['MemberID'] == null)
          body?['MemberID'] = HospitalsService.memberId.isNotEmpty ? HospitalsService.memberId : doctorProfile.doctorID; // changed from null; because create update episode not working
      }

      if (profile != null) {
        DoctorProfileModel doctorProfile = DoctorProfileModel.fromJson(profile);
        if (body!['DoctorID'] == null) {
          body['DoctorID'] = doctorProfile.doctorID;
        }
      }
      if (body!['DoctorID'] == 0) {
        body['DoctorID'] = null;
      }
      var languageID = await sharedPref.getStringWithDefaultValue(APP_Language, 'en');
      body['SetupID'] = body!.containsKey('SetupID')
          ? body['SetupID'] != null
              ? body['SetupID']
              : await sharedPref.getString(DOCTOR_SETUP_ID)
          : await sharedPref.getString(DOCTOR_SETUP_ID);

      body['VersionID'] = VERSION_ID;
      body['Channel'] = CHANNEL;
      body['LanguageID'] = languageID == 'ar' ? 1 : 2;

      body['IPAdress'] = "10.20.10.20";
      body['generalid'] = GENERAL_ID;
      body['PatientOutSA'] = body.containsKey('PatientOutSA')
          ? body['PatientOutSA'] != null
              ? body['PatientOutSA']
              : PATIENT_OUT_SA_PATIENT_REQ
          : PATIENT_OUT_SA_PATIENT_REQ;

      if (body.containsKey('isDentalAllowedBackend')) {
        body['isDentalAllowedBackend'] = body.containsKey('isDentalAllowedBackend')
            ? body['isDentalAllowedBackend'] != null
                ? body['isDentalAllowedBackend']
                : IS_DENTAL_ALLOWED_BACKEND
            : IS_DENTAL_ALLOWED_BACKEND;
      }

      body['DeviceTypeID'] = Platform.isAndroid ? 1 : 2;

      body['PatientType'] = body.containsKey('PatientType')
          ? body['PatientType'] != null
              ? body['PatientType']
              : patient!.patientType != null
                  ? patient.patientType
                  : PATIENT_TYPE
          : PATIENT_TYPE;

      body['PatientTypeID'] = body.containsKey('PatientTypeID')
          ? body['PatientTypeID'] != null
              ? body['PatientTypeID']
              : patient!.patientType != null
                  ? patient.patientType
                  : PATIENT_TYPE_ID
          : PATIENT_TYPE_ID;

      body['TokenID'] = body.containsKey('TokenID') ? body['TokenID'] ?? token : token;
      body['PatientID'] = body['PatientID'] != null ? body['PatientID'] : patient!.patientId ?? patient.patientMRN;
      body['PatientMRN'] = body['PatientMRN'] != null ? body['PatientMRN'] : patient!.patientId ?? patient.patientMRN;
      if (body['ProjectID'] == null) {
        body['ProjectID'] = patient?.projectId.toString();
      }

      body['PatientOutSA'] = 0; //user['OutSA']; //TODO change it
      body['SessionID'] = SESSION_ID; //getSe

      int? projectID = await sharedPref.getInt(PROJECT_ID);
      if (projectID == 2 || projectID == 3)
        body['PatientOutSA'] = true;
      else
        body['PatientOutSA'] = false;

      // if(!body.containsKey('ProjectID')) {
      //   if (projectID != null) {
      // body['ProjectID'] = 313;
      //   } else {
      //     body['ProjectID'] = 0;
      //   }
      // }

      // body['DoctorID'] = 24; //3844083
      // body['TokenID'] = "@dm!n";

      print("URL : $url");
      print("Body : ${json.encode(body)}");
      var asd = json.encode(body);
      var asd2;
      if (await Utils.checkConnection()) {
        final response = await http.post(Uri.parse(url.trim()), body: json.encode(body), headers: headers);
        final int statusCode = response.statusCode;
        print("statusCode :$statusCode");
        if (statusCode < 200 || statusCode >= 400 || json == null) {
          onFailure('Error While Fetching data', statusCode);
        } else {
          // var parsed = json.decode(response.body.toString());
          var parsed = json.decode(utf8.decode(response.bodyBytes));
          if (parsed['Response_Message'] != null) {
            onSuccess(parsed, statusCode);
          } else {
            if (parsed['ErrorType'] == 4) {
              helpers.navigateToUpdatePage(parsed['ErrorEndUserMessage'], parsed['AndroidLink'], parsed['IOSLink']);
            }
            if (parsed['IsAuthenticated'] == null) {
              if (parsed['isSMSSent'] == true) {
                onSuccess(parsed, statusCode);
              } else if (parsed['MessageStatus'] == 1) {
                onSuccess(parsed, statusCode);
              } else if (parsed['Result'] == 'OK') {
                onSuccess(parsed, statusCode);
              } else {
                if (parsed != null) {
                  onSuccess(parsed, statusCode);
                } else {
                  if (body['DoctorID'] != null) postFailureResponse(doctorId: body['DoctorID'], url: url, request: json.encode(body), response: response.body, exception: getError(parsed));
                  onFailure(getError(parsed), statusCode);
                }
              }
            } else if (parsed['MessageStatus'] == 1 || parsed['SMSLoginRequired'] == true) {
              onSuccess(parsed, statusCode);
            } else if (parsed['MessageStatus'] == 2 && parsed['IsAuthenticated']) {
              if (parsed['SameClinicApptList'] != null) {
                onSuccess(parsed, statusCode);
              } else {
                if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) {
                  if (parsed['ErrorSearchMsg'] == null) {
                    if (body['DoctorID'] != null)
                      postFailureResponse(doctorId: body['DoctorID'], url: url, request: json.encode(body), response: response.body, exception: "Server Error found with no available message");

                    onFailure("Server Error found with no available message", statusCode);
                  } else {
                    if (body['DoctorID'] != null) postFailureResponse(doctorId: body['DoctorID'], url: url, request: json.encode(body), response: response.body, exception: parsed['ErrorSearchMsg']);
                    onFailure(parsed['ErrorSearchMsg'], statusCode);
                  }
                } else {
                  if (body['DoctorID'] != null)
                    postFailureResponse(
                        doctorId: body['DoctorID'],
                        url: url,
                        request: json.encode(body),
                        response: response.body,
                        exception: parsed['message'] ?? parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);
                  onFailure(parsed['message'] ?? parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode);
                }
              }
            } else {
              if (parsed['SameClinicApptList'] != null) {
                onSuccess(parsed, statusCode);
              } else {
                if (parsed['message'] != null) {
                  if (body['DoctorID'] != null) postFailureResponse(doctorId: body['DoctorID'], url: url, request: json.encode(body), response: response.body, exception: parsed['message']);

                  onFailure(parsed['message'] ?? parsed['message'], statusCode);
                } else {
                  if (body['DoctorID'] != null)
                    postFailureResponse(doctorId: body['DoctorID'], url: url, request: json.encode(body), response: response.body, exception: parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage']);

                  onFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode);
                }
              }
            }
          }
        }
      } else {
        onFailure('Please Check The Internet Connection', -1);
      }
    } catch (e) {
      print(e);
      onFailure(e.toString(), -1);
    }
  }

  String getError(parsed) {
    //TODO change this fun
    String? error = parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'];
    if (parsed["ValidationErrors"] != null) {
      error = parsed["ValidationErrors"]["StatusMessage"].toString() + "\n";

      if (parsed["ValidationErrors"]["ValidationErrors"] != null && parsed["ValidationErrors"]["ValidationErrors"].length != 0) {
        for (var i = 0; i < parsed["ValidationErrors"]["ValidationErrors"].length; i++) {
          error = error! + parsed["ValidationErrors"]["ValidationErrors"][i]["Messages"][0] + "\n";
        }
      }
    }
    if (error == null || error == "null" || error == "null\n") {
      return Utils.generateContactAdminMsg();
    }
    return error;
  }

  get({required String endPoint, required Function(dynamic response, int statusCode) onSuccess, required Function(String error, int statusCode) onFailure}) async {
    String token = await sharedPref.getString(TOKEN);
    String url = DOCTOR_ROTATION + endPoint + '&token=' + token;
    print(url);
    final response = await http.get(Uri.parse(url));

    final int statusCode = response.statusCode;
    if (statusCode < 200 || statusCode >= 400) {
      onFailure(Utils.generateContactAdminMsg(), statusCode);
    } else {
      var parsed = json.decode(response.body.toString());
      onSuccess(parsed, statusCode);
    }
  }
}
