/* eslint-disable @typescript-eslint/no-non-null-assertion */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable react-hooks/exhaustive-deps */
import { useEffect, useRef, useState } from "react";
import { PixelStreamingWrapper2 } from "../components/PixelStreamingWrapper2";
import api from "../utils/api";
import { useParams, useSearchParams } from "react-router-dom";
import useStateRef from "react-usestateref";
import Peer from "peerjs";
import useIsAudioActive from "use-is-audio-active";
import { v4 as uuidv4 } from "uuid";
import { io } from "socket.io-client";
import IRemoteStream from "../types/IRemoteStream";
import Video from "../components/Video";
import ModalContainer2 from "../components/ModalContainer2";
import IUser from "../types/IUser";
import useModalStore from "../stores/useModalStore";
import SetNameModal from "../components/modals/stream/SetNameModal";
import useStreamStore from "../stores/useStreamStore";
import Button from "../components/ui/Button";
import HandOnIcon from "../components/icons/HandOnIcon";
import HandOffIcon from "../components/icons/HandOffIcon";
import MicroOnIcon from "../components/icons/MicroOnIcon";
import MicroOffIcon from "../components/icons/MicroOffIcon";
import CameraOnIcon from "../components/icons/CameraOnIcon";
import CameraOffIcon from "../components/icons/CameraOffIcon";
import { Trans, useTranslation } from "react-i18next";
import { isIOS, isMobile, useMobileOrientation } from "react-device-detect";
import WindowIcon from "../components/icons/WindowIcon";
import FullscreenIcon from "../components/icons/FullscreenIcon";
import ShareIcon from "../components/icons/ShareIcon";
import { useFullscreen } from "ahooks";
import InviteModal from "../components/modals/stream/InviteModal";
import Tooltip from "../components/Tooltip";
import { toast, ToastContainer } from "react-toastify";
import LoadingModal from "../components/modals/stream/LoadingModal";
import useSocketStore from "../stores/useSocketStore";
import useStreamUserStore from "../stores/useStreamUserStore";
import Chat2 from "../components/Chat2";
import Rotate64Icon from "../components/icons/Rotate64Icon";
import Draggable from "react-draggable";
import DesktopIcon from "../components/icons/DesktopIcon";
import MobileIcon from "../components/icons/MobileIcon";
import ChatIcon from "../components/icons/ChatIcon";
import useChatStore from "../stores/useChatStore";
import UsersIcon from "../components/icons/UsersIcon";
import Users from "../components/Users";
import SpeedtestModal from "../components/modals/stream/SpeedtestModal";
import InternetSpeedHighIcon from "../components/icons/InternetSpeedHighIcon";
import InternetSpeedLowIcon from "../components/icons/InternetSpeedLowIcon";
import InternetSpeedMediumIcon from "../components/icons/InternetSpeedMediumIcon";
// import ChatIcon from "../components/icons/ChatIcon";

// import MoreIcon from "../components/icons/MoreIcon";

const userId = uuidv4();

