part of '../voice_channel.dart';

// Unified participant data to handle both LiveKit and VoIP
class _ParticipantData {
  final String id;
  final String name;
  final Widget? videoWidget;
  final bool isSpeaking;
  final bool isMuted;
  final bool hasVideo;
  final bool isScreenShare;
  final Color avatarColor;
  final dynamic originalParticipant;
  final double aspectRatio;

  const _ParticipantData({
    required this.id,
    required this.name,
    this.videoWidget,
    this.isSpeaking = false,
    this.isMuted = false,
    this.hasVideo = false,
    this.isScreenShare = false,
    this.avatarColor = Colors.grey,
    this.originalParticipant,
    this.aspectRatio = 16.0 / 9.0,
  });
}

class VoiceChannelView extends ConsumerWidget {
  const VoiceChannelView({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final pt = PyramidTheme.of(context);
    final call = ref.watch(voiceChannelProvider);
    final voip = ref.watch(callSignalingProvider);

    if (voip.currentCall != null && voip.currentCall!.state != CallState.kEnded) {
      return _UnifiedCallView(
        participants: _getVoipParticipants(voip),
        isLiveKit: false,
        displayName: voip.currentCall!.room.getLocalizedDisplayname(),
        isConnecting: false,
        onHangUp: () {
          voip.hangup();
          ref.read(viewModeProvider.notifier).state = ViewMode.chat;
        },
        onMinimize: () =>
            ref.read(viewModeProvider.notifier).state = ViewMode.chat,
        onToggleMic: voip.toggleMic,
        onToggleDeafen: voip.toggleDeafen,
        onToggleCam: voip.toggleCamera,
        onToggleScreen: () => voip.toggleScreenSharing(context),
        isMuted: voip.isMicMuted,
        isDeafened: voip.isDeafened,
        isCameraOff: voip.isCameraMuted,
        isScreenSharing: voip.isScreensharing,
        onQualityMenu: (pos) => _showVoipQualityMenu(context, voip, pos),
        pt: pt,
      );
    }

    if (!call.isActive) {
      return _NoCall(pt: pt, ref: ref);
    }

    return _UnifiedCallView(
      participants: _getLiveKitParticipants(call),
      isLiveKit: true,
      displayName: call.displayName,
      isConnecting: call.isConnecting,
      onHangUp: () {
        call.hangUp();
        ref.read(viewModeProvider.notifier).state = ViewMode.chat;
      },
      onMinimize: () =>
          ref.read(viewModeProvider.notifier).state = ViewMode.chat,
      onToggleMic: call.toggleMute,
      onToggleDeafen: call.toggleDeafen,
      onToggleCam: call.toggleCamera,
      onToggleScreen: () => _handleLiveKitScreenShare(context, call),
      isMuted: call.isMuted,
      isDeafened: call.isDeafened,
      isCameraOff: call.isCameraOff,
      isScreenSharing: call.isScreenSharing,
      onQualityMenu: (pos) => _showLiveKitQualityMenu(context, call, pos),
      pt: pt,
    );
  }

  List<_ParticipantData> _getLiveKitParticipants(VoiceChannelService call) {
    final room = call.room;
    if (room == null) return [];
    final all = <Participant>[
      if (room.localParticipant != null) room.localParticipant!,
      ...room.remoteParticipants.values,
    ];

    return all.mapIndexed((i, p) {
      final screenPub = p.videoTrackPublications.firstWhereOrNull((v) => v.source == TrackSource.screenShareVideo);
      final camPub = p.videoTrackPublications.firstWhereOrNull((v) => v.source == TrackSource.camera);
      final videoTrack = (screenPub?.track ?? camPub?.track) as VideoTrack?;
      final isScreen = screenPub != null;

      double ar = 16.0 / 9.0;
      if (videoTrack != null) {
        try {
          final dim = (videoTrack as dynamic).currentDimensions ?? (videoTrack as dynamic).dimensions;
          if (dim != null) {
            final w = (dim.width as num?)?.toDouble() ?? 0;
            final h = (dim.height as num?)?.toDouble() ?? 0;
            if (w > 0 && h > 0) ar = w / h;
          }
        } catch (_) {}
      }

      return _ParticipantData(
        id: p.identity,
        name: p.identity == room.localParticipant?.identity ? 'Du' : p.identity,
        videoWidget: videoTrack != null ? VideoTrackRenderer(videoTrack, fit: VideoViewFit.contain) : null,
        isSpeaking: p.isSpeaking,
        isMuted: !p.isMicrophoneEnabled(),
        hasVideo: videoTrack != null,
        isScreenShare: isScreen,
        avatarColor: _avatarColors[i % _avatarColors.length],
        originalParticipant: p,
        aspectRatio: ar,
      );
    }).toList();
  }

  List<_ParticipantData> _getVoipParticipants(CallSignalingService voip) {
    final participants = <_ParticipantData>[];

    double ar(rtc.RTCVideoRenderer r) {
      final w = r.videoWidth.toDouble();
      final h = r.videoHeight.toDouble();
      return (w > 0 && h > 0) ? w / h : 16.0 / 9.0;
    }

    // Remote
    final isRemoteScreen = voip.isRemoteScreensharing;
    final hasRemoteVideo = voip.remoteRenderer.srcObject != null && voip.remoteRenderer.srcObject!.getVideoTracks().isNotEmpty;
    participants.add(_ParticipantData(
      id: 'remote',
      name: voip.currentCall?.room.getLocalizedDisplayname() ?? 'Remote',
      videoWidget: hasRemoteVideo ? rtc.RTCVideoView(voip.remoteRenderer, objectFit: rtc.RTCVideoViewObjectFit.RTCVideoViewObjectFitContain) : null,
      isMuted: false,
      hasVideo: hasRemoteVideo,
      isScreenShare: isRemoteScreen,
      avatarColor: _avatarColors[1],
      aspectRatio: hasRemoteVideo ? ar(voip.remoteRenderer) : 16.0 / 9.0,
    ));

    // Local
    final isLocalScreen = voip.isScreensharing;
    final hasLocalVideo = voip.localRenderer.srcObject != null && voip.localRenderer.srcObject!.getVideoTracks().isNotEmpty;
    participants.add(_ParticipantData(
      id: 'local',
      name: 'Du',
      videoWidget: hasLocalVideo ? rtc.RTCVideoView(voip.localRenderer, objectFit: rtc.RTCVideoViewObjectFit.RTCVideoViewObjectFitContain) : null,
      isMuted: voip.isMicMuted,
      hasVideo: hasLocalVideo,
      isScreenShare: isLocalScreen,
      avatarColor: _avatarColors[0],
      aspectRatio: hasLocalVideo ? ar(voip.localRenderer) : 16.0 / 9.0,
    ));

    return participants;
  }

  static const _avatarColors = [
    Color(0xFFFF6B9D), Color(0xFF06B6D4), Color(0xFFA855F7),
    Color(0xFF10B981), Color(0xFFF59E0B), Color(0xFFEF4444),
    Color(0xFF3B82F6), Color(0xFF84CC16),
  ];
}
