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

import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:electronic_assistant/base/base_controller.dart';
import 'package:electronic_assistant/data/consts/event_report_id.dart';
import 'package:electronic_assistant/data/repositories/account_repository.dart';
import 'package:electronic_assistant/data/repositories/task_repository.dart';
import 'package:electronic_assistant/utils/audio_picker_utils.dart';
import 'package:electronic_assistant/handler/event_handler.dart';
import 'package:electronic_assistant/module/chat/view.dart';
import 'package:electronic_assistant/module/login/view.dart';
import 'package:electronic_assistant/module/store/view.dart';
import 'package:electronic_assistant/module/talk/summary/view.dart';
import 'package:electronic_assistant/module/talk/todo/controller.dart';
import 'package:electronic_assistant/module/talk/todo/view.dart';
import 'package:electronic_assistant/resource/assets.gen.dart';
import 'package:electronic_assistant/resource/colors.gen.dart';
import 'package:electronic_assistant/resource/string.gen.dart';
import 'package:electronic_assistant/utils/error_handler.dart';
import 'package:electronic_assistant/utils/expand.dart';
import 'package:electronic_assistant/utils/file_upload_check_helper.dart';
import 'package:electronic_assistant/utils/mmkv_util.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:just_audio/just_audio.dart';
import 'package:wakelock_plus/wakelock_plus.dart';

import '../../data/api/request/agenda_update_bean.dart';
import '../../data/bean/agenda.dart';
import '../../data/bean/agenda_list_all_bean.dart';
import '../../data/bean/talks.dart';
import '../../data/repositories/agenda_repository.dart';
import '../../data/repositories/talk_repository.dart';
import '../../dialog/add_agenda_dialog.dart';
import '../../dialog/alert_dialog.dart';
import '../../utils/event_bus.dart';
import '../../utils/toast_util.dart';
import '../record/controller.dart';
import 'original/view.dart';

class TalkController extends BaseController {
  static const String argumentItem = 'argument_item';
  static const String argumentEventTag = 'argument_event_tag';

  final String uploadNoPrompts = "UPLOAD_NO_PROMPTS";

  final Rxn<TalkBean> talkBean = Rxn();

  final isShowElectricLow = false.obs;

  bool isAudioLoading = false;

  final double sliderMax = 1;

  bool? audioFileIsExist;

  bool? isUploadedFile;

  Rxn<bool> isUploading = Rxn();

  final isAudioPlaying = false.obs;

  final audioProgressValue = 0.0.obs;

  final audioDuration = Duration.zero.obs;

  final agendaOriginalAllList = <AgendaListAllBean>[];

  final agendaAllList = <AgendaListAllBean>[].obs;

  final _isEditModel = false.obs;

  final TextEditingController editTalkNameController = TextEditingController();

  final tabIndex = 0.obs;

  final List<String> tabBeans = [
    StringName.talkTabSummary.tr,
    StringName.talkTabMyTask.tr,
    StringName.talkTabOriginal.tr
  ];

  bool get isEditModel => _isEditModel.value;

  RxBool get isEditModelRx => _isEditModel;

  final _audioPlayer = AudioPlayer();

  StreamSubscription? _talkBeanListener;

  final pages = [const SummaryView(), const TodoView(), const OriginalView()];

  TextEditingController? _agendaContentController;
  TextEditingController? _agendaNameController;

  TextEditingController get agendaContentController {
    _agendaContentController ??= TextEditingController();
    return _agendaContentController!;
  }

  TextEditingController get agendaNameController {
    _agendaNameController ??= TextEditingController();
    return _agendaNameController!;
  }

  String? eventTag;

  bool isLocalFileHas = false;

  @override
  void onReady() {
    super.onReady();

    _initAudioPlayer();
    _initListener();
    _getArguments();
    eventReport(EventId.event_101001, params: {EventId.id: eventTag});
  }

  RxDouble getUploadingProgress() {
    return talkRepository.getUploadProgress(talkBean.value!.id);
  }

  void eventReport(String eventId, {Map<String, dynamic>? params}) {
    if (talkBean.value == null || talkBean.value?.isExample == true) {
      return;
    }
    EventHandler.report(eventId, params: params);
  }

