import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:logger/logger.dart' as L;
import 'package:mohem_flutter_app/api/api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/models/marathon/marathon_generic_model.dart';
import 'package:mohem_flutter_app/models/marathon/marathon_model.dart';
import 'package:mohem_flutter_app/models/marathon/question_model.dart';
import 'package:mohem_flutter_app/models/marathon/winner_model.dart';
import 'package:mohem_flutter_app/ui/marathon/marathon_provider.dart';
import 'package:provider/provider.dart';

class MarathonApiClient {
  L.Logger logger = L.Logger();

  Future<String> getMarathonToken() async {
    String employeeUserName = AppState().getUserName ?? "";
    String employeeSession = AppState().postParamsObject?.pSessionId.toString() ?? "";
    Map<String, String> jsonObject = <String, String>{"userName": employeeUserName, "password": employeeSession};

    return await ApiClient().postJsonForObject(
      (json) {
        MarathonGenericModel marathonModel = MarathonGenericModel.fromJson(json);
        AppState().setMarathonToken = marathonModel.data["token"] ?? "";
        return marathonModel.data["token"] ?? "";
      },
      ApiConsts.marathonParticipantLoginUrl,
      jsonObject,
    );
  }

  Future<String> getProjectId() async {
    return await ApiClient().postJsonForObject(
      (json) {
        MarathonGenericModel responseData = MarathonGenericModel.fromJson(json);
        return responseData.data[0]["id"] ?? "";
      },
      ApiConsts.marathonProjectGetUrl,
      <String, dynamic>{},
      token: AppState().getMarathonToken == null || AppState().getMarathonToken == "" ? await getMarathonToken() : AppState().getMarathonToken,
    );
  }

  Future<MarathonDetailModel> getMarathonDetails() async {
    String payrollString = AppState().postParamsObject?.payrollCodeStr.toString() ?? "CS";

    Response response = await ApiClient().getJsonForResponse(
      ApiConsts.marathonUpcomingUrl + payrollString,
      token: AppState().getMarathonToken == null || AppState().getMarathonToken == "" ? await getMarathonToken() : AppState().getMarathonToken,
    );

    var json = jsonDecode(response.body);
    logger.i("json in getMarathonDetails: $json");

    MarathonGenericModel marathonGenericModel = MarathonGenericModel.fromJson(json);

    if (marathonGenericModel.data == null) {
      return MarathonDetailModel();
    }

    MarathonDetailModel marathonDetailModel = MarathonDetailModel.fromJson(marathonGenericModel.data);

    AppState().setMarathonProjectId = marathonDetailModel.id!;

    return marathonDetailModel;
  }

  Future<int?> joinMarathonAsParticipant() async {
    Map<String, String> jsonObject = <String, String>{
      "employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER ?? "",
      "employeeNameAr": AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEAr ?? "",
      "employeeNameEn": AppState().memberInformationList!.eMPLOYEEDISPLAYNAMEEn ?? "",
      "marathonId": AppState().getMarathonProjectId!,
    };

    return await ApiClient().postJsonForObject(
      (json) {
        MarathonGenericModel marathonModel = MarathonGenericModel.fromJson(json);
        return marathonModel.data["remainingTime"];
      },
      ApiConsts.marathonJoinParticipantUrl,
      jsonObject,
      token: AppState().getMarathonToken == null || AppState().getMarathonToken == "" ? await getMarathonToken() : AppState().getMarathonToken,
    );
  }

  Future<QuestionModel> getNextQuestion({required String? questionId, required String marathonId}) async {
    Map<String, String?> jsonObject = <String, String?>{
      "previousQuestionId": questionId,
      "marathonId": marathonId,
    };

    return await ApiClient().postJsonForObject(
      (json) {
        MarathonGenericModel marathonModel = MarathonGenericModel.fromJson(json);

        if (marathonModel.statusCode == 404 || marathonModel.statusCode == 208 || marathonModel.statusCode == 204 || marathonModel.statusCode == 500) {
          Utils.confirmDialog(
            AppRoutes.navigatorKey.currentContext,
            marathonModel.message!,
            onTap: () {
              AppRoutes.navigatorKey.currentContext!.read<MarathonProvider>().resetValues();
              Navigator.of(
                AppRoutes.navigatorKey.currentContext!,
              ).popUntil(ModalRoute.withName(AppRoutes.dashboard));
            },
          );
        }
        QuestionModel newQuestion = QuestionModel.fromJson(marathonModel.data);
        return newQuestion;
      },
      ApiConsts.marathonNextQuestionUrl,
      jsonObject,
      token: AppState().getMarathonToken == null || AppState().getMarathonToken == "" ? await getMarathonToken() : AppState().getMarathonToken,
    );
  }

  Future<bool> submitSelectedOption({required String marathonId, required String? questionId, required String? selectedAnswerId}) async {
    Map<String, String?> jsonObject = <String, String?>{"marathonId": marathonId, "questionId": questionId, "selectedOptionId": selectedAnswerId};

    return await ApiClient().postJsonForObject(
      (json) {
        MarathonGenericModel marathonModel = MarathonGenericModel.fromJson(json);
        if (marathonModel.data != null) {
          bool isOptionCorrect = marathonModel.data["isCorrect"];
          return isOptionCorrect;
        }
        return false;
      },
      ApiConsts.marathonSubmitAnswerUrl,
      jsonObject,
      token: AppState().getMarathonToken == null || AppState().getMarathonToken == "" ? await getMarathonToken() : AppState().getMarathonToken,
    );
  }