function StreamPage() {
  const { t } = useTranslation();
  const params = useParams();
  const [searchParams] = useSearchParams();
  const [WSUrl, setWSUrl] = useState<string>("");

  const localVideoRef = useRef<HTMLVideoElement>(null);
  const [localStream, setLocalStream] = useState<MediaStream>(
    new MediaStream()
  );
  const [remoteStreams, setRemoteStreams, remoteStreamsRef] = useStateRef<
    IRemoteStream[]
  >([]);
  const [peerId, setPeerId] = useState<string>("");
  const [peerInstance, setPeerInstance] = useState<Peer>();
  const [permission, setPermission] = useState<boolean>();
  const isSpeaking = useIsAudioActive({
    source: localStream.getTracks().length ? localStream : null,
  });
  const { me, users, setMe, setUsers } = useStreamUserStore();
  const isCallInit = useRef<boolean>(false);
  const [roomId] = useState<string>(params.id!);
  const { socket, setSocket } = useSocketStore();
  const { setModal } = useModalStore();
  const { name } = useStreamStore();
  const [isMicEnabled, setIsMicEnabled] = useState(true);
  const [isCameraEnabled, setIsCameraEnabled] = useState(true);
  const [isEnded, setIsEnded] = useState<boolean>();
  const [, setEndAt] = useState<Date>();
  const fullscreenRef = useRef(null);
  const [isFullscreen, { toggleFullscreen }] = useFullscreen(fullscreenRef);
  const [isVideoInitialized, setIsVideoInitialized] = useState<boolean>(false);
  const [step, setStep] = useState<number>(1);
  const [isShowChat, setIsShowChat] = useState<boolean>(false);
  const [isShowUsers, setIsShowUsers] = useState<boolean>(false);
  const { isPortrait } = useMobileOrientation();
  const { setMessages } = useChatStore();
  const [activeSession, setActiveSession, activeSessionRef] =
    useStateRef<any>();
  const [downloadSpeed, setDownloadSpeed] = useState(0);

  async function startCall(remotePeerId: string) {
    if (!peerInstance) return;

    console.log("startCall", remotePeerId);

    const options = {
      constraints: {
        offerToReceiveVideo: true,
        offerToReceiveAudio: true,
      },
    };

    const call = peerInstance.call(remotePeerId, localStream, options as any);

    let accept = true;
    call.on("stream", (remoteStream) => {
      if (!accept) return;
      console.log("setRemoteStreams", remoteStream);
      setRemoteStreams((prev) => [
        ...prev,
        { peerId: remotePeerId, mediaStream: remoteStream },
      ]);
      accept = false;
    });
  }

  async function getUserMedia() {
    try {
      const mediaStream = await navigator.mediaDevices.getUserMedia({
        video: true,
        audio: true,
      });

      if (!localVideoRef.current) return;

      localVideoRef.current.srcObject = mediaStream;
      localVideoRef.current.onloadedmetadata = () => {
        localVideoRef.current?.play();
      };

      setLocalStream(mediaStream);
      setPermission(true);
      console.log("setLocalStream mediaStream", mediaStream);
    } catch (error) {
      setPermission(false);
      console.log("ERROR: ", error);
    }
  }

  function initPeer() {
    console.log("initPeer");

    const peer = new Peer({
      host: "stream.graff.tech",
      config: {
        iceServers: [
          {
            urls: "turn:185.173.176.83:3478", // Replace with your TURN server URL
            username: "username1", // Replace with your TURN username
            credential: "password1", // Replace with your TURN credential
          },
        ],
      },
    });

    peer.on("open", (id) => {
      setPeerId(id);
    });

    peer.on("call", (call) => {
      call.answer(localStream || undefined);

      let accept = true;
      call.on("stream", (remoteStream) => {
        if (!accept) return;
        setRemoteStreams((prev) => [
          ...prev,
          { peerId: call.peer, mediaStream: remoteStream },
        ]);
        accept = false;
      });
    });

    setPeerInstance(peer);
  }

  function initSocket() {
    const superAdmin = searchParams.has("admin", true);

    console.log("superAdmin", superAdmin);

    const socket = io(import.meta.env.VITE_SOCKET_URL, {
      transports: ["websocket"],
      auth: {
        roomId,
        user: {
          id: userId,
          name,
          peerId,
          superAdmin,
          isVideoInitialized,
          downloadSpeed,
        },
      },
    });

    socket.on("update", async (users: IUser[]) => {
      console.log("isCallInit", isCallInit.current);

      if (!isCallInit.current) {
        for (const user of users) {
          if (userId === user.id) continue;

          await startCall(user.peerId);
        }

        isCallInit.current = true;
      }

      setMe(users.find((user) => user.id === userId));
      setUsers(users);
    });

    socket.on("request-control", (userId) => {
      const user = users.find((user) => user.id === userId);

      if (user?.id === me?.id || !me?.isAdmin) return;

      toast.info(`${user?.name} ${t("toasts.requestPermission")}`);
    });

    socket.on("transfer-control", (userId) => {
      if (me?.id !== userId) return;

      toast.info(t("toasts.receivedPermission"));
    });

    socket.on("kick", (userId) => {
      if (useStreamUserStore.getState().me?.id !== userId) return;

      window.close();
      socket.disconnect();
      setPeerInstance(undefined);
      setWSUrl("");
      setUsers([]);
      setRemoteStreams([]);
    });

    socket.on("message", ({ userId, text }) => {
      setMessages([...useChatStore.getState().messages, { userId, text }]);
    });

    socket.on("connect", () => {
      setSocket(socket);
    });
  }

  function toggleMic() {
    localStream.getAudioTracks().forEach((track) => {
      track.enabled = !track.enabled;

      if (!permission) return;
      setIsMicEnabled(track.enabled);
      socket?.emit("mic-enabled", track.enabled);
    });
  }

  function toggleCamera() {
    localStream.getVideoTracks().forEach((track) => {
      track.enabled = !track.enabled;

      if (!permission) return;
      setIsCameraEnabled(track.enabled);
    });
  }

  useEffect(() => {
    if (!socket) return;
    console.log("socket", socket);
  }, [socket?.connected]);

  function updateRemoteStreams() {
    setTimeout(() => {
      console.log("users", users);

      const newRemoteStreams = remoteStreamsRef.current.filter((remoteStream) =>
        users.some((user) => user.peerId === remoteStream.peerId)
      );

      setRemoteStreams(newRemoteStreams);
    }, 500);
  }

  function handleSetName() {
    setStep(2);
    getUserMedia();
  }

  async function getWSUrl() {
    console.log("activeSession", activeSession);

    setWSUrl(
      `wss://${activeSessionRef.current.location}.sess.stream.graff.tech/server/${activeSessionRef.current.localIP}:${activeSessionRef.current.cirrusPort}`
    );
    setModal(<SetNameModal onAction={handleSetName} />);

    checkSessionStatus();
  }

  function transferControl(userId: string) {
    socket?.emit("transfer-control", userId);
  }

  function requestControl(userId: string) {
    socket?.emit("request-control", userId);
  }

  function kick(userId: string) {
    socket?.emit("kick", userId);
  }

  function videoInitialized() {
    socket?.emit("video-initialized", userId);
  }

  async function getActiveSession() {
    const activeSession: any = await api
      .get(`activeSessions/${params.id}`)
      .json();

    if (activeSession?.endAt) {
      setEndAt(activeSession.endAt);
    }

    return activeSession;
  }

  async function checkSessionStatus() {
    const activeSession = await getActiveSession();

    if (!activeSession || activeSession.status === "error") {
      setIsEnded(true);
      return;
    }

    setTimeout(async () => {
      await checkSessionStatus();
    }, 1000);
  }

  async function init() {
    const activeSession = await getActiveSession();

    console.log("activeSession init", activeSession);

    if (!activeSession || activeSession.status === "error") {
      setIsEnded(true);
      return;
    }

    setActiveSession(activeSession);
    setIsEnded(false);

    setModal(
      <SpeedtestModal
        onSuccess={(downloadSpeed) => {
          setDownloadSpeed(Math.round(downloadSpeed));
          getWSUrl();
        }}
      />
    );
  }

  useEffect(() => {
    init();
    // getWSUrl();
    // initSocket();
  }, []);

  useEffect(() => {
    console.log("permission", permission);

    if (permission === undefined) return;

    initPeer();
  }, [permission]);

  useEffect(() => {
    if (step !== 2) return;

    if (!isVideoInitialized) {
      setModal(<LoadingModal />);
    } else {
      videoInitialized();
      setModal(null);
    }
  }, [step, isVideoInitialized]);

  useEffect(() => {
    if (!peerId) return;

    initSocket();
  }, [peerId]);

  useEffect(() => {
    if (!users.length) return;

    updateRemoteStreams();
  }, [users.length]);

  useEffect(() => {
    toggleCamera();
    toggleMic();
  }, [localStream]);

  return (
    <div
      ref={fullscreenRef}
      className="h-dvh flex lg:flex-col bg-[#111C26] overflow-hidden"
    >
      {isEnded === false && (
        <>
          <Draggable
            disabled={true}
            positionOffset={!isMobile ? { x: "-50%", y: 0 } : { x: 0, y: 0 }}
            defaultClassName={`lg:fixed top-2 left-1/2 z-10 transition-opacity ${
              me ? "opacity-100" : "opacity-0"
            }`}
            defaultClassNameDragging="cursor-grabbing"
          >
            <div
              className={`flex flex-col px-2 bg-white max-lg:flex-col lg:h-12 lg:px-6 max-lg:py-2 lg:min-w-[744px] lg:rounded-lg`}
            >
              <div
                className={`flex flex-1 justify-between items-center max-lg:flex-col`}
              >
                <div className="lg:pr-6">
                  <img
                    src="/images/logo24.svg"
                    alt=""
                    className="hidden pointer-events-none lg:block"
                  />
                </div>
                <div className="flex gap-4 items-center max-lg:flex-col">
                  <div className="hidden gap-2 items-center lg:flex">
                    {/* <div className="relative w-6 h-6 bg-[#E6ECF2] rounded-full flex items-center justify-center">
                      <p className="text-xs font-semibold">
                        {name[0]?.toUpperCase()}
                      </p>
                      {me?.isControlAllowed && (
                        <div className="absolute bottom-0 right-0 bg-[#49A1F5] w-2 h-2 rounded-full border border-white"></div>
                      )}
                    </div> */}
                    {me && (
                      <div className="-mt-0.5">
                        {(me.downloadSpeed < 10 && <InternetSpeedLowIcon />) ||
                          (me.downloadSpeed < 20 && (
                            <InternetSpeedMediumIcon />
                          )) ||
                          (me.downloadSpeed >= 20 && <InternetSpeedHighIcon />)}
                      </div>
                    )}
                    <p className="text-xs">{name}</p>
                    <div className="text-[#CCCCCC]">
                      {isMobile ? <MobileIcon /> : <DesktopIcon />}
                    </div>
                  </div>
                  <div className="flex gap-2 items-center max-lg:flex-col">
                    <div className="relative group">
                      <Button
                        variant="secondary"
                        icon={
                          me?.isControlAllowed ? (
                            <HandOnIcon />
                          ) : (
                            <HandOffIcon />
                          )
                        }
                        onlyIcon
                        onClick={() =>
                          me!.isAdmin
                            ? transferControl(me!.id)
                            : requestControl(me!.id)
                        }
                      />
                      {me?.isAdmin && !me.isControlAllowed && (
                        <Tooltip text={t("tooltips.returnControl")} />
                      )}

                      {!me?.isAdmin && !me?.isControlAllowed && (
                        <Tooltip text={t("tooltips.requestControl")} />
                      )}
                    </div>

                    {permission && (
                      <>
                        <div className="relative group">
                          <Button
                            variant="secondary"
                            icon={
                              isMicEnabled ? <MicroOnIcon /> : <MicroOffIcon />
                            }
                            onlyIcon
                            onClick={toggleMic}
                          />
                          <Tooltip
                            text={
                              isMicEnabled
                                ? t("tooltips.turnOffMic")
                                : t("tooltips.turnOnMic")
                            }
                          />
                        </div>
                        <div className="relative group">
                          <Button
                            variant="secondary"
                            icon={
                              isCameraEnabled ? (
                                <CameraOnIcon />
                              ) : (
                                <CameraOffIcon />
                              )
                            }
                            onlyIcon
                            onClick={toggleCamera}
                          />
                          <Tooltip
                            text={
                              isCameraEnabled
                                ? t("tooltips.turnOffCamera")
                                : t("tooltips.turnOnCamera")
                            }
                          />
                        </div>
                      </>
                    )}
                  </div>
                  <div className="h-4 w-px bg-[#DAE0E5] lg:block hidden"></div>
                  <div className="flex gap-6">
                    <div className="relative group">
                      <Button
                        variant="secondary"
                        icon={<UsersIcon />}
                        onlyIcon
                        onClick={() => (
                          setIsShowUsers((prev) => !prev), setIsShowChat(false)
                        )}
                      />
                      <Tooltip
                        text={
                          isShowUsers
                            ? t("tooltips.hideParticipants")
                            : t("tooltips.showParticipants")
                        }
                      />
                      {users.filter((user) => user.id !== userId).length >
                        0 && (
                        <div className="absolute flex items-center justify-center w-4 h-4 bg-[#49A1F5] rounded-full -top-1 -right-1">
                          <p className="text-[10px] text-white">
                            {users.filter((user) => user.id !== userId).length}
                          </p>
                        </div>
                      )}
                    </div>
                    {/* {me &&
                      users.map((user) => {
                        if (user.id !== userId) {
                          return (
                            <User
                              me={me}
                              user={user}
                              handleTransferControl={() =>
                                transferControl(user.id)
                              }
                              handleKick={() => kick(user.id)}
                            />
                          );
                        }
                      })} */}
                  </div>
                </div>
                <div className="flex gap-2 items-center lg:gap-4 max-lg:flex-col lg:ml-auto">
                  <div className="relative group">
                    <Button
                      variant="secondary"
                      icon={<ChatIcon />}
                      onlyIcon
                      onClick={() => (
                        setIsShowChat((prev) => !prev), setIsShowUsers(false)
                      )}
                    />
                    <Tooltip
                      text={
                        isShowChat ? t("tooltips.hideChat") : t("tooltips.showChat")
                      }
                    />
                  </div>
                  <div className="w-px h-4 bg-[#DAE0E5] max-lg:hidden"></div>
                  <div className="flex gap-2 max-lg:flex-col lg:ml-auto">
                    <div className="relative group">
                      <Button
                        variant="secondary"
                        icon={<ShareIcon />}
                        onlyIcon
                        onClick={() => setModal(<InviteModal />)}
                      />
                      <Tooltip text={t("tooltips.share")} />
                    </div>
                    {!isIOS && (
                      <div className="relative group">
                        <Button
                          variant="secondary"
                          icon={
                            isFullscreen ? <WindowIcon /> : <FullscreenIcon />
                          }
                          onlyIcon
                          onClick={toggleFullscreen}
                        />
                        <Tooltip
                          text={
                            isFullscreen
                              ? t("tooltips.windowedMode")
                              : t("tooltips.fullscreenMode")
                          }
                        />
                      </div>
                    )}
                  </div>
                </div>
              </div>
            </div>
          </Draggable>
          <div className="flex relative flex-1">
            {WSUrl && (
              <PixelStreamingWrapper2
                initialSettings={{
                  AutoPlayVideo: true,
                  AutoConnect: true,
                  ss: WSUrl,
                  StartVideoMuted: true,
                  HoveringMouse: true,
                  WaitForStreamer: true,
                }}
                onVideoInitialized={() => setIsVideoInitialized(true)}
              />
            )}

            {step !== 1 &&
              !users.find((user) => user.id === userId)?.isControlAllowed && (
                <div
                  className="absolute top-0 left-0 w-full h-full"
                  onClick={() => toast.warn(t("toasts.needPermission"))}
                ></div>
              )}

            <Draggable
              disabled={isMobile}
              defaultClassName={`cursor-grab transition-opacity ${
                isMobile ? "overflow-y-auto h-dvh" : ""
              } ${me ? "opacity-100" : "opacity-0"}`}
              defaultClassNameDragging="cursor-grabbing"
            >
              <div className="absolute top-2 space-y-2 lg:left-2 max-lg:right-2">
                <div
                  className={`relative border-2 rounded-lg ${
                    !permission || !isCameraEnabled ? "hidden" : ""
                  } ${
                    isMicEnabled && isSpeaking
                      ? "border-green-500"
                      : "border-transparent"
                  }`}
                >
                  <video
                    ref={localVideoRef}
                    className={`object-cover bg-gray-500 rounded-lg aspect-video lg:w-[216px] w-[160px] lg:h-[162px] h-[120px] -scale-x-100`}
                    playsInline
                    autoPlay
                    muted
                  ></video>
                  <div className="absolute bottom-0 p-2">
                    <p className="text-xs text-white truncate lg:text-sm">
                      {name}
                    </p>
                  </div>
                </div>
                {remoteStreams.map(({ peerId, mediaStream }) => (
                  <Video
                    key={peerId}
                    mediaStream={mediaStream}
                    muted={!permission}
                    user={users.find((user) => user.peerId === peerId)}
                  />
                ))}
              </div>
            </Draggable>
          </div>

          {isShowChat && <Chat2 onClose={() => setIsShowChat(false)} />}
          {isShowUsers && (
            <Users
              onClose={() => setIsShowUsers(false)}
              transferControl={(userId) => transferControl(userId)}
              kick={(userId) => kick(userId)}
            />
          )}

          {isPortrait && (
            <div className="flex absolute top-0 left-0 flex-col gap-2 justify-center items-center w-full h-full bg-white">
              <Rotate64Icon />
              <p className="font-semibold">
                <Trans i18nKey={"stream.rotateDevice"}>Поверните устройство</Trans>
              </p>
            </div>
          )}

          <ToastContainer />
          <ModalContainer2 />
        </>
      )}

      {isEnded === true && (
        <div className="flex flex-1 justify-center items-center p-8">
          <p className="text-2xl text-center text-white font-gilroy">
            <Trans i18nKey={"demonstrationCompleted"}>
              Данная демонстрация была завершена
            </Trans>
          </p>
        </div>
      )}
    </div>
  );
}

export default StreamPage;
