import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:lottie/lottie.dart';
import 'package:openim_common/openim_common.dart';
import 'package:rxdart/rxdart.dart';
import 'package:sprintf/sprintf.dart';

typedef SpeakViewChildBuilder = Widget Function(ChatVoiceRecordBar recordBar);

class ChatVoiceRecordLayout extends StatefulWidget {
  const ChatVoiceRecordLayout({
    Key? key,
    required this.builder,
    this.locale,
    this.onCompleted,
    this.speakTextStyle,
    this.speakBarColor,
    this.maxRecordSec = 60,
  }) : super(key: key);

  final SpeakViewChildBuilder builder;
  final Locale? locale;
  final Function(int sec, String path)? onCompleted;
  final Color? speakBarColor;
  final TextStyle? speakTextStyle;

  final int maxRecordSec;

  @override
  State<ChatVoiceRecordLayout> createState() => _ChatVoiceRecordLayoutState();
}

class _ChatVoiceRecordLayoutState extends State<ChatVoiceRecordLayout> {
  final _interruptSub = PublishSubject<bool>();
  bool _showVoiceRecordView = false;
  RecordBarStatus _status = RecordBarStatus.holdTalk;
  bool _isCancelSend = false;
  bool _autoSendByLimit = false;

  void _completed(int sec, String path) {
    final autoSend = _autoSendByLimit;
    _autoSendByLimit = false;
    if (_isCancelSend && !autoSend) {
      File(path).delete();
      _status = RecordBarStatus.holdTalk;
      _isCancelSend = false;
    } else {
      if (sec == 0) {
        File(path).delete();
        IMViews.showToast(StrRes.talkTooShort);
      } else {
        widget.onCompleted?.call(sec, path);
        if (autoSend) {
          IMViews.showToast(StrRes.autoSendMaxVoiceDuration);
        }
      }
    }
  }

  @override
  void initState() {
    super.initState();
  }

  @override
  void dispose() {
    _interruptSub.close();
    super.dispose();
  }

  ChatVoiceRecordBar get _createSpeakBar => ChatVoiceRecordBar(
        speakBarColor: widget.speakBarColor,
        speakTextStyle: widget.speakTextStyle,
        interruptListener: _interruptSub.stream,
        onChangedBarStatus: (status) {
          if (status != _status) {
            setState(() {
              _isCancelSend = status == RecordBarStatus.liftFingerToCancelSend;
              _status = status;
            });
          }
        },
        onLongPressMoveUpdate: (details) {},
        onLongPressEnd: (details) async {
          setState(() {
            _showVoiceRecordView = false;
          });
        },
        onLongPressStart: (details) {
          setState(() {
            _autoSendByLimit = false;
            _isCancelSend = false;
            _showVoiceRecordView = true;
          });
        },
      );

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        widget.builder(_createSpeakBar),
        if (_showVoiceRecordView)
          _VoiceRecordOverlayFade(
            child: ChatRecordVoiceView(
              maxRecordSec: widget.maxRecordSec,
              onCompleted: _completed,
              onInterrupt: () {
                if (_autoSendByLimit) return;
                _autoSendByLimit = true;
                setState(() {
                  _interruptSub.add(true);
                  _showVoiceRecordView = false;
                });
              },
              builder: (_, sec) => Material(
                color: Colors.transparent,
                child: Center(
                  child: AnimatedContainer(
                    duration: Styles.motionOf(context, Styles.durationOverlaySwitch),
                    curve: Curves.easeOut,
                    width: 160.w,
                    height: 140.h,
                    padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 12.h),
                    decoration: BoxDecoration(
                      color: Styles.c_000000_opacity70,
                      borderRadius: BorderRadius.circular(12.r),
                    ),
                    child: Column(
                      children: [
                        _timerText(sec),
                        Expanded(
                          child: _isCancelSend
                              ? Icon(Icons.delete_outline,
                                  size: 48.w, color: Styles.c_FF381F)
                              : _lottieAnimWidget,
                        ),
                        (_isCancelSend
                                ? StrRes.liftFingerToCancelSend
                                : StrRes.releaseToSendSwipeUpToCancel)
                            .toText
                          ..style = _isCancelSend
                              ? Styles.ts_FF381F_12sp
                              : Styles.ts_FFFFFF_12sp
                          ..maxLines = 1,
                      ],
                    ),
                  ),
                ),
              ),
            ),
          ),
      ],
    );
  }

  Widget _timerText(int sec) {
    final remaining = widget.maxRecordSec - sec;
    final nearLimit = sec >= widget.maxRecordSec - 10 && remaining > 0;
    final text = nearLimit
        ? sprintf(StrRes.remainingRecordSeconds, [remaining])
        : IMUtils.seconds2HMS(sec);
    return text.toText
      ..style = nearLimit ? Styles.ts_FFB300_12sp : Styles.ts_FFFFFF_12sp;
  }

  Widget get _lottieAnimWidget => Lottie.asset(
        'assets/anim/voice_record.json',
        fit: BoxFit.contain,
        package: 'openim_common',
      );
}

class _VoiceRecordOverlayFade extends StatefulWidget {
  const _VoiceRecordOverlayFade({required this.child});

  final Widget child;

  @override
  State<_VoiceRecordOverlayFade> createState() => _VoiceRecordOverlayFadeState();
}

class _VoiceRecordOverlayFadeState extends State<_VoiceRecordOverlayFade> {
  double _opacity = 0;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (!mounted) return;
      setState(() => _opacity = 1);
    });
  }

  @override
  Widget build(BuildContext context) {
    final reduce = Styles.reduceMotion(context);
    return AnimatedOpacity(
      opacity: reduce ? 1 : _opacity,
      duration: Styles.motionOf(context, Styles.durationOverlay),
      curve: Curves.easeOut,
      child: widget.child,
    );
  }
}
