import 'package:audio_session/audio_session.dart';
import 'package:fis_common/env/env.dart';
import 'package:fis_common/logger/logger.dart';
import 'package:fis_i18n/i18n.dart';
import 'package:fis_lib_report/report_info/input_text_info.dart';
import 'package:fis_ui/base_define/page.dart';
import 'package:fis_ui/index.dart';
import 'package:fis_ui/values/font_sizes.dart';
import 'package:fis_ui/values/spacings.dart';
import 'package:fis_ui/widgets/progressbar/progress_indicator.dart';
import 'package:flutter/material.dart';
import 'package:flutter_sound/flutter_sound.dart';
import 'package:flyinsono/architecture/router/index.dart';
import 'package:flutter_sound_platform_interface/flutter_sound_recorder_platform_interface.dart'
    as recorderInterface;
import 'package:flyinsono/managers/interfaces/report.dart';
import 'package:flyinsono/rpc.dart';
import 'package:get/get.dart';
import 'package:universal_html/html.dart' as html;
import 'package:http/http.dart' as http;
import 'package:uuid/uuid.dart';

const theSource = recorderInterface.AudioSource.microphone;

class SpeechInput extends FStatefulWidget implements FPage {
  final String pageName;
  final InputTextInfo? inputTextInfo;
  final TextEditingController? textEditingController;
  final void Function(String)? onSubmit;

  SpeechInput(
    this.inputTextInfo, {
    this.textEditingController,
    this.pageName = "SpeechInput",
    this.onSubmit,
  });

  @override
  _SpeechInputState createState() => _SpeechInputState();
}

