import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:dio/dio.dart';
import 'package:flutter_sound/flutter_sound.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;
import 'package:permission_handler/permission_handler.dart';
import '../../../../core/network/dio_client.dart';

enum _VoiceProvider { local, openai }

/// Temporary voice I/O test page — TTS + STT + Round-trip.
/// Supports switching between Local (Kokoro/faster-whisper) and OpenAI APIs.
class VoiceTestPage extends ConsumerStatefulWidget {
  const VoiceTestPage({super.key});

  @override
  ConsumerState<VoiceTestPage> createState() => _VoiceTestPageState();
}

class _VoiceTestPageState extends ConsumerState<VoiceTestPage> {
  final _ttsController = TextEditingController(
    text: '你好，我是IT0运维助手。很高兴为您服务！',
  );
  final _player = FlutterSoundPlayer();
  final _recorder = FlutterSoundRecorder();
  bool _playerReady = false;
  bool _recorderReady = false;

  _VoiceProvider _provider = _VoiceProvider.openai;

  String _ttsStatus = '';
  String _sttStatus = '';
  String _sttResult = '';
  String _rtStatus = '';
  String _rtResult = '';
  bool _isRecording = false;
  bool _isSynthesizing = false;
  String _recordMode = ''; // 'stt' or 'rt'
  String? _recordingPath;

  // Endpoint paths based on provider
  String get _ttsEndpoint => _provider == _VoiceProvider.openai
      ? '/api/v1/test/tts/synthesize-openai'
      : '/api/v1/test/tts/synthesize';

  String get _sttEndpoint => _provider == _VoiceProvider.openai
      ? '/api/v1/test/stt/transcribe-openai'
      : '/api/v1/test/stt/transcribe';

  Dio get _dioBinary {
    final base = ref.read(dioClientProvider);
    return Dio(BaseOptions(
      baseUrl: base.options.baseUrl,
      connectTimeout: const Duration(seconds: 30),
      receiveTimeout: const Duration(seconds: 120),
      responseType: ResponseType.bytes,
    ));
  }

  Dio get _dioJson => ref.read(dioClientProvider);

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

  Future<void> _init() async {
    await _player.openPlayer();
    _playerReady = true;
    await _recorder.openRecorder();
    _recorderReady = true;
    if (mounted) setState(() {});
  }

  @override
  void dispose() {
    _ttsController.dispose();
    if (_playerReady) _player.closePlayer();
    if (_recorderReady) _recorder.closeRecorder();
    super.dispose();
  }

  // ---- TTS ----
  Future<void> _doTTS() async {
    final text = _ttsController.text.trim();
    if (text.isEmpty) return;
    final label = _provider == _VoiceProvider.openai ? 'OpenAI' : 'Local';
    setState(() {
      _isSynthesizing = true;
      _ttsStatus = '[$label] 合成中...';
    });
    final sw = Stopwatch()..start();
    try {
      final resp = await _dioBinary.get(
        _ttsEndpoint,
        queryParameters: {'text': text},
      );
      sw.stop();
      final bytes = resp.data as List<int>;
      setState(() {
        _ttsStatus =
            '[$label] 完成！耗时 ${sw.elapsedMilliseconds}ms，大小 ${(bytes.length / 1024).toStringAsFixed(1)}KB';
      });
      await _playWav(Uint8List.fromList(bytes));
    } catch (e) {
      sw.stop();
      setState(() => _ttsStatus = '[$label] 错误: $e');
    } finally {
      setState(() => _isSynthesizing = false);
    }
  }

  // ---- Recording ----
  Future<void> _startRecording(String mode) async {
    if (_isRecording || !_recorderReady) return;

    final status = await Permission.microphone.request();
    if (!status.isGranted) {
      setState(() {
        final msg = '麦克风权限被拒绝';
        if (mode == 'stt') {
          _sttStatus = msg;
        } else {
          _rtStatus = msg;
        }
      });
      return;
    }

    final dir = await getTemporaryDirectory();
    _recordingPath = p.join(
        dir.path, 'voice_test_${DateTime.now().millisecondsSinceEpoch}.wav');
    _recordMode = mode;

    setState(() {
      _isRecording = true;
      if (mode == 'stt') {
        _sttStatus = '录音中...';
        _sttResult = '';
      } else {
        _rtStatus = '录音中...';
        _rtResult = '';
      }
    });

    await _recorder.startRecorder(
      toFile: _recordingPath,
      codec: Codec.pcm16WAV,
      sampleRate: 16000,
      numChannels: 1,
    );
  }

