import React, { useState, useEffect, useCallback, useContext, useMemo } from 'react';
import Paper from '@mui/material/Paper';
import List from '@mui/material/List';
import './PlayerList.css';
import { MediaControl, MediaAgent, Peer } from './MediaControl';
import { PlayerColor } from './PlayerColor';
import Box from '@mui/material/Box';
import { GlobalContext } from './GlobalContext';
import { styles } from './Styles';

type Player = {
  name: string;
  session_id: string;
  live: boolean;
  local: boolean /* Client side variable */;
  protected?: boolean;
  has_media?: boolean; // Whether this Player provides audio/video streams
  color?: string;
  bot_run_id?: string;
  bot_provider_id?: string;
  bot_instance_id?: string; // For bot instances
  muted?: boolean;
  video_on?: boolean;
};

const PlayerList: React.FC = () => {
  const { session, socketUrl, lastJsonMessage, sendJsonMessage } = useContext(GlobalContext);
  const [players, setPlayers] = useState<Player[]>([]);
  const [player, setPlayer] = useState<Player | null>(null);
  const [peers, setPeers] = useState<Record<string, Peer>>({});
  const [gameState, setGameState] = useState<string | undefined>(undefined);

  useEffect(() => {
    console.log('player-list - Mounted - requesting fields');
    if (sendJsonMessage) {
      sendJsonMessage({
        type: 'get',
        fields: ['participants'],
      });
    }
  }, [sendJsonMessage]);

  const sortPlayers = useCallback(
    (A: any, B: any) => {
      if (!session) {
        return 0;
      }
      /* active Player first */
      if (A.name === session.name) {
        return -1;
      }
      if (B.name === session.name) {
        return +1;
      }
      /* Sort active Players first */
      if (A.name && !B.name) {
        return -1;
      }
      if (B.name && !A.name) {
        return +1;
      }
      /* Otherwise, sort by color */
      if (A.color && B.color) {
        return A.color.localeCompare(B.color);
      }
      return 0;
    },
    [session]
  );

  // Use the WebSocket hook for room events with automatic reconnection
  useEffect(() => {
    if (!lastJsonMessage) {
      return;
    }
    const data: any = lastJsonMessage;
    switch (data.type) {
      case 'game-update': {
        console.log(`player-list - game-update:`, data.update);

        // Track game state if provided
        if ('state' in data.update) {
          setGameState(data.update.state);
        }

        // Handle participants list
        if ('participants' in data.update && data.update.participants) {
          const participantsList: Player[] = data.update.participants;
          console.log(`player-list - participants:`, participantsList);

          participantsList.forEach(player => {
            player.local = player.session_id === session?.id;
            if (player.local) {
              setPlayer(player);
            }
          });
          participantsList.sort(sortPlayers);
          console.log(`player-list - sorted participants:`, participantsList);
          setPlayers(participantsList);

          // Initialize peers with remote mute/video state
          setPeers(prevPeers => {
            const updated: Record<string, Peer> = { ...prevPeers };
            participantsList.forEach(player => {
              // Only update remote peers, never overwrite local peer object
              if (!player.local && updated[player.session_id]) {
                updated[player.session_id] = {
                  ...updated[player.session_id],
                  muted: player.muted ?? false,
                  video_on: player.video_on ?? true,
                };
              }
            });
            return updated;
          });
        }
        break;
      }
      case 'peer_state_update': {
        // Update peer state in peers, but do not override local mute
        setPeers(prevPeers => {
          const updated = { ...prevPeers };
          const peerId = data.data?.peer_id || data.peer_id;
          if (peerId && updated[peerId]) {
            updated[peerId] = {
              ...updated[peerId],
              muted: data.data?.muted ?? data.muted,
              video_on: data.data?.video_on ?? data.video_on,
            };
          }
          return updated;
        });
        break;
      }
      default:
        // console.log(`player-list - ignoring message: ${data.type}`);
        break;
    }
  }, [lastJsonMessage, session, sortPlayers, setPeers, setPlayers]);

  // Compute which colors are already taken
  const availableColors = useMemo(() => {
    const assignedColors = new Set(players.filter(p => p.color !== 'unassigned').map(p => p.color));
    return ['O', 'R', 'W', 'B'].filter(color => !assignedColors.has(color));
  }, [players]);

  useEffect(() => {
    if (players.length !== 0 || !sendJsonMessage) {
      return;
    }
    // Request participants list
    sendJsonMessage({
      type: 'get',
      fields: ['participants'],
    });
  }, [players, sendJsonMessage]);

  return (
    <Box sx={{ position: 'relative', width: '100%' }}>
      <Paper
        className={`PlayerList Medium`}
        sx={{
          maxWidth: { xs: '100%', sm: 500 },
          p: { xs: 1, sm: 2 },
          m: { xs: 0, sm: 2 },
        }}
      >
        <MediaAgent {...{ session, peers, setPeers }} />
        <List className="PlayerSelector Players">
          {players
            .filter(p => p.color && p.color !== 'unassigned')
            .map(player => {
              const peerObj = peers[player.session_id] || peers[player.name];
              const playerStyle = player.color !== 'unassigned' ? styles[player.color] : {};
              return (
                <Box
                  key={player.session_id}
                  sx={{
                    display: 'flex',
                    flexDirection: 'column',
                    alignItems: 'center',
                    p: 1,
                    borderRadius: '0.25rem',
                    ...playerStyle,
                  }}
                  className={`PlayerEntry ${player.local ? 'PlayerSelf' : ''}`}
                >
                  <Box
                    style={{
                      display: 'flex-wrap',
                      alignItems: 'center',
                      justifyContent: 'space-between',
                    }}
                  >
                    <Box style={{ display: 'flex-wrap', alignItems: 'center' }} className="Name">
                      {player.bot_instance_id && <>🤖</>}
                      {player.name ? player.name : player.session_id}
                    </Box>
                    {player.name && !player.live && <Box className="NoNetwork"></Box>}
                  </Box>
                  {player.name && player.live ? (
                    <MediaControl
                      key={player.session_id}
                      peer={peerObj}
                      isSelf={player.local}
                      sendJsonMessage={player.local ? sendJsonMessage : undefined}
                      remoteAudioMuted={peerObj?.muted}
                      remoteVideoOff={peerObj?.video_on === false}
                    />
                  ) : (
                    <div
                      className="Video fade-in"
                      style={{
                        background: '#333',
                        color: '#fff',
                        display: 'flex',
                        alignItems: 'center',
                        justifyContent: 'center',
                        width: '100%',
                        height: '100%',
                        fontSize: '14px',
                      }}
                    >
                      💬 Chat Only
                    </div>
                  )}
                </Box>
              );
            })}
        </List>
        {gameState === 'lobby' && (
          <Paper sx={{ p: 0.5, mt: 0.5, backgroundColor: '#f9f9f9' }}>
            <div style={{ marginBottom: 6, fontSize: '0.9em' }}>
              {player && player.color !== 'unassigned' ? 'Change' : 'Pick'} your color:
            </div>
            <Box style={{ display: 'flex', gap: 8 }}>
              {availableColors.map(c => {
                return (
                  <Box
                    key={c}
                    sx={{
                      display: 'flex',
                      alignItems: 'center',
                      cursor: 'pointer',
                    }}
                    onClick={() => {
                      sendJsonMessage({ type: 'set', field: 'color', value: c });
                    }}
                  >
                    <PlayerColor color={c} />
                  </Box>
                );
              })}
            </Box>
          </Paper>
        )}
        <Paper>
          <List className="PlayerSelector Observers">
            {players
              .filter(p => !p.color || p.color === 'unassigned')
              .map(player => {
                const peerObj = peers[player.session_id] || peers[player.name];
                return (
                  <Box
                    key={player.session_id}
                    sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}
                    className={`PlayerEntry ${player.local ? 'PlayerSelf' : ''}`}
                    data-selectable={player.local && gameState === 'lobby'}
                  >
                    <Box
                      style={{
                        display: 'flex-wrap',
                        alignItems: 'center',
                        justifyContent: 'space-between',
                      }}
                    >
                      <Box style={{ display: 'flex-wrap', alignItems: 'center' }} className="Name">
                        {player.bot_instance_id && <>🤖</>}
                        {player.name ? player.name : player.session_id}
                      </Box>
                      {player.name && !player.live && <Box className="NoNetwork"></Box>}
                    </Box>

                    {/* Show media control if available */}
                    {player.name &&
                      player.live &&
                      peerObj &&
                      (player.local || player.has_media !== false) && (
                        <MediaControl
                          key={player.session_id}
                          peer={peerObj}
                          isSelf={player.local}
                          sendJsonMessage={player.local ? sendJsonMessage : undefined}
                          remoteAudioMuted={peerObj?.muted}
                          remoteVideoOff={peerObj?.video_on === false}
                        />
                      )}
                  </Box>
                );
              })}
          </List>
        </Paper>
      </Paper>
    </Box>
  );
};

export { PlayerList };
