import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_sound/flutter_sound.dart';
import 'package:fis_i18n/i18n.dart';

/// 麦克风输入可视化
class MicrophoneWave extends StatefulWidget {
  final FlutterSoundRecorder recorder;
  final VoidCallback onAutoDetectPass;
  final double width;
  final double height;
  final bool isRecording;
  final double fontSize;

  MicrophoneWave(
      {required this.recorder,
      required this.isRecording,
      required this.onAutoDetectPass,
      this.width = 250.0,
      this.height = 40.0,
      this.fontSize = 16.0});

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

class _MicrophoneWaveState extends State<MicrophoneWave>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;
  StreamSubscription? _recorderSubscription;
  List<double> _loudnessValues = [];
  int autoDetectCount = 0;
  static const int autoDetectThreshold = 10;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: Duration(milliseconds: 50),
    );
    _animation = Tween<double>(begin: 0.0, end: 1.0).animate(_controller)
      ..addListener(() {
        setState(() {});
      });
    _recorderSubscription =
        widget.recorder.onProgress!.listen((RecordingDisposition e) {
      /// 输出响度，响度范围是0-120
      /// 0表示没有声音，120表示最大声音
      final loudness = ((e.decibels ?? 0) + 5) / 120;
      if (loudness > 0.2) {
        autoDetectCount++;
      }
      if (autoDetectCount > autoDetectThreshold) {
        autoDetectCount = 0;
        widget.onAutoDetectPass.call();
      }
      setState(() {
        _loudnessValues.add(loudness);
      });
      if (_loudnessValues.length > widget.width) {
        _loudnessValues.removeAt(0);
      }
      _controller.forward(from: 0.0);
    }, onError: (err) {
      print('onError: $err');
    });
  }

  @override
  void didUpdateWidget(covariant MicrophoneWave oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.isRecording != widget.isRecording) {
      if (widget.isRecording) {
        _loudnessValues.clear();
      }
    }
  }

  @override
  void dispose() {
    super.dispose();
    _controller.dispose();
    _recorderSubscription?.cancel();
    _recorderSubscription = null;
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: widget.width,
      height: widget.height,
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Text(
            i18nBook.setting.micInput.t,
            style: TextStyle(
              height: 1,
              color: Colors.black87,
              fontSize: widget.fontSize,
            ),
          ),
          SizedBox(
            width: 20,
          ),
          Expanded(
              child: ClipPath(
            child: CustomPaint(
              painter: _MicrophoneVisualizerPainter(
                loudnessList: _loudnessValues,
                animationValue: _animation.value,
                isRecording: widget.isRecording,
              ),
              size: Size(widget.width, widget.height),
            ),
          )),
          SizedBox(
            width: 20,
          ),
        ],
      ),
    );
  }
}

class _MicrophoneVisualizerPainter extends CustomPainter {
  final List<double> loudnessList;
  final double animationValue;
  final bool isRecording;
  _MicrophoneVisualizerPainter({
    required this.loudnessList,
    required this.animationValue,
    this.isRecording = false,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final double sampleStep = 5.0;
    final offsetX = sampleStep * animationValue;
    final double centerY = size.height / 2;
    Paint linePaint = Paint()
      ..color = Colors.grey
      ..strokeWidth = 1.0;

    /// 绘制中轴线
    canvas.drawLine(Offset(0, centerY), Offset(size.width, centerY), linePaint);
    if (!isRecording) return;
    linePaint = Paint()
      ..color = Colors.blue
      ..strokeWidth = 2.0;
    for (int i = 0; i < loudnessList.length; i++) {
      final loudness = loudnessList[loudnessList.length - i - 1];
      final x = i * sampleStep + offsetX;
      final y = centerY + loudness * centerY;
      final y2 = centerY - loudness * centerY;
      canvas.drawLine(Offset(x, y), Offset(x, y2), linePaint);
    }
  }

  @override
  bool shouldRepaint(_MicrophoneVisualizerPainter oldDelegate) {
    return oldDelegate.animationValue != animationValue;
  }
}