  Future<void> _stopRecording() async {
    if (!_isRecording || !_recorderReady) return;
    final path = await _recorder.stopRecorder();
    setState(() => _isRecording = false);

    final filePath = path ?? _recordingPath;
    if (filePath == null || filePath.isEmpty) return;
    if (!File(filePath).existsSync()) return;

    if (_recordMode == 'stt') {
      _doSTT(filePath);
    } else {
      _doRoundTrip(filePath);
    }
  }

  // ---- STT ----
  Future<void> _doSTT(String audioPath) async {
    final label = _provider == _VoiceProvider.openai ? 'OpenAI' : 'Local';
    setState(() => _sttStatus = '[$label] 识别中...');
    final sw = Stopwatch()..start();
    try {
      final formData = FormData.fromMap({
        'audio':
            await MultipartFile.fromFile(audioPath, filename: 'recording.wav'),
      });
      final resp = await _dioJson.post(_sttEndpoint, data: formData);
      sw.stop();
      final data = resp.data as Map<String, dynamic>;
      setState(() {
        _sttResult = data['text'] ?? '(empty)';
        final extra = data['duration'] != null ? '，时长 ${data['duration']}s' : '';
        _sttStatus = '[$label] 完成！耗时 ${sw.elapsedMilliseconds}ms$extra';
      });
    } catch (e) {
      sw.stop();
      setState(() {
        _sttStatus = '[$label] 错误: $e';
        _sttResult = '';
      });
    } finally {
      _cleanupFile(audioPath);
    }
  }

  // ---- Round-trip: STT → TTS ----
  Future<void> _doRoundTrip(String audioPath) async {
    final label = _provider == _VoiceProvider.openai ? 'OpenAI' : 'Local';
    setState(() => _rtStatus = '[$label] STT 识别中...');
    final totalSw = Stopwatch()..start();
    try {
      // 1. STT
      final sttSw = Stopwatch()..start();
      final formData = FormData.fromMap({
        'audio':
            await MultipartFile.fromFile(audioPath, filename: 'recording.wav'),
      });
      final sttResp = await _dioJson.post(_sttEndpoint, data: formData);
      sttSw.stop();
      final sttData = sttResp.data as Map<String, dynamic>;
      final text = sttData['text'] ?? '';
      setState(() {
        _rtResult = '[$label] STT (${sttSw.elapsedMilliseconds}ms): $text';
        _rtStatus = '[$label] TTS 合成中...';
      });
      if (text.isEmpty) {
        setState(() => _rtStatus = '[$label] STT 识别为空');
        return;
      }

      // 2. TTS
      final ttsSw = Stopwatch()..start();
      final ttsResp = await _dioBinary.get(
        _ttsEndpoint,
        queryParameters: {'text': text},
      );
      ttsSw.stop();
      totalSw.stop();
      final audioBytes = ttsResp.data as List<int>;
      setState(() {
        _rtResult +=
            '\n[$label] TTS (${ttsSw.elapsedMilliseconds}ms): ${(audioBytes.length / 1024).toStringAsFixed(1)}KB';
        _rtStatus =
            '[$label] STT=${sttSw.elapsedMilliseconds}ms + TTS=${ttsSw.elapsedMilliseconds}ms = ${totalSw.elapsedMilliseconds}ms';
      });
      await _playWav(Uint8List.fromList(audioBytes));
    } catch (e) {
      totalSw.stop();
      setState(() => _rtStatus = '[$label] 错误: $e');
    } finally {
      _cleanupFile(audioPath);
    }
  }

  Future<void> _playWav(Uint8List wavBytes) async {
    if (!_playerReady) return;
    await _player.startPlayer(
      fromDataBuffer: wavBytes,
      codec: Codec.pcm16WAV,
      whenFinished: () {},
    );
  }

