import 'dart:developer';
import 'package:flutter_tts/flutter_tts.dart';
import 'package:hmg_qline/constants/app_constants.dart';
import 'package:hmg_qline/models/global_config_model.dart';
import 'package:hmg_qline/models/ticket_model.dart';
import 'package:hmg_qline/services/logger_service.dart';
import 'package:hmg_qline/utilities/enums.dart';
import 'package:hmg_qline/utilities/extensions.dart';
import 'package:logger/logger.dart';

abstract class TextToSpeechService {
  Future<void> speechText({
    required TicketDetailsModel ticket,
    required GlobalConfigurationsModel globalConfigurationsModel,
    bool isMute = false,
  });

  // Future<void> speechTextTest(TicketData ticket);

  void listenToTextToSpeechEvents({required Function() onVoiceCompleted});
}

class TextToSpeechServiceImp implements TextToSpeechService {
  FlutterTts textToSpeechInstance;
  LoggerService loggerService;

  TextToSpeechServiceImp({required this.textToSpeechInstance, required this.loggerService});

  double volume = 1.0;
  double pitch = 0.6;
  Map<String, String> arabicVoice = {"name": "ar-xa-x-ard-local", "locale": "ar"};

  @override
  // Future<void> speechTextTest(TicketData ticket) async {
  //   const ttsGoogleEngine = 'com.google.android.tts';
  //   LanguageEnum langEnum = ticket.voiceLanguageEnum;
  //   List engines = await textToSpeechInstance.getEngines;
  //   if (engines.contains(ttsGoogleEngine)) {
  //     await textToSpeechInstance.setEngine(ttsGoogleEngine);
  //   }
  //
  //     textToSpeechInstance.setVolume(1.0);
  //
  //   // final voices = await textToSpeechInstance.getVoices;
  //   // log ("voices:: $voices");
  //
  //   await textToSpeechInstance.setVoice(arabicVoice);
  //
  //   if (langEnum == LanguageEnum.arabic) {
  //     try {
  //       await textToSpeechInstance.setLanguage(LanguageEnum.arabic.enumToString());
  //     } catch (e) {
  //       log("error setting language english: ${e.toString()}");
  //     }
  //   } else if (langEnum == LanguageEnum.english) {
  //     try {
  //       await textToSpeechInstance.setLanguage(LanguageEnum.english.enumToString());
  //     } catch (e) {
  //       log("error setting language english: ${e.toString()}");
  //     }
  //   }
  //   String preVoice = ticket.ticketNoText;
  //   String postVoice = ticket.postVoiceText;
  //   if (preVoice.isNotEmpty) {
  //     preVoice = '$preVoice..';
  //   }
  //   String ticketNo = ticket.queueNo!.trim().toString();
  //
  //   log("areLanguagesInstalled: ${await textToSpeechInstance.areLanguagesInstalled(["en", "ar"])}");
  //
  //   log("lang: $langEnum");
  //   log("preVoice: $preVoice");
  //   log("postVoice: $postVoice");
  //   log("ticketNo: $ticketNo");
  //
  //   String patientAlpha = "";
  //   String patientNumeric = "";
  //   String clinicName = "";
  //
  //   bool isClinicNameAdded = (ticket.queueNo != ticket.callNoStr);
  //
  //   if (isClinicNameAdded) {
  //     var queueNo = "";
  //     var clinic = ticketNo.split(" ");
  //     if (clinic.length > 1) {
  //       clinicName = clinic[0];
  //       queueNo = clinic[1];
  //     } else {
  //       queueNo = ticketNo;
  //     }
  //
  //     var queueNoArray = queueNo.split("-");
  //     if (queueNoArray.length > 2) {
  //       patientAlpha = "${queueNoArray[0]} .. ${queueNoArray[1]}";
  //       patientNumeric = queueNoArray[2];
  //     } else {
  //       patientAlpha = queueNoArray[0];
  //       patientNumeric = queueNoArray[1];
  //     }
  //   } else {
  //     var queueNoArray = ticketNo.split("-");
  //     if (queueNoArray.length > 2) {
  //       patientAlpha = "${queueNoArray[0]} .. ${queueNoArray[1]}";
  //       patientNumeric = queueNoArray[2];
  //     } else {
  //       patientAlpha = queueNoArray[0];
  //       patientNumeric = queueNoArray[1];
  //     }
  //   }
  //
  //   patientAlpha = patientAlpha.split('').join(' .. ');
  //   String roomNo = "";
  //
  //   log("I will now all this:{ $preVoice .. $clinicName .. $patientAlpha .. $patientNumeric .. $postVoice $roomNo } ");
  //
  //   if (langEnum == LanguageEnum.english) {
  //     await textToSpeechInstance.speak("$preVoice .. $clinicName .. $patientAlpha .. $patientNumeric .. $postVoice $roomNo");
  //     return;
  //   }
  //
  //   if (isNeedToBreakVoiceForArabic) {
  //     await textToSpeechInstance.awaitSpeakCompletion(true);
  //
  //     isSpeechCompleted = false;
  //     if (preVoice.isNotEmpty) {
  //       await textToSpeechInstance.speak("$preVoice ");
  //     }
  //     try {
  //       await textToSpeechInstance.setLanguage(LanguageEnum.english.enumToString());
  //     } catch (e) {
  //       log("error setting language english: ${e.toString()}");
  //     }
  //     await textToSpeechInstance.speak("$patientAlpha .. $patientNumeric");
  //
  //     try {
  //       await textToSpeechInstance.setLanguage(langEnum.enumToString());
  //     } catch (e) {
  //       log("error setting language langEnum: ${e.toString()}");
  //     }
  //
  //     await textToSpeechInstance.speak("$postVoice $roomNo").whenComplete(() {
  //       isSpeechCompleted = true;
  //     });
  //   } else {
  //     await textToSpeechInstance.speak("$preVoice .. $clinicName .. $patientAlpha .. $patientNumeric .. $postVoice $roomNo");
  //   }
  // }