  Future<int?> getQualifiers({required String marathonId}) async {
    Map<String, String> params = <String, String>{"marathonId": marathonId};
    Response response = await ApiClient().getJsonForResponse(
      ApiConsts.marathonQualifiersUrl,
      queryParameters: params,
      token: AppState().getMarathonToken == null || AppState().getMarathonToken == "" ? await getMarathonToken() : AppState().getMarathonToken,
    );

    var json = jsonDecode(response.body);
    logger.i("json in getQualifiers: $json");

    MarathonGenericModel marathonGenericModel = MarathonGenericModel.fromJson(json);

    if (marathonGenericModel.isSuccessful == true && marathonGenericModel.statusCode == 200 && marathonGenericModel.data != null) {
      return marathonGenericModel.data["winnerCount"];
    }
    return null;
  }

  Future<List<WinnerModel>?> getSelectedWinner({required String marathonId}) async {
    Map<String, String> params = <String, String>{"marathonId": marathonId};
    Response response = await ApiClient().getJsonForResponse(
      ApiConsts.marathonSelectedWinner,
      queryParameters: params,
      token: AppState().getMarathonToken == null || AppState().getMarathonToken == "" ? await getMarathonToken() : AppState().getMarathonToken,
    );

    var json = jsonDecode(response.body);
    logger.i("json in getSelectedWinner: $json");

    MarathonGenericModel marathonGenericModel = MarathonGenericModel.fromJson(json);

    if (marathonGenericModel.isSuccessful == true && marathonGenericModel.statusCode == 200 && marathonGenericModel.data != null) {
      List<WinnerModel> winners = <WinnerModel>[];
      List data = marathonGenericModel.data as List;

      for (Map<String, dynamic> winner in data) {
        winners.add(WinnerModel.fromJson(winner));
      }
      return winners;
    }
    return null;
  }

//  late HubConnection hubConnection;
// Future<void> buildHubConnection(BuildContext context, String prizeId) async {
//   HttpConnectionOptions httpOptions = HttpConnectionOptions(skipNegotiation: false, logMessageContent: true);
//   hubConnection = HubConnectionBuilder()
//       .withUrl(
//         ApiConsts.marathonHubConnectionUrl + "?employeeNumber=${AppState().memberInformationList!.eMPLOYEENUMBER ?? ""}&employeeName=${AppState().memberInformationList!.eMPLOYEENAME ?? ""}",
//         options: httpOptions,
//       )
//       .withAutomaticReconnect(
//         retryDelays: <int>[2000, 5000, 10000, 20000],
//       )
//       .configureLogging(
//         Logger("Logging"),
//       )
//       .build();
//   hubConnection.onclose(
//     ({Exception? error}) {
//       logger.i("onclose");
//     },
//   );
//   hubConnection.onreconnecting(
//     ({Exception? error}) {
//       logger.i("onreconnecting");
//     },
//   );
//   hubConnection.onreconnected(
//     ({String? connectionId}) {
//       logger.i("onreconnected");
//     },
//   );
//   if (hubConnection.state != HubConnectionState.Connected) {
//     await hubConnection.start();
//     logger.i("Started HubConnection");
//
//     await hubConnection.invoke(
//       "AddParticipant",
//       args: <Object>[
//         <String, dynamic>{
//           "employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER ?? "",
//           "employeeName": AppState().memberInformationList!.eMPLOYEENAME ?? "",
//           "marathonId": AppState().getMarathonProjectId,
//           "prizeId": "8577B2E8-5DD7-43F0-10DD-08DACB0AC064",
//         }
//       ],
//     ).catchError((e) {
//       logger.i("Error in AddParticipant: $e");
//     });
//
//     context.read<MarathonProvider>().addItemToList(ApiConsts.dummyQuestion);
//
//     await hubConnection.invoke(
//       "SendQuestionToParticipant",
//       args: <Object>[
//         <String, dynamic>{
//           "marathonId": "${AppState().getMarathonProjectId}",
//         }
//       ],
//     ).catchError((e) {
//       Utils.confirmDialog(context, e.toString());
//       logger.i("Error in SendQuestionToParticipant: $e");
//     });
//
//     try {
//       hubConnection.on("OnSendQuestionToParticipant", (List<Object?>? arguments) {
//         onSendQuestionToParticipant(arguments, context);
//       });
//     } catch (e, s) {
//       logger.i("Error in OnSendQuestionToParticipant");
//     }
//
//     try {
//       hubConnection.on("OnParticipantJoin", (List<Object?>? arguments) {
//         onParticipantJoin(arguments, context);
//       });
//     } catch (e, s) {
//       logger.i("Error in OnParticipantJoin");
//     }
//   }
// }
//
// Future<void> onSendQuestionToParticipant(List<Object?>? arguments, BuildContext context) async {
//   logger.i("onSendQuestionToParticipant arguments: $arguments");
//
//   if (arguments != null) {
//     Map<dynamic, dynamic> data = arguments.first! as Map<dynamic, dynamic>;
//     var json = data["data"];
//     QuestionModel newQuestion = QuestionModel.fromJson(json);
//     AppRoutes.navigatorKey.currentContext!.read<MarathonProvider>().onNewQuestionReceived(newQuestion);
//   }
// }
//
// Future<void> onParticipantJoin(List<Object?>? arguments, BuildContext context) async {
//   logger.i("OnParticipantJoin arguments: $arguments");
//   context.watch<MarathonProvider>().totalMarathoners++;
// }
}
