import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:record/record.dart';
import 'package:audioplayers/audioplayers.dart';
import 'package:path_provider/path_provider.dart';
import '../../core/theme/app_colors.dart';
import '../../core/theme/app_typography.dart';
import '../../services/app_provider.dart';
import '../../services/api_service.dart';
import '../../widgets/pulsing_orb.dart';
import '../../widgets/upgrade_prompt.dart';

/// Voice call using REST API.
/// Flow: Record WAV → Whisper transcribe → Chat → TTS → Play MP3
class VoiceCallScreen extends StatefulWidget {
  const VoiceCallScreen({super.key});

  @override
  State<VoiceCallScreen> createState() => _VoiceCallScreenState();
}

class _VoiceCallScreenState extends State<VoiceCallScreen>
    with SingleTickerProviderStateMixin {
  bool _active = false;
  bool _muted = false;
  bool _recording = false;
  bool _processing = false;
  bool _playing = false;
  String _status = 'Tap to start call';
  double _amplitude = 0.0;
  String? _conversationId;
  final List<Map<String, String>> _transcript = [];

  // Voice selection
  String _selectedVoice = 'nova';
  static const _voices = {
    'nova': 'Nova (Female)',
    'echo': 'Echo (Male)',
  };

  late AnimationController _fadeCtrl;
  final AudioRecorder _recorder = AudioRecorder();
  final AudioPlayer _player = AudioPlayer();
  String? _recordingPath;

  Timer? _silenceTimer;
  static const _silenceThreshold = Duration(milliseconds: 1500);
  DateTime? _lastAudioTime;

  @override
  void initState() {
    super.initState();
    _fadeCtrl = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 400),
    );
    _player.onPlayerComplete.listen((_) => _onPlaybackComplete());
  }

  @override
  void dispose() {
    _endCall();
    _fadeCtrl.dispose();
    _recorder.dispose();
    _player.dispose();
    _silenceTimer?.cancel();
    super.dispose();
  }

  Future<void> _toggleCall() async {
    if (_active) {
      await _endCall();
    } else {
      await _startCall();
    }
  }

  Future<void> _startCall() async {
    final micStatus = await Permission.microphone.request();
    if (!micStatus.isGranted) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: const Text('Microphone permission required'),
            backgroundColor: AppColors.error,
            behavior: SnackBarBehavior.floating,
            shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
          ),
        );
      }
      return;
    }

    setState(() {
      _active = true;
      _status = 'Starting call...';
      _amplitude = 0.1;
      _transcript.clear();
    });
    _fadeCtrl.forward();

    try {
      final provider = context.read<AppProvider>();
      final country = provider.auth.userCountry;

      _conversationId = await provider.createConversation(
        title: 'Voice Call',
        country: country,
      );

      setState(() {
        _status = 'Speak now';
        _amplitude = 0.3;
      });

      await _startRecording();
    } on ApiException catch (e) {
      if (e.isLimitError) {
        setState(() {
          _active = false;
          _status = 'Tap to start call';
          _amplitude = 0.0;
        });
        _fadeCtrl.reverse();
        if (mounted) showUpgradePrompt(context, feature: 'voice calls');
      } else {
        setState(() => _status = 'Error: ${e.message}');
        await Future.delayed(const Duration(seconds: 2));
        if (mounted) _endCall();
      }
    } catch (e) {
      debugPrint('Start call error: $e');
      setState(() => _status = 'Failed to start');
      await Future.delayed(const Duration(seconds: 2));
      if (mounted) _endCall();
    }
  }

  Future<void> _startRecording() async {
    if (_recording || _muted || !_active || _processing || _playing) return;

    try {
      if (!await _recorder.hasPermission()) return;

      final tempDir = await getTemporaryDirectory();
      _recordingPath =
          '${tempDir.path}/voice_${DateTime.now().millisecondsSinceEpoch}.wav';

      await _recorder.start(
        const RecordConfig(
          encoder: AudioEncoder.wav,
          sampleRate: 16000,
          numChannels: 1,
        ),
        path: _recordingPath!,
      );

      _lastAudioTime = DateTime.now();
      _startSilenceDetection();

      setState(() {
        _recording = true;
        _status = 'Listening...';
        _amplitude = 0.4;
      });
    } catch (e) {
      debugPrint('Start recording error: $e');
      setState(() => _status = 'Mic error');
    }
  }

  void _startSilenceDetection() {
    _silenceTimer?.cancel();
    _silenceTimer =
        Timer.periodic(const Duration(milliseconds: 200), (_) async {
      if (!_recording || !_active) return;

      try {
        final amp = await _recorder.getAmplitude();
        final db = amp.current;
        final normalized = ((db + 60) / 60).clamp(0.2, 0.8);
        if (mounted) setState(() => _amplitude = normalized);

        if (db < -40) {
          final now = DateTime.now();
          if (_lastAudioTime != null &&
              now.difference(_lastAudioTime!) > _silenceThreshold) {
            _silenceTimer?.cancel();
            await _processRecording();
          }
        } else {
          _lastAudioTime = DateTime.now();
        }
      } catch (_) {}
    });
  }

  Future<void> _stopRecording() async {
    _silenceTimer?.cancel();
    if (!_recording) return;
    try {
      await _recorder.stop();
    } catch (_) {}
    setState(() {
      _recording = false;
      _amplitude = 0.2;
    });
  }

  Future<void> _processRecording() async {
    if (_processing || !_active) return;

    await _stopRecording();

    if (_recordingPath == null || !File(_recordingPath!).existsSync()) {
      _startRecording();
      return;
    }

    final file = File(_recordingPath!);
    final size = await file.length();

    // Skip if recording is too short
    if (size < 16000) {
      debugPrint('Recording too short ($size bytes), ignoring');
      _startRecording();
      return;
    }

    setState(() {
      _processing = true;
      _status = 'Transcribing...';
      _amplitude = 0.3;
    });

    try {
      final provider = context.read<AppProvider>();

      // 1. Transcribe audio via Whisper
      final transcribeRes =
          await provider.api.voiceTranscribe(_recordingPath!, 'recording.wav');
      final userText = transcribeRes['text']?.toString() ?? '';

      if (userText.isEmpty || userText.length < 2) {
        setState(() {
          _processing = false;
          _status = 'Speak now';
        });
        _startRecording();
        return;
      }

      _transcript.add({'role': 'user', 'text': userText});
      setState(() => _status = 'Thinking...');

      // 2. Send transcribed text to chat
      final chatRes = await provider.api.sendMessage(
        conversationId: _conversationId!,
        message: userText,
        inputType: 'voice',
      );
      final aiText =
          chatRes['ai_message']?['content']?.toString() ??
          chatRes['response']?.toString() ??
          '';

      if (aiText.isEmpty) {
        setState(() {
          _processing = false;
          _status = 'Speak now';
        });
        _startRecording();
        return;
      }

      _transcript.add({'role': 'assistant', 'text': aiText});
      setState(() => _status = 'Speaking...');

      // 3. TTS with selected voice
      final audioBytes =
          await provider.api.voiceTtsBytes(text: aiText, voice: _selectedVoice);

      // 4. Play response
      await _playAudio(audioBytes);
    } on ApiException catch (e) {
      if (e.isLimitError) {
        if (mounted) showUpgradePrompt(context, feature: 'voice calls');
        _endCall();
      } else {
        if (mounted) {
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(
              content: Text(e.message),
              backgroundColor: AppColors.error,
              behavior: SnackBarBehavior.floating,
              shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(10)),
            ),
          );
        }
        setState(() {
          _processing = false;
          _status = 'Speak now';
        });
        _startRecording();
      }
    } catch (e) {
      debugPrint('Process recording error: $e');
      setState(() {
        _processing = false;
        _status = 'Error, try again';
      });
      await Future.delayed(const Duration(seconds: 1));
      if (mounted && _active) {
        setState(() => _status = 'Speak now');
        _startRecording();
      }
    }
  }

  Future<void> _playAudio(List<int> audioBytes) async {
    if (audioBytes.isEmpty) {
      _onPlaybackComplete();
      return;
    }

    setState(() {
      _playing = true;
      _processing = false;
      _amplitude = 0.5;
    });

    try {
      final tempDir = await getTemporaryDirectory();
      final file = File(
          '${tempDir.path}/tts_${DateTime.now().millisecondsSinceEpoch}.mp3');
      await file.writeAsBytes(audioBytes);
      await _player.play(DeviceFileSource(file.path));
    } catch (e) {
      debugPrint('Play audio error: $e');
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: const Text('Audio playback error'),
            backgroundColor: AppColors.error,
            behavior: SnackBarBehavior.floating,
            shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(10)),
          ),
        );
      }
      _onPlaybackComplete();
    }
  }

  void _onPlaybackComplete() {
    setState(() {
      _playing = false;
      _amplitude = 0.3;
      _status = 'Speak now';
    });
    if (_active && !_muted) {
      _startRecording();
    }
  }

  Future<void> _endCall() async {
    if (!_active) return;
    setState(() {
      _status = 'Ending call...';
      _amplitude = 0.05;
    });
    _silenceTimer?.cancel();
    await _stopRecording();
    try {
      await _player.stop();
    } catch (_) {}
    _fadeCtrl.reverse();
    if (mounted) {
      setState(() {
        _active = false;
        _recording = false;
        _processing = false;
        _playing = false;
        _status = 'Call ended';
        _amplitude = 0.0;
        _conversationId = null;
      });
    }
    await Future.delayed(const Duration(seconds: 2));
    if (mounted) setState(() => _status = 'Tap to start call');
  }

  void _toggleMute() {
    setState(() => _muted = !_muted);
    if (_muted) {
      _stopRecording();
      setState(() => _status = 'Muted');
    } else if (_active && !_playing && !_processing) {
      setState(() => _status = 'Speak now');
      _startRecording();
    }
  }

  void _showVoiceSelector() {
    showModalBottomSheet(
      context: context,
      backgroundColor: AppColors.navy,
      shape: const RoundedRectangleBorder(
        borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
      ),
      builder: (ctx) => SafeArea(
        child: Padding(
          padding: const EdgeInsets.all(20),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text('Select AI Voice',
                  style: AppTypography.headingMd
                      .copyWith(color: Colors.white)),
              const SizedBox(height: 16),
              ..._voices.entries.map((e) => ListTile(
                    contentPadding: EdgeInsets.zero,
                    leading: Icon(
                      e.key == _selectedVoice
                          ? Icons.radio_button_checked
                          : Icons.radio_button_off,
                      color: e.key == _selectedVoice
                          ? AppColors.royalBlue
                          : AppColors.textMuted,
                    ),
                    title: Text(e.value,
                        style: AppTypography.bodyMd
                            .copyWith(color: Colors.white)),
                    onTap: () {
                      setState(() => _selectedVoice = e.key);
                      Navigator.pop(ctx);
                    },
                  )),
            ],
          ),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: AppColors.navy,
      body: SafeArea(
        child: Column(
          children: [
            // Header
            Padding(
              padding: const EdgeInsets.fromLTRB(8, 8, 8, 0),
              child: Row(
                children: [
                  IconButton(
                    icon: const Icon(Icons.arrow_back_rounded,
                        color: Colors.white),
                    onPressed: () {
                      if (_active) _endCall();
                      Navigator.of(context).pop();
                    },
                  ),
                  const Spacer(),
                  Text('Voice Call',
                      style: AppTypography.headingMd
                          .copyWith(color: Colors.white)),
                  const Spacer(),
                  const SizedBox(width: 48),
                ],
              ),
            ),

            const Spacer(flex: 2),

            // Voice selector (only when not in a call)
            if (!_active)
              Padding(
                padding: const EdgeInsets.only(bottom: 24),
                child: GestureDetector(
                  onTap: _showVoiceSelector,
                  child: Container(
                    padding: const EdgeInsets.symmetric(
                        horizontal: 20, vertical: 12),
                    decoration: BoxDecoration(
                      color: AppColors.glassSurface,
                      borderRadius: BorderRadius.circular(30),
                      border: Border.all(color: AppColors.glassBorder),
                    ),
                    child: Row(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        const Icon(Icons.record_voice_over_rounded,
                            color: AppColors.royalBlue, size: 20),
                        const SizedBox(width: 10),
                        Text(
                          _voices[_selectedVoice] ?? 'Nova',
                          style: AppTypography.bodyMd
                              .copyWith(color: Colors.white),
                        ),
                        const SizedBox(width: 6),
                        const Icon(Icons.arrow_drop_down_rounded,
                            color: AppColors.textMuted, size: 20),
                      ],
                    ),
                  ),
                ),
              ),

            // Pulsing Orb
            GestureDetector(
              onTap: _active ? null : _toggleCall,
              child: PulsingOrb(
                size: 240,
                amplitude: _amplitude,
                active: _active,
              ),
            ),

            const SizedBox(height: 32),

            // Status text
            Text(
              _status,
              style: AppTypography.headingLg.copyWith(
                color: _active ? AppColors.gold : AppColors.textMuted,
              ),
              textAlign: TextAlign.center,
            ),

            const SizedBox(height: 8),

            if (_active)
              Text(
                _recording
                    ? 'Listening...'
                    : _playing
                        ? 'AI Speaking...'
                        : _processing
                            ? 'Processing...'
                            : '',
                style: AppTypography.bodyMd
                    .copyWith(color: AppColors.textSecondary),
              ),

            const Spacer(),

            // Transcript (last 2 entries)
            if (_transcript.isNotEmpty)
              Container(
                height: 120,
                margin: const EdgeInsets.symmetric(horizontal: 20),
                child: ListView.builder(
                  reverse: true,
                  itemCount:
                      _transcript.length > 2 ? 2 : _transcript.length,
                  itemBuilder: (ctx, i) {
                    final entry = _transcript[_transcript.length - 1 - i];
                    final isUser = entry['role'] == 'user';
                    return Padding(
                      padding: const EdgeInsets.symmetric(vertical: 4),
                      child: Row(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Icon(
                            isUser
                                ? Icons.person_rounded
                                : Icons.smart_toy_rounded,
                            color: isUser
                                ? AppColors.textMuted
                                : AppColors.gold,
                            size: 16,
                          ),
                          const SizedBox(width: 8),
                          Expanded(
                            child: Text(
                              entry['text'] ?? '',
                              style: AppTypography.bodySm.copyWith(
                                color: isUser
                                    ? AppColors.textMuted
                                    : Colors.white,
                              ),
                              maxLines: 2,
                              overflow: TextOverflow.ellipsis,
                            ),
                          ),
                        ],
                      ),
                    );
                  },
                ),
              ),

            const Spacer(),

            // Controls
            if (_active)
              Padding(
                padding: const EdgeInsets.only(bottom: 40),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    // Mute button
                    GestureDetector(
                      onTap: _toggleMute,
                      child: Container(
                        width: 56,
                        height: 56,
                        decoration: BoxDecoration(
                          color: _muted
                              ? AppColors.warning.withValues(alpha: 0.2)
                              : AppColors.glassSurface,
                          shape: BoxShape.circle,
                        ),
                        child: Icon(
                          _muted
                              ? Icons.mic_off_rounded
                              : Icons.mic_rounded,
                          color: _muted ? AppColors.warning : Colors.white,
                        ),
                      ),
                    ),
                    const SizedBox(width: 24),
                    // End call button
                    GestureDetector(
                      onTap: _endCall,
                      child: Container(
                        width: 64,
                        height: 64,
                        decoration: const BoxDecoration(
                          color: AppColors.error,
                          shape: BoxShape.circle,
                        ),
                        child: const Icon(Icons.call_end_rounded,
                            color: Colors.white, size: 28),
                      ),
                    ),
                  ],
                ),
              )
            else
              const SizedBox(height: 100),
          ],
        ),
      ),
    );
  }
}
