import 'dart:async';
import 'dart:io';

import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:just_audio/just_audio.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:rxdart/rxdart.dart';
import 'package:voice_buddies/app/models/common_model.dart';
import 'package:voice_buddies/app/models/login_model.dart';
import 'package:voice_buddies/app/models/search_model.dart';
import 'package:voice_buddies/app/utils/all_imports.dart';
import 'package:voice_buddies/app/widget/base_controller.dart';

import '../../../widget/common_seekbar.dart';

class UserProfileController extends BaseController {
  AudioPlayer player = AudioPlayer();
  AudioPlayer recordingPlayer = AudioPlayer();
  List<CommonModel> messages = [];
  bool isRecordingAvailable = false;
  List<CommonModel> userDetails = [];

  String urlName = "https://codeskulptor-demos.commondatastorage.googleapis.com/pang/paza-moduless.mp3";

  List<CommonModel> suggestionList = [
    CommonModel(image: AppImages.icGreenMike, name: AppStrings.tapGreenMike),
    CommonModel(image: AppImages.icGreenPause, name: AppStrings.tapGreenPause),
    CommonModel(image: AppImages.icGreenPlay, name: AppStrings.tapGreenPlay),
    CommonModel(image: AppImages.icGreenSend, name: AppStrings.tapGreenSend),
  ];

  /// sendChatMediaApi
  sendChatMediaApi() async {
    FormData formData = FormData.fromMap({
      "media": MultipartFile.fromFileSync(path!, filename: path!.split("/").last),
      "user_id": loginData?.userId ?? 0,
      "receiver_id": searchResult.userId.toString(),
    });

    final data = await APIFunction().apiCall(apiName: Constants.sendChatMedia, params: formData);

    LoginDataModel model = LoginDataModel.fromJson(data);

    if (model.responseCode == 1) {
      sendNewMessage(
        message: model.data?.name,
        senderId: loginData?.userId.toString(),
        receiverId: searchResult.userId.toString(),
        createdAt: DateTime.now().toUtc().toString().split(".").first,
      );
      utils.showCustomToast(message: AppStrings.yourMessageHasBeenSent, context: Get.context!);
    } else {
      utils.showSnackBar(message: model.responseMsg!, statusCode: model.responseCode);
    }
  }

  /// record
  String? path;
  Directory? appDirectory;
  bool isRecording = false;
  RecorderController? recorderController;
  PlayerController? playerController;
  File? file;
  Duration maxDuration = const Duration();
  Timer? timer;
  bool isPlayButtonShow = false;

  SearchResult searchResult = SearchResult();
  @override
  void onInit() {
    if (Get.arguments != null) {
      searchResult = Get.arguments;
      userDetails = [
        CommonModel(
          name: AppStrings.gender,
          details: searchResult.gender ?? "Male",
        ),
        CommonModel(
          name: AppStrings.age,
          details: searchResult.age ?? "20",
        ),
        CommonModel(
          name: AppStrings.currentlyIAm,
          details: searchResult.iAm ?? "In-between Jobs",
        ),
        CommonModel(
          name: AppStrings.whereILive,
          details: searchResult.iLive ?? "Asia",
        ),
        CommonModel(
          name: AppStrings.spokenLanguages,
          details: searchResult.spoken ?? "Russian, Korean, Other",
        ),
      ];
      urlName = searchResult.voice ?? "https://codeskulptor-demos.commondatastorage.googleapis.com/pang/paza-moduless.mp3";
    }
    player.setAudioSource(AudioSource.uri(Uri.parse(urlName)));

    getDir();
    initialiseControllers();
    playerController = PlayerController();
    super.onInit();
  }

  sendNewMessage({message, senderId, receiverId, createdAt}) async {
    if (Constants.socket!.connected) {
      Constants.socket!.emit(Constants.sendMessage, [message, senderId, receiverId, createdAt]);
      update();
      printAction("new message sent");
    }

    update();
  }

  Stream<PositionData> get positionDataStream {
    return Rx.combineLatest3<Duration, Duration, Duration?, PositionData>(
      player.positionStream,
      player.bufferedPositionStream,
      player.durationStream,
      (position, bufferedPosition, duration) => PositionData(
        position,
        bufferedPosition,
        duration ?? Duration.zero,
      ),
    );
  }