  @override
  Future<void> speechText({
    required TicketDetailsModel ticket,
    required GlobalConfigurationsModel globalConfigurationsModel,
    bool isMute = false,
  }) async {
    log("ticket data i got: ${ticket.ticketModel.toString()}");
    const ttsGoogleEngine = 'com.google.android.tts';
    LanguageEnum langEnum = ticket.ticketModel!.voiceLanguageEnum;
    List engines = await textToSpeechInstance.getEngines;
    if (engines.contains(ttsGoogleEngine)) {
      await textToSpeechInstance.setEngine(ttsGoogleEngine);
    }

    log("engines: $engines");
    await textToSpeechInstance.setVoice(arabicVoice);

    if (isMute) {
      textToSpeechInstance.setVolume(0.0);
    } else {
      textToSpeechInstance.setVolume(1.0);
    }

    textToSpeechInstance.setSpeechRate(0.4);
    if (langEnum == LanguageEnum.arabic) {
      try {
        await textToSpeechInstance.setLanguage(LanguageEnum.arabic.enumToString());
      } catch (e) {
        log("error setting language english: ${e.toString()}");
      }
    } else if (langEnum == LanguageEnum.english) {
      try {
        await textToSpeechInstance.setLanguage(LanguageEnum.english.enumToString());
      } catch (e) {
        log("error setting language english: ${e.toString()}");
      }
    }
    String preVoice = ticket.ticketModel!.ticketNoText;
    String postVoice = '';
    if (globalConfigurationsModel.qTypeEnum == QTypeEnum.appointment) {
      postVoice = ticket.ticketModel!.callTypeEnum.getCallTextFromCallType(ticket.ticketModel!);
    } else {
      postVoice = ticket.ticketModel!.postVoiceText;
    }
    String roomNo = '';
    if (globalConfigurationsModel.qTypeEnum != QTypeEnum.appointment && ticket.ticketModel!.roomNo != null && ticket.ticketModel!.roomNo!.isNotEmpty) {
      roomNo = ".. ${ticket.ticketModel!.roomNo.toString()}";
    }

    if (preVoice.isNotEmpty) {
      preVoice = '$preVoice..';
    }

    String ticketNo = ticket.ticketModel!.queueNo!.trim().toString();

    log("areLanguagesInstalled: ${await textToSpeechInstance.areLanguagesInstalled(["en-US", "ar-SA"])}");
    log("lang: $langEnum");
    log("preVoice: $preVoice");
    log("postVoice: $postVoice");
    log("ticketNo: $ticketNo");

    String patientAlpha = "";
    String patientNumeric = "";
    String clinicName = "";

    bool isClinicNameAdded = (ticket.ticketModel?.queueNo != ticket.ticketModel?.callNoStr);

    if (isClinicNameAdded) {
      var queueNo = "";
      var clinic = ticketNo.split(" ");
      if (clinic.length > 1) {
        clinicName = clinic[0];
        queueNo = clinic[1];
      } else {
        queueNo = ticketNo;
      }

      var queueNoArray = queueNo.split("-");
      if (queueNoArray.length > 2) {
        patientAlpha = "${queueNoArray[0]} .. ${queueNoArray[1]}";
        patientNumeric = queueNoArray[2];
      } else {
        patientAlpha = queueNoArray[0];
        patientNumeric = queueNoArray[1];
      }
    } else {
      var queueNoArray = ticketNo.split("-");
      if (queueNoArray.length > 2) {
        patientAlpha = "${queueNoArray[0]} .. ${queueNoArray[1]}";
        patientNumeric = queueNoArray[2];
      } else {
        patientAlpha = queueNoArray[0];
        patientNumeric = queueNoArray[1];
      }
    }

    patientAlpha = patientAlpha.split('').join(' .. ');

    log("I will now all this:{ $preVoice .. $clinicName .. $patientAlpha .. $patientNumeric .. $postVoice $roomNo } ");

    if (langEnum == LanguageEnum.english) {
      await textToSpeechInstance.speak("$preVoice .. $clinicName .. $patientAlpha .. $patientNumeric .. $postVoice $roomNo");
      return;
    }

    if (isNeedToBreakVoiceForArabic) {
      await textToSpeechInstance.awaitSpeakCompletion(true);

      isSpeechCompleted = false;
      if (preVoice.isNotEmpty) {
        await textToSpeechInstance.speak("$preVoice ");
      }
      try {
        await textToSpeechInstance.setLanguage(LanguageEnum.english.enumToString());
      } catch (e) {
        log("error setting language english: ${e.toString()}");
      }
      await textToSpeechInstance.speak("$patientAlpha .. $patientNumeric");

      try {
        await textToSpeechInstance.setLanguage(langEnum.enumToString());
      } catch (e) {
        log("error setting language langEnum: ${e.toString()}");
      }

      await textToSpeechInstance.speak("$postVoice $roomNo").whenComplete(() {
        isSpeechCompleted = true;
      });
    } else {
      await textToSpeechInstance.speak("$preVoice .. $clinicName .. $patientAlpha .. $patientNumeric .. $postVoice $roomNo");
    }
  }

  @override
  void listenToTextToSpeechEvents({required Function() onVoiceCompleted}) {
    textToSpeechInstance.setCompletionHandler(onVoiceCompleted);

    textToSpeechInstance.setErrorHandler((message) {
      loggerService.logInfo("setErrorHandler: $message\nCompleting the voice for now");
      isSpeechCompleted = true;
      onVoiceCompleted();
    });

    textToSpeechInstance.setPauseHandler(() {
      loggerService.logInfo("setPauseHandler");
    });

    textToSpeechInstance.setCancelHandler(() {
      loggerService.logInfo("setCancelHandler");
    });
  }
}