  void _initAudioPlayer() {
    _audioPlayer.playerStateStream.listen((playerState) {
      if (playerState.processingState == ProcessingState.loading ||
          playerState.processingState == ProcessingState.buffering) {
        isAudioLoading = true;
        debugPrint('音频load = true');
      } else {
        debugPrint('音频load = false');
        isAudioLoading = false;
        if (playerState.processingState == ProcessingState.completed) {
          _audioPlayer.stop();
          _audioPlayer.seek(Duration.zero);
          isAudioPlaying.value = false;
          debugPrint('音频 播放结束了');
        }
      }
      isAudioPlaying.value = playerState.playing;
    }, onError: (Object e, StackTrace stackTrace) {
      debugPrint('音频加载异常 == $e');
    });

    _audioPlayer.durationStream.listen((duration) {
      if (duration != null) {
        debugPrint('音频总播放时长 == ${duration.inMilliseconds}');
        audioDuration.value = duration;
      }
    });

    _audioPlayer.positionStream.listen((position) {
      if (audioDuration.value.inMilliseconds > 0) {
        audioProgressValue.value =
            (position.inMilliseconds / audioDuration.value.inMilliseconds)
                .clamp(0.0, sliderMax);
      }
    });
  }

  void _initListener() {
    _talkBeanListener = talkBean.listen((bean) {
      _dealTalkUpdate(bean);
    });
  }

  void _dealTalkUpdate(TalkBean? bean) async {
    String? id = talkBean.value?.id;
    if (id == null) {
      return;
    }
    if (talkRepository.isUploadingTalk(id) &&
        talkBean.value?.status.value == TalkStatus.notAnalysis) {
      isUploading.value = true;
    } else {
      isUploading.value = false;
    }
    _loadAudioFile(bean);
  }

  Future<void> _loadAudioFile(TalkBean? bean, {bool? loadPlay}) async {
    try {
      Uri? uri;
      if (bean?.isExample == true && bean?.audioUrl != null) {
        uri = Uri.parse(bean!.audioUrl!);
      } else {
        File? file = await getFileByTalk(talkBean.value);
        if (file?.existsSync() == true) {
          uri = file?.uri;
        }
      }
      if (uri == null) {
        throw '音频文件不存在';
      }
      await _audioPlayer.setAudioSource(AudioSource.uri(uri));
      if (loadPlay == true) {
        clickPlayAudio();
      }
      audioFileIsExist = true;
    } catch (e) {
      audioFileIsExist = false;
      debugPrint('音频设置异常 == $e');
    }
  }

  void _getArguments() {
    TalkBean? bean = parameters?[argumentItem];
    if (bean != null) {
      talkBean.value = bean;
    }
    eventTag = parameters?[argumentEventTag];
  }

  void updateProgress(double value) {
    final newPosition = Duration(
        milliseconds: (value * audioDuration.value.inMilliseconds).toInt());
    _audioPlayer.seek(newPosition);
  }

  void clickPlayAudio() async {
    if (audioFileIsExist != true && isLocalFileHas == false) {
      ToastUtil.showToast(StringName.talkFileNotFind.tr);
      return;
    }
    if (isLocalFileHas == true &&
        audioFileIsExist == false &&
        !await AudioPickerUtils.hasPermission()) {
      bool has = await AudioPickerUtils.requestPermissionExtend();
      if (has == false) {
        ToastUtil.showToast(StringName.authorizationFailed.tr);
        return;
      }
      //重新加载
      _loadAudioFile(talkBean.value, loadPlay: true);
      return;
    }
    if (isAudioLoading) {
      ToastUtil.showToast(StringName.talkAudioLoading.tr);
      return;
    }
    if (_audioPlayer.playing) {
      _audioPlayer.pause();
      isAudioPlaying.value = false;
    } else {
      _audioPlayer.play();
      isAudioPlaying.value = true;
    }
  }