  Stream<PositionData> get positionDataStreamRecording {
    return Rx.combineLatest3<Duration, Duration, Duration?, PositionData>(
      recordingPlayer.positionStream,
      recordingPlayer.bufferedPositionStream,
      recordingPlayer.durationStream,
      (position, bufferedPosition, duration) => PositionData(
        position,
        bufferedPosition,
        duration ?? Duration.zero,
      ),
    );
  }

  startOrStopRecording() async {
    player.playing ? player.pause() : null;
    recordingPlayer.playing ? recordingPlayer.pause() : null;
    // final hasPermission = await recorderController?.checkPermission();
    if (isRecording) {
      printAction("stop record");
      await recorderController!.stop(false);
      isRecording = false;
      stopTimer(resets: false);
      isRecordingAvailable = true;
      loadRecordingToPlayer();
      update();
    } else {
      playerController?.startPlayer(finishMode: FinishMode.stop);
      playerController?.stopPlayer();
      printAction("start recording");
      isRecording = true;
      startTimerCount();
      printAction("------isRecording------$path>>>>> $isRecording");
      await recorderController!.record(
        path: path!,
        sampleRate: 24000,
        bitRate: 16000,
        androidEncoder: AndroidEncoder.aac,
      );
      utils.showCustomToast(message: AppStrings.recordingStarted, context: Get.context!);
      update();
      printAction("------------$path>>>>> $path");
    }
    update();
  }

  loadRecordingToPlayer() async {
    utils.showCustomToast(message: AppStrings.recordingStop, context: Get.context!);
    if (path != null) {
      await recordingPlayer.setAudioSource(AudioSource.file(path!));
      printAction("recording path in controller=$path");

      update();
    } else {
      update();
    }
  }

  void startTimerCount() {
    printAction("timer started");
    timer = Timer.periodic(const Duration(seconds: 1), (_) => addTime());
  }

  Future<void> addTime() async {
    const addSeconds = 1;

    final seconds = maxDuration.inSeconds + addSeconds;
    if (seconds < 0 || seconds >= 21) {
      await recorderController!.stop(false);
      isRecording = false;
      stopTimer(resets: false);
      isRecordingAvailable = true;
      loadRecordingToPlayer();
      isPlayButtonShow = true;
    } else {
      maxDuration = Duration(seconds: seconds);
    }
    printAction(maxDuration.inSeconds.toString());
    update();
  }

  void reset() {
    maxDuration = const Duration();
    update();
  }

  void stopTimer({bool resets = true}) {
    if (resets) {
      reset();
    }
    timer?.cancel();
    update();
  }

  initialiseControllers() {
    recorderController = RecorderController()
      ..androidEncoder = AndroidEncoder.aac
      ..androidOutputFormat = AndroidOutputFormat.mpeg4
      ..iosEncoder = IosEncoder.kAudioFormatMPEG4AAC
      ..sampleRate = 44100;
  }

  getDir() async {
    appDirectory = await getApplicationDocumentsDirectory();
    path = "${appDirectory!.path}/voiceBuddiesRecording.m4a";

    printAction("--path---------------->> $path");
    checkPermission();
    update();
  }

  checkPermission() async {
    final status = await Permission.microphone.request();
    printAction("statusstatusstatus");
    printAction(status.toString());
    if (status.isGranted) {
      printAction("isGranted");
    } else if (status.isPermanentlyDenied) {
      await openAppSettings();
      Get.back();
      printAction("isPermanentlyDenied");
    } else if (status.isDenied) {
      await openAppSettings();
      Get.back();
    }
    update();
  }

  // preparePlayer() async {
  //   playerController!.preparePlayer(path: path!, shouldExtractWaveform: true, volume: 1.0, noOfSamples: 100);
  //   playerController!
  //       .extractWaveformData(
  //     path: path!,
  //   )
  //       .then((waveformData) async {
  //     playerController?.startPlayer(finishMode: FinishMode.stop);
  //   });
  // }

  @override
  void onClose() {
    timer?.cancel();
    recordingPlayer.stop();
    player.stop();
    recorderController?.stop(true);

    super.onClose();
  }

  @override
  void dispose() {
    timer?.cancel();
    recordingPlayer.stop();
    player.stop();
    recorderController?.stop(true);
    super.dispose();
  }
}
