import React, { useState, useEffect, useCallback } from "react";
import Paper from "@mui/material/Paper";
import List from "@mui/material/List";
import "./PlayerList.css";
import { MediaControl, MediaAgent, Peer } from "./MediaControl";
import Box from "@mui/material/Box";
import { Session, Room } from "./GlobalContext";
import useWebSocket from "react-use-websocket";

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
  bot_run_id?: string;
  bot_provider_id?: string;
  bot_instance_id?: string; // For bot instances
  muted?: boolean;
  video_on?: boolean;
};

type PlayerListProps = {
  socketUrl: string;
  session: Session;
  roomId: string;
};

const PlayerList: React.FC<PlayerListProps> = (props: PlayerListProps) => {
  const { socketUrl, session, roomId } = props;
  const [Players, setPlayers] = useState<Player[] | null>(null);
  const [peers, setPeers] = useState<Record<string, Peer>>({});

  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
  const { sendJsonMessage } = useWebSocket(socketUrl, {
    share: true,
    shouldReconnect: (closeEvent) => true, // Auto-reconnect on connection loss
    reconnectInterval: 5000,
    onMessage: (event: MessageEvent) => {
      if (!session) {
        return;
      }
      const message = JSON.parse(event.data);
      const data: any = message.data;
      switch (message.type) {
        case "room_state": {
          type RoomStateData = {
            participants: Player[];
          };
          const room_state = data as RoomStateData;
          console.log(`Players - room_state`, room_state.participants);
          room_state.participants.forEach((Player) => {
            Player.local = Player.session_id === session.id;
          });
          room_state.participants.sort(sortPlayers);
          setPlayers(room_state.participants);
          // Initialize peers with remote mute/video state
          setPeers((prevPeers) => {
            const updated: Record<string, Peer> = { ...prevPeers };
            room_state.participants.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 "update_name": {
          // Update local session name immediately
          if (data && typeof data.name === "string") {
            session.name = data.name;
          }
          break;
        }
        case "peer_state_update": {
          // Update peer state in peers, but do not override local mute
          setPeers((prevPeers) => {
            const updated = { ...prevPeers };
            const peerId = data.peer_id;
            if (peerId && updated[peerId]) {
              updated[peerId] = {
                ...updated[peerId],
                muted: data.muted,
                video_on: data.video_on,
              };
            }
            return updated;
          });
          break;
        }
        default:
          break;
      }
    },
  });

  useEffect(() => {
    if (Players !== null) {
      return;
    }
    sendJsonMessage({
      type: "list_Players",
    });
  }, [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, socketUrl, peers, setPeers }} />
        <List className="PlayerSelector">
          {Players?.map((Player) => (
            <Box
              key={Player.session_id}
              sx={{ display: "flex", flexDirection: "column", alignItems: "center" }}
              className={`PlayerEntry ${Player.local ? "PlayerSelf" : ""}`}
            >
              <Box>
                <Box style={{ display: "flex-wrap", alignItems: "center", justifyContent: "space-between" }}>
                  <Box style={{ display: "flex-wrap", alignItems: "center" }}>
                    <div className="Name">{Player.name ? Player.name : Player.session_id}</div>
                    {Player.protected && (
                      <div
                        style={{ marginLeft: 8, fontSize: "0.8em", color: "#a00" }}
                        title="This name is protected with a password"
                      >
                        🔒
                      </div>
                    )}
                    {Player.bot_instance_id && (
                      <div style={{ marginLeft: 8, fontSize: "0.8em", color: "#00a" }} title="This is a bot">
                        🤖
                      </div>
                    )}
                  </Box>
                </Box>
                {Player.name && !Player.live && <div className="NoNetwork"></div>}
              </Box>
              {Player.name && Player.live && peers[Player.session_id] && (Player.local || Player.has_media !== false) ? (
                <MediaControl
                  className="Medium"
                  key={Player.session_id}
                  peer={peers[Player.session_id]}
                  isSelf={Player.local}
                  sendJsonMessage={Player.local ? sendJsonMessage : undefined}
                  remoteAudioMuted={peers[Player.session_id].muted}
                  remoteVideoOff={peers[Player.session_id].video_on === false}
                />
              ) : Player.name && Player.live && Player.has_media === 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>
              ) : (
                <video className="Video"></video>
              )}
            </Box>
          ))}
        </List>
      </Paper>
    </Box>
  );
};

export { PlayerList };