  void _checkFileSizeAndNet() async {
    String? id = talkBean.value?.id;
    if (id == null) {
      return;
    }
    File? file = await getFileByTalk(talkBean.value);
    if (isLocalFileHas == true &&
        audioFileIsExist == false &&
        !await AudioPickerUtils.hasPermission()) {
      bool has = await AudioPickerUtils.requestPermissionExtend();
      if (has == false) {
        ToastUtil.showToast(StringName.authorizationFailed.tr);
        return;
      }
      //重新上传
      _checkFileSizeAndNet();
      return;
    }
    if (file == null || !file.existsSync()) {
      ToastUtil.showToast(StringName.talkUploadFileNotExist.tr);
      return;
    }
    bool isCheckRemind = KVUtil.getBool(uploadNoPrompts, false);
    if (isCheckRemind) {
      _requestAnalyze(file);
      return;
    }
    //如果文件大小低于250MB 不弹窗提醒
    if (file.lengthSync() < 250 * 1024 * 1024) {
      _requestAnalyze(file);
      return;
    }

    final List<ConnectivityResult> connectivityResult =
        await (Connectivity().checkConnectivity());
    if (connectivityResult.contains(ConnectivityResult.wifi)) {
      _requestAnalyze(file);
    } else {
      _showTrafficRemindDialog(file.lengthSync().toReadableSize(),
          confirmOnTap: (isCheckRemind) {
        if (isCheckRemind) {
          KVUtil.putBool(uploadNoPrompts, true);
        }
        _requestAnalyze(file);
      });
    }
  }

  void _showTrafficRemindDialog(String holderTxt,
      {void Function(bool isCheckRemind)? confirmOnTap}) {
    final remindTrafficConsume = false.obs;

    Widget getSelectIcon() {
      return Obx(() {
        return remindTrafficConsume.value
            ? Assets.images.iconSelectTrue.image()
            : Assets.images.iconSelectFalse.image();
      });
    }

    Assets.images.iconSelectTrue.image();

    EAAlertDialog.show(
        contentWidget: Column(
          children: [
            Text(
              StringName.talkTrafficRemindTitle.tr
                  .replacePlaceholders([holderTxt]),
              style:
                  TextStyle(fontSize: 15.sp, color: ColorName.primaryTextColor),
            ),
            SizedBox(height: 8.h),
            GestureDetector(
              onTap: () {
                remindTrafficConsume.value = !remindTrafficConsume.value;
              },
              child: IntrinsicWidth(
                child: Row(
                  children: [
                    SizedBox(width: 20.w, height: 20.w, child: getSelectIcon()),
                    SizedBox(width: 5.w),
                    Text(
                      StringName.talkTrafficRemindTips.tr,
                      style: TextStyle(
                          fontSize: 15.sp, color: ColorName.tertiaryTextColor),
                    )
                  ],
                ),
              ),
            )
          ],
        ),
        cancelText: StringName.cancel.tr,
        confirmText: StringName.sure.tr,
        confirmOnTap: () {
          confirmOnTap?.call(remindTrafficConsume.value);
        });
  }

  void checkCanAnalyze() {
    String? id = talkBean.value?.id;
    double? duration = talkBean.value?.duration;
    if (id == null || duration == null) {
      return;
    }
    eventReport(EventId.event_101002);
    talkRepository.checkElectric(duration).then((data) {
      if (data.enough) {
        //检查网络以及文件大小
        _checkFileSizeAndNet();
      } else {
        ToastUtil.showToast(StringName.talkAnalyseLowToast.tr);
        isShowElectricLow.value = true;
      }
    }).catchError((error) {
      ToastUtil.showToast(error);
    });
  }

  void _requestAnalyze(File file) {
    String? talkId = talkBean.value?.id;
    double? duration = talkBean.value?.duration;

    if (talkId == null || duration == null || isUploadedFile == true) {
      return;
    }
    isUploading.value = true;
    WakelockPlus.enable();
    talkRepository.uploadTalkFile(talkId, duration, file).then((taskId) {
      isUploadedFile = true;
      talkBean.value?.status.value = TalkStatus.analysing;
      taskRepository.addTask(taskId);
    }).catchError((error) {
      isUploading.value = false;
      ErrorHandler.toastError(error);
    }).whenComplete(() => WakelockPlus.disable());
  }

  void refreshAgendaAllData({bool isForceRefresh = false}) {
    String? id = talkBean.value?.id;
    if (id == null || (!isForceRefresh && agendaAllList.isNotEmpty)) {
      return;
    }
    agendaRepository.agendaListAll(id).then((agenda) {
      agendaAllList.clear();
      agendaOriginalAllList.clear();
      if (agenda.list != null) {
        agendaOriginalAllList.addAll(
            agenda.list!.map((item) => AgendaListAllBean.from(item)).toList());
        agendaAllList.addAll(agenda.list!);
      }
    });
  }