  void _cleanupFile(String path) {
    try {
      File(path).deleteSync();
    } catch (_) {}
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('语音 I/O 测试')),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          // Provider toggle
          Center(
            child: SegmentedButton<_VoiceProvider>(
              segments: const [
                ButtonSegment(
                  value: _VoiceProvider.local,
                  label: Text('Local'),
                  icon: Icon(Icons.computer, size: 18),
                ),
                ButtonSegment(
                  value: _VoiceProvider.openai,
                  label: Text('OpenAI'),
                  icon: Icon(Icons.cloud, size: 18),
                ),
              ],
              selected: {_provider},
              onSelectionChanged: (Set<_VoiceProvider> sel) {
                setState(() => _provider = sel.first);
              },
            ),
          ),
          Padding(
            padding: const EdgeInsets.only(top: 4, bottom: 12),
            child: Center(
              child: Text(
                _provider == _VoiceProvider.openai
                    ? 'STT: gpt-4o-transcribe  |  TTS: tts-1'
                    : 'STT: faster-whisper  |  TTS: Kokoro',
                style: TextStyle(fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant),
              ),
            ),
          ),
          // TTS Section
          _buildSection(
            title: 'TTS (文本转语音)',
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                TextField(
                  controller: _ttsController,
                  maxLines: 3,
                  decoration: const InputDecoration(
                    hintText: '输入要合成的文本...',
                    border: OutlineInputBorder(),
                  ),
                ),
                const SizedBox(height: 8),
                ElevatedButton.icon(
                  onPressed: _isSynthesizing ? null : _doTTS,
                  icon: _isSynthesizing
                      ? const SizedBox(
                          width: 16,
                          height: 16,
                          child: CircularProgressIndicator(strokeWidth: 2))
                      : const Icon(Icons.volume_up),
                  label: Text(_isSynthesizing ? '合成中...' : '合成语音'),
                ),
                if (_ttsStatus.isNotEmpty)
                  Padding(
                    padding: const EdgeInsets.only(top: 8),
                    child: Text(_ttsStatus,
                        style:
                            TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant, fontSize: 13)),
                  ),
              ],
            ),
          ),
          const SizedBox(height: 16),
          // STT Section
          _buildSection(
            title: 'STT (语音转文本)',
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                GestureDetector(
                  onLongPressStart: (_) => _startRecording('stt'),
                  onLongPressEnd: (_) => _stopRecording(),
                  child: ElevatedButton.icon(
                    onPressed: () {},
                    style: ElevatedButton.styleFrom(
                      backgroundColor: _isRecording && _recordMode == 'stt'
                          ? Colors.red
                          : null,
                    ),
                    icon: Icon(_isRecording && _recordMode == 'stt'
                        ? Icons.mic
                        : Icons.mic_none),
                    label: Text(_isRecording && _recordMode == 'stt'
                        ? '录音中... 松开结束'
                        : '长按录音'),
                  ),
                ),
                if (_sttStatus.isNotEmpty)
                  Padding(
                    padding: const EdgeInsets.only(top: 8),
                    child: Text(_sttStatus,
                        style:
                            TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant, fontSize: 13)),
                  ),
                if (_sttResult.isNotEmpty)
                  Container(
                    width: double.infinity,
                    margin: const EdgeInsets.only(top: 8),
                    padding: const EdgeInsets.all(12),
                    decoration: BoxDecoration(
                      color: Theme.of(context).colorScheme.surfaceContainerHighest,
                      borderRadius: BorderRadius.circular(8),
                    ),
                    child: Text(_sttResult,
                        style: TextStyle(
                            fontSize: 16,
                            color: Theme.of(context).colorScheme.onSurface)),
                  ),
              ],
            ),
          ),
          const SizedBox(height: 16),
          // Round-trip Section
          _buildSection(
            title: 'Round-trip (STT + TTS)',
            subtitle: '录音 → 识别文本 → 合成语音播放',
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                GestureDetector(
                  onLongPressStart: (_) => _startRecording('rt'),
                  onLongPressEnd: (_) => _stopRecording(),
                  child: ElevatedButton.icon(
                    onPressed: () {},
                    style: ElevatedButton.styleFrom(
                      backgroundColor: _isRecording && _recordMode == 'rt'
                          ? Colors.red
                          : null,
                    ),
                    icon: Icon(_isRecording && _recordMode == 'rt'
                        ? Icons.mic
                        : Icons.swap_horiz),
                    label: Text(_isRecording && _recordMode == 'rt'
                        ? '录音中... 松开结束'
                        : '长按说话 (Round-trip)'),
                  ),
                ),
                if (_rtStatus.isNotEmpty)
                  Padding(
                    padding: const EdgeInsets.only(top: 8),
                    child: Text(_rtStatus,
                        style:
                            TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant, fontSize: 13)),
                  ),
                if (_rtResult.isNotEmpty)
                  Container(
                    width: double.infinity,
                    margin: const EdgeInsets.only(top: 8),
                    padding: const EdgeInsets.all(12),
                    decoration: BoxDecoration(
                      color: Theme.of(context).colorScheme.surfaceContainerHighest,
                      borderRadius: BorderRadius.circular(8),
                    ),
                    child: Text(_rtResult,
                        style: TextStyle(
                            fontSize: 14,
                            color: Theme.of(context).colorScheme.onSurface)),
                  ),
              ],
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildSection({
    required String title,
    String? subtitle,
    required Widget child,
  }) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(title,
                style:
                    const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
            if (subtitle != null)
              Padding(
                padding: const EdgeInsets.only(top: 4),
                child: Text(subtitle,
                    style: TextStyle(fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant)),
              ),
            const SizedBox(height: 12),
            child,
          ],
        ),
      ),
    );
  }
}