class _SpeechInputState extends FState<SpeechInput>
    with SingleTickerProviderStateMixin {
  final double _maxWidth = 400;
  final int _countdownDuration = 56;
  final double _lineProcessHeight = 8;
  final double _hintTextHeight = 25;
  TextEditingController _textEditingController = TextEditingController();
  late final FlutterSoundPlayer _mPlayer;
  late final FlutterSoundRecorder _mRecorder;
  late final AnimationController _animationController;
  late final Tween<double> _tween;
  late final String _fileExtension;
  AudioRecorderState? _audioState;
  Codec _codec = Codec.mp3;
  String _mPath = 'tau_file.mp3';

  @override
  void initState() {
    _audioState = null;
    super.initState();
    _fileExtension = FPlatform.isPureWeb ? "mp3" : "wav";
    _tween = Tween(begin: 1.0, end: 0.0);
    _animationController = AnimationController(
      duration: Duration(seconds: _countdownDuration),
      vsync: this,
    )..addListener(() {
        setState(() {});
      });
    _initRecord();
    if (widget.textEditingController != null) {
      _textEditingController = widget.textEditingController!;
    } else if (widget.inputTextInfo != null) {
      _textEditingController.text = widget.inputTextInfo!.text;
    }
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }

  @override
  FWidget build(BuildContext context) {
    return FSimpleDialog(
      title: FText(
        i18nBook.remedical.speechInput.t,
        style: TextStyle(
          color: Colors.white,
          fontSize: FFontSizes.H5,
        ),
      ),
      okString: i18nBook.common.confirm.t,
      cancelString: i18nBook.common.cancel.t,
      contentPadding: EdgeInsets.all(FSpacings.XXL),
      isDefault: true,
      children: [
        _buildAudioTextInput(),
        const FSizedBox(height: FSpacings.L),
        if (_audioState == AudioRecorderState.Recording) ...[
          _buildLinearProgressIndicator(),
          _buildEndSecondsHint(),
        ] else ...[
          FSizedBox(
            height: _hintTextHeight + _lineProcessHeight,
          )
        ],
        const FSizedBox(height: FSpacings.M),
        _buildPrimaryButton(),
      ],
      onCancel: () async {
        await _secondaryConfirmation(() {
          router.back();
        });
      },
      onOk: () async {
        if (_audioState == AudioRecorderState.Recording ||
            _audioState == AudioRecorderState.Identifying) {
          await _secondaryConfirmation(() {
            router.back();
          });
        } else {
          widget.inputTextInfo?.text = _textEditingController.text;
          router.back();
        }
      },
      onClose: () async {
        await _secondaryConfirmation(() {
          router.back();
        });
      },
    );
  }

  ///主按钮，开始录音、结束录音
  FWidget _buildPrimaryButton() {
    var primaryButtonText = i18nBook.remedical.startRecording.t;
    if (_audioState == AudioRecorderState.Recording) {
      primaryButtonText = i18nBook.remedical.endRecording.t;
    } else if (_audioState == AudioRecorderState.Identifying) {
      primaryButtonText = i18nBook.remedical.identifying.t;
    }
    return FAlign(
      alignment: Alignment.center,
      child: FPrimaryButton(
        onPressed: ((FPlatform.isWindows || FPlatform.isMacOS) ||
                _audioState != AudioRecorderState.Identifying)
            ? onRercordChange
            : null,
        text: primaryButtonText,
      ),
    );
  }

  //录音倒计时显示
  FWidget _buildLinearProgressIndicator() {
    return FConstrainedBox(
      constraints: BoxConstraints(
        maxWidth: _maxWidth,
        maxHeight: _lineProcessHeight,
        minHeight: _lineProcessHeight,
      ),
      child: FRow(
        children: [
          FExpanded(
            child: FLinearProgressIndicator(
              minHeight: FSpacings.M,
              value: _tween.evaluate(_animationController),
            ),
          ),
        ],
      ),
    );
  }

  ///倒计时文字提示
  FWidget _buildEndSecondsHint() {
    var endSeconds =
        (_tween.evaluate(_animationController) * (_countdownDuration + 4))
            .toInt();

    if (endSeconds < 1) {
      onRercordChange();
    }
    return FSizedBox(
      height: _hintTextHeight,
      child: FAlign(
        alignment: Alignment.centerRight,
        child: FText(
          i18nBook.remedical.endSeconds.translate([endSeconds]),
        ),
      ),
    );
  }

  FWidget _buildAudioTextInput() {
    return FSizedBox(
      width: _maxWidth,
      child: FTextField(
        controller: _textEditingController,
        readOnly: [AudioRecorderState.Recording, AudioRecorderState.Identifying]
            .contains(_audioState),
        maxLines: 5,
        decoration: InputDecoration(
          contentPadding: EdgeInsets.all(FSpacings.M),
          hintText: _audioState == AudioRecorderState.Identifying
              ? i18nBook.remedical.identifying.t
              : null,
          border: const OutlineInputBorder(),
        ),
        textAlignVertical: TextAlignVertical.top,
      ),
    );
  }

  ///-------------------------------------------UI逻辑&方法部分--------------------------------

  ///离开二次确认
  Future<void> _secondaryConfirmation(VoidCallback? onConfirm) async {
    if (_audioState == AudioRecorderState.Recording ||
        _audioState == AudioRecorderState.Identifying) {
      FConfirmAlert.show(
        context: Get.context!,
        title: i18nBook.common.tip.t,
        subTitle: i18nBook.common.leaveCurrentPage.t,
        confrimLabel: i18nBook.common.confirm.t,
        cancelLabel: i18nBook.common.cancel.t,
        businessParent: this.widget,
        onConfirm: onConfirm,
      );
    } else {
      router.back();
    }
  }

  Future<void> onRercordChange() async {
    if (_audioState == null) {
      return;
    }
    switch (_audioState!) {
      case AudioRecorderState.Init:
        setState(() {
          _audioState = AudioRecorderState.Recording;
        });

        break;
      case AudioRecorderState.Recording:
        setState(() {
          _audioState = AudioRecorderState.Identifying;
        });

        break;
      case AudioRecorderState.Identifying:
        break;
    }
    if (_audioState == AudioRecorderState.Recording) {
      _animationController.forward();
    } else {
      _animationController.reset();
    }
    if (FPlatform.isPureWeb) {
      if (_mRecorder.isStopped) {
        await _record();
      } else {
        await _stopRecorder();
      }
    } else if (FPlatform.isMacOS || FPlatform.isWindows) {
      if (_audioState == AudioRecorderState.Recording) {
        _startShellRecord();
      } else {
        await _stopRecorder();
      }
    }
  }

  void _startShellRecord() {
    rpc.platform.startShellRecord();
  }

  Future<void> _record() async {
    await _mRecorder.startRecorder(
      toFile: _mPath,
      codec: _codec,
      audioSource: theSource,
    );
    setState(() {});
  }

  Future<void> _stopRecorder() async {
    if (FPlatform.isPureWeb) {
      await _mRecorder.stopRecorder();

      ///停止录制后需将缓存转为MP3格式音频
      Future.delayed(Duration(milliseconds: 100), () async {
        await _uploadAudioFile();
        setState(() {
          _audioState = AudioRecorderState.Init;
        });
      });
    } else {
      var base64 = await rpc.platform.stopShellRecord();
      if (base64.isNotEmpty) {
        var fileToken = await rpc.storage
                .uploadBase64File(base64, Uuid().v4() + '.' + _fileExtension) ??
            '';
        if (fileToken.isNotEmpty) {
          await _commitASRInfoAsync(fileToken);
        }
      } else {
        setState(() {
          _audioState = AudioRecorderState.Init;
          print(_audioState);
        });
      }
    }
  }

  ///初始化录音器
  Future<void> _initRecord() async {
    _mPlayer = FlutterSoundPlayer();
    _mRecorder = FlutterSoundRecorder();

    await _mPlayer.openPlayer();
    setState(() {
      print('_mPlayerIsInited');
    });
    print("_mPlayer$_mPlayer");
    await openTheRecorder();
    setState(() {
      _audioState = AudioRecorderState.Init;
      print('_mRecorderIsInited');
    });
  }

  Future<void> openTheRecorder() async {
    try {
      await _mRecorder.openRecorder();
      if (!await _mRecorder.isEncoderSupported(_codec)) {
        _codec = Codec.opusWebM;
        _mPath = 'tau_file.webm';
        if (!await _mRecorder.isEncoderSupported(_codec)) {
          return;
        }
      }
      final session = await AudioSession.instance;
      await session.configure(AudioSessionConfiguration(
        avAudioSessionCategory: AVAudioSessionCategory.playAndRecord,
        avAudioSessionCategoryOptions:
            AVAudioSessionCategoryOptions.allowBluetooth |
                AVAudioSessionCategoryOptions.defaultToSpeaker,
        avAudioSessionMode: AVAudioSessionMode.spokenAudio,
        avAudioSessionRouteSharingPolicy:
            AVAudioSessionRouteSharingPolicy.defaultPolicy,
        avAudioSessionSetActiveOptions: AVAudioSessionSetActiveOptions.none,
        androidAudioAttributes: const AndroidAudioAttributes(
          contentType: AndroidAudioContentType.speech,
          flags: AndroidAudioFlags.none,
          usage: AndroidAudioUsage.voiceCommunication,
        ),
        androidAudioFocusGainType: AndroidAudioFocusGainType.gain,
        androidWillPauseWhenDucked: true,
      ));
    } catch (e) {
      print(e);
    }
  }

  Future<void> _uploadAudioFile() async {
    html.Storage localStorage = html.window.sessionStorage;
    if (localStorage.containsKey(_mPath)) {
      var webaFilePath = localStorage[_mPath] ?? '';
      if (webaFilePath.isEmpty) {
        return;
      }
      final pathInfos = webaFilePath.split('/');
      final name = pathInfos.last + '.' + _fileExtension;
      final webaFile = await http.get(Uri.parse(webaFilePath));
      final audioBytes = webaFile.bodyBytes;
      final fileToken =
          await rpc.storage.uploadUint8List(audioBytes, name) ?? '';
      if (fileToken.isNotEmpty) {
        await _commitASRInfoAsync(fileToken);
      }
    }
  }

  Future<void> _commitASRInfoAsync(String fileToken) async {
    var manager = Get.find<IReportManager>();
    var result = await manager.commitASRInfoAsync(fileToken, _fileExtension);
    _textEditingController.text += result;
    widget.onSubmit?.call(_textEditingController.text);
    setState(() {
      _audioState = AudioRecorderState.Init;
    });
    logger.i("audioConvertResult $result");
  }
}

enum AudioRecorderState {
  Init,
  Recording,
  Identifying,
}