  void clickAIAnalysis() {
    if (!accountRepository.isLogin.value) {
      LoginPage.start(fromType: LoginFromType.talkDetail);
      return;
    }
    if (talkBean.value != null) {
      eventReport(EventId.event_101003);
      ChatPage.startByTalk(
          talkBean.value!.isExample == true
              ? ChatFromType.fromTalkExample
              : ChatFromType.fromTalkDetail,
          talkBean.value!);
    }
  }

  void onGoElectricStore() {
    StorePage.start(fromType: StoreFromType.analyse);
    Future.delayed(const Duration(milliseconds: 250), () {
      isShowElectricLow.value = false;
    });
  }

  void onEditModelClick() {
    if (!accountRepository.isLogin.value) {
      LoginPage.start(fromType: LoginFromType.talkDetail);
      return;
    }

    _isEditModel.value = true;
    if (_audioPlayer.playing) {
      _audioPlayer.pause();
      isAudioPlaying.value = false;
    }
    editTalkNameController.text = talkBean.value?.title.value ?? '';
  }

  void updateTabIndex(int index) {
    tabIndex.value = index;
  }

  void onEditCancel() {
    _isEditModel.value = false;
    agendaAllList.assignAll(agendaOriginalAllList
        .map((item) => AgendaListAllBean.from(item))
        .toList());
  }

  void onEditDoneClick() {
    if (talkBean.value == null) {
      return;
    }
    List<AgendaUpdateBean> list = [];
    for (AgendaListAllBean item in agendaAllList) {
      if (item.list != null) {
        for (Agenda agenda in item.list!) {
          list.add(AgendaUpdateBean(agenda.id, agenda.name, agenda.content));
        }
      }
    }
    agendaRepository.agendaUpdate(talkBean.value!.id, list).then((data) {
      refreshAgendaAllData(isForceRefresh: true);
      eventBus.emit(TodoController.refreshTalkMineTask);
      isEditModelRx.value = false;
    }).catchError((error) {
      ErrorHandler.toastError(error);
    });
    if (tabIndex.value == 0) {
      String updateName = editTalkNameController.text;
      talkRepository.talkRename(talkBean.value!.id, updateName).then((data) {
        talkBean.value?.title.value = updateName;
      }).catchError((error) {
        ErrorHandler.toastError(error);
      });
    }
  }

  void removeTalkAgenda(List<Agenda>? list, Agenda agenda) {
    list?.remove(agenda);
    agendaAllList.refresh();
  }

  void showSingleAddAgendaDialog(BuildContext context) {
    showAddAgendaDialog(context, agendaContentController, agendaNameController,
        list: agendaAllList.map((e) => e.name ?? "").toList(), callback: () {
      if (agendaContentController.text.isEmpty) {
        ToastUtil.showToast(StringName.talkAddAgendaContentHint.tr);
        return;
      }
      if (agendaNameController.text.isEmpty) {
        ToastUtil.showToast(StringName.talkAddAgendaNameHint.tr);
        return;
      }
      Get.back();
      _dealAddProcedureList();
    });
  }

  void _dealAddProcedureList() {
    String name = agendaNameController.text;
    final addItem = Agenda(
      id: "",
      talkId: "",
      name: name,
    );
    addItem.content = agendaContentController.text;
    for (AgendaListAllBean item in agendaAllList) {
      if (item.name == name) {
        List<Agenda> list = item.list ?? [];
        list.add(addItem);
        item.list = list;
        agendaAllList.refresh();
        agendaContentController.clear();
        agendaNameController.clear();
        return;
      }
    }
    agendaAllList.add(AgendaListAllBean(name: name, list: [addItem]));
    agendaContentController.clear();
    agendaNameController.clear();
  }

  Future<File?> getFileByTalk(TalkBean? bean) async {
    isLocalFileHas = false;
    if (bean == null) {
      return null;
    }
    if (bean.uploadType == TalkUploadType.localUpload) {
      String? audioId =
          FileUploadCheckHelper.getLocalAudioId(bean.localAudioUrl);
      if (audioId != null && audioId.isNotEmpty) {
        isLocalFileHas = true;
        return await AudioPickerUtils.getAssetFile(audioId);
      } else {
        return await FileUploadCheckHelper.getChoiceUploadFile(bean.id);
      }
    } else {
      return await RecordController.getRecordFile(bean.id);
    }
  }

  @override
  void onClose() {
    super.onClose();
    _talkBeanListener?.cancel();
    _audioPlayer.dispose();
    _agendaContentController?.dispose();
    _agendaNameController?.dispose();
  }
}
