"use client";
import { useState, useEffect } from "react";
import { Markazi_Text, Nunito } from "next/font/google";
import { useRouter } from "next/navigation";
import Image from "next/image";
import Link from "next/link";
import { useAuth } from "react-oidc-context";
import { useSession } from "muzak/contexts/SessionContext";
import { getUser, api, Track } from "muzak/data/fetcher";
import getSessionId from "muzak/data/session";
import { useSpotifyIframe } from "muzak/contexts/SpotifyIframe";

const nunito = Nunito({
  weight: "900",
  subsets: ["latin"],
});

const MAX_PARTY_SIZE = 8;

export default function Lobby() {
  const [userList, setUserList] = useState<any[]>([]);
  const [noList, setNoList] = useState<any[]>([]);
  const [yesList, setYesList] = useState<any[]>([]);
  const [sessionSocket, setSessionSocket] = useState<WebSocket | null>(null);
  const { sessionId, setSessionId } = useSession();
  const [sessionState, setSessionState] = useState("lobby");
  const [currentSong, setCurrentSong] = useState<Track>();
  const [songLoading, setSongLoading] = useState(false);
  const [spotifyId, setSpotifyId] = useState<string | null>(null);
  const auth = useAuth();
  const user = getUser();
  const router = useRouter();
  const controller = useSpotifyIframe();
  const [revealed, setRevealed] = useState(false);
  const [playingPercentage, setPlayingPercentage] = useState(0);
  const [secondsLeft, setSecondsLeft] = useState(30);
  const [state, setState] = useState("lobby"); // lobby, playing, waiting, loading

  // Main message handler and dispatcher
  function onMessage(e) {
    console.log(e);
    let data = JSON.parse(e.data);
    for (let key in data) {
      if (key === "joined") {
        addUser(data[key]);
      } else if (key == "track") {
        getTrack();
      } else if (key == "voted") {
        voteUser(data[key]);
      } else if (key == "done") {
        router.push("/post-game");
      }
    }
    console.log(data);
  }

  // Setup session
  useEffect(() => {
    //console.log("session: ", sessionId);
    let socket: WebSocket | null;
    if (sessionId) {
      socket = new WebSocket(
        `${process.env.NEXT_PUBLIC_WS_HOST}/voting/session/${sessionId}/`,
      );
      socket.onmessage = onMessage;
      setSessionSocket(socket);
      // console.log("session made: ", sessionId);
    }
    return () => {
      if (socket) {
        socket.close();
      }
    };
  }, [sessionId]);
  async function setSession() {
    const id = await getSessionId();
    setSessionId(id);
    console.log("Session ID:", id);
  }
  useEffect(() => {
    if (!auth.isLoading && !auth.error && auth.isAuthenticated) {
      setSession();
    }
  }, [auth]);

  function startSession() {
    setSessionState("voting");
    setState("loading");
    getTrack();
  }

  function addUser(user: object) {
    const newUser = {
      id: user["id"],
      name: user["username"],
      avatar: `https://api.dicebear.com/9.x/bottts-neutral/svg?seed=${user["id"]}`,
      hidden: false,
    };

    setUserList((prevUserList) => {
      if (prevUserList.find((u) => u.id === user["id"])) {
        console.log("User already exists, not adding");
        return prevUserList;
      }
      return [...prevUserList, newUser];
    });
  }

  // Visually processes the incoming vote for a user.
  function voteUser(vote: object) {
    const userId = vote["id"];
    const userName = vote["username"];
    const points = vote["points"];
    if (points === 0) {
      setYesList((prevYesList) => {
        //if (prevYesList.find((u) => u.id === userId)) return prevYesList;
        return prevYesList.filter((u) => u.id !== userId);
      });
      setNoList((prevNoList) => {
        if (prevNoList.find((u) => u.id === userId)) {
          return prevNoList;
        }
        return [
          ...prevNoList,
          {
            id: userId,
            name: userName,
            avatar: `https://api.dicebear.com/9.x/bottts-neutral/svg?seed=${userId}`,
          },
        ];
      });
    } else {
      setNoList((prevNoList) => {
        return prevNoList.filter((u) => u.id !== userId);
      });
      setYesList((prevYesList) => {
        if (prevYesList.find((u) => u.id === userId)) {
          return prevYesList;
        }
        return [
          ...prevYesList,
          {
            id: userId,
            name: userName,
            avatar: `https://api.dicebear.com/9.x/bottts-neutral/svg?seed=${userId}`,
          },
        ];
      });
    }
    setUserList((prevUserList) => {
      // Set hidden true on the user that voted:
      return prevUserList.map((user) => {
        if (user.id === userId) {
          return { ...user, hidden: true };
        }
        return user;
      });
    });
  }

  async function getTrack() {
    setSongLoading(true);
    setState("loading");
    setUserList((prevUserList) => {
      return prevUserList.map((user) => {
        return { ...user, hidden: false };
      });
    });
    setYesList([]);
    setNoList([]);
    const { data: session } = await api.sessions.get({ session_id: sessionId });
    const trackId = session?.current_track;
    if (trackId) {
      const { data: track } = await api.tracks.detail({ id: trackId });
      console.log(session);
      console.log(track);
      setCurrentSong(track);
    } else {
      nextTrack();
    }
    setSpotifyId(session?.current_track);
    setSongLoading(false);
  }

  async function nextTrack() {
    console.log("nextTrack");
    setState("loading");
    setRevealed(false);
    setSongLoading(true);
    sessionSocket.send(
      JSON.stringify({
        action: "next",
        token: user.access_token,
      }),
    );
  }

  async function endPlay() {
    controller?.seek(100);
  }

  // Spotify Player stuff
  useEffect(() => {
    if (controller) {
      console.log("Loaded track:", spotifyId);
      controller.loadUri(`spotify:track:${spotifyId}`);
      controller.play();
      // Note: do not set playing state here, but later when its actually playing.
      console.log(controller._listeners);
      if (controller._listeners["playback_update"].length === 0) {
        controller.addListener("playback_update", (e) => {
          updatePlayback(e);
        });
      }
    } else {
      console.log("Spotify player not initialized");
    }
  }, [controller, spotifyId]);
  function updatePlayback(e) {
    let duration = e.data.duration;
    let playingPosition = e.data.position;
    const playingSeconds = Math.floor((duration - playingPosition) / 1000);
    setPlayingPercentage((playingPosition / duration) * 100);
    setSecondsLeft((s) => {
      setState((state) => {
        if (playingSeconds >= 1) {
          return "playing";
        }
        if (state == "playing" && s <= 0) {
          console.log("track ended");
          return "waiting";
        }
        return state;
      });
      return playingSeconds;
    });
  }
  async function playTrack() {
    controller.play();
  }
  async function pauseTrack() {
    controller.togglePlay();
  }

  useEffect(() => {
    console.log("useEffect state:", state);
    if (state == "waiting") {
      setRevealed(true);
      setTimeout(() => {
        setState("next");
      }, 5000);
    } else if (state == "next") {
      nextTrack();
    }
  }, [state]);

  if (sessionState == "lobby") {
    return (
      <main className="relative flex min-h-screen flex-col items-center justify-between p-24">
        <div className="absolute top-[-1000px]">
          <div id="splayer"></div>
        </div>
        <div>
          <h1
            className={`${nunito.className} text-outline text-[42px] tracking-tighter text-yellow-500`}
          >
            LOBBY
          </h1>
        </div>

        <div className="absolute inset-1/2 flex min-h-[532px] min-w-[500px] -translate-x-1/2 -translate-y-1/2 flex-col items-center justify-start gap-4 rounded-md bg-blue-950/80 p-8">
          <div className="flex w-full flex-row items-center justify-between px-1">
            <div className="text-3xl font-bold text-yellow-500">
              Players: {userList.length}
            </div>
            <button
              onClick={startSession}
              className="rounded-lg border-2 border-black bg-yellow-500 p-4 text-2xl font-extrabold text-blue-600 hover:bg-yellow-400 disabled:bg-yellow-900 disabled:text-gray-400"
              disabled={sessionId === null}
            >
              START
            </button>
          </div>

          {userList.length === 0 ? (
            <div className="mt-31 min-w-52 text-3xl font-semibold text-white drop-shadow-sm drop-shadow-gray-900">
              Waiting for players...
            </div>
          ) : (
            <div className="grid min-w-52 grid-flow-row grid-cols-2 items-start justify-start gap-4">
              {userList.map((user) => (
                <div
                  key={user.id}
                  className="flex min-w-51 items-center gap-x-4 rounded-l-[40px] rounded-r-lg border-2 bg-orange-400/90 p-2"
                >
                  <img
                    src={user.avatar}
                    alt={user.name}
                    className="h-16 w-16 rounded-full bg-gray-300"
                  />
                  <span className="text-2xl font-semibold text-white">
                    {user.name}
                  </span>
                  {user.host && (
                    <div className="rounded-full bg-blue-950 p-[5px]">
                      <Image
                        src="/crown.png"
                        width={24}
                        height={24}
                        alt="Crown image"
                        className="p-[1px]"
                      />
                    </div>
                  )}
                </div>
              ))}
            </div>
          )}
        </div>
      </main>
    );
  } else if (sessionState == "voting") {
    return (
      <main className="flex min-h-screen flex-col items-center justify-between gap-4 p-24">
        <div className="flex w-full items-start justify-between text-center">
          <div className="flex-1"></div>
          <div className="flex flex-1 items-center justify-center">
            {(state == "playing" || state == "waiting") && (
              <div
                className={`flex h-[170px] w-[170px] items-center justify-center rounded-full border-2 ${state == "playing" ? "bg-orange-400" : ""} ${state == "waiting" ? "bg-green-400" : ""}`}
              >
                <div className="text-5xl text-white drop-shadow-sm drop-shadow-black">
                  {secondsLeft}
                </div>
              </div>
            )}
          </div>

          <div className="flex flex-1 flex-row items-center justify-end gap-4">
            <button
              className="w-30 rounded-lg border-2 border-black bg-yellow-500 p-4 text-2xl font-extrabold text-blue-600 hover:bg-yellow-400"
              onClick={playTrack}
            >
              PLAY
            </button>
            <button
              onClick={pauseTrack}
              className="w-30 rounded-lg border-2 border-black bg-yellow-500 p-4 text-2xl font-extrabold text-blue-600 hover:bg-yellow-400"
            >
              PAUSE
            </button>
            <button
              className="w-30 rounded-lg border-2 border-black bg-yellow-500 p-4 text-2xl font-extrabold text-blue-600 hover:bg-yellow-400"
              onClick={endPlay}
            >
              NEXT
            </button>
          </div>
        </div>

        <div className="flex flex-col items-center justify-center">
          <div className="flex flex-row items-center justify-center gap-x-36">
            <div className="relative w-fit overflow-hidden">
              <div className="grid min-h-[516px] min-w-[516px] grid-flow-row grid-cols-3 place-items-center items-start justify-center gap-4 rounded bg-blue-950/80 px-4 pt-10">
                {noList.map((user) => (
                  <div
                    key={user.id}
                    className="flex h-[120px] w-[120px] flex-col items-center justify-center p-4"
                  >
                    <img
                      src={user.avatar}
                      alt={user.name}
                      width={100}
                      height={100}
                    />
                    <div className="mt-1 min-w-[90px] rounded-3xl px-3 text-center text-3xl font-semibold text-white">
                      {user.name}
                    </div>
                  </div>
                ))}{" "}
              </div>
              <div
                className={`absolute inset-0 flex items-center justify-center rounded bg-red-800 text-5xl font-bold text-white shadow-[inset_0_0_20px_rgba(0,0,0,0.3)] transition-transform duration-1000 ease-in-out ${
                  revealed ? "-translate-y-full" : "translate-y-0"
                }`}
                style={{
                  backgroundImage: `
                 linear-gradient(to bottom, rgba(0,0,0,0.2), rgba(0,0,0,0) 20%, rgba(0,0,0,0.2) 80%, rgba(0,0,0,0.2)),
                 repeating-linear-gradient(
                  90deg,
                  rgba(255,255,255,0.1),
                  rgba(255,255,255,0.1) 30px,
                  rgba(0,0,0,0) 30px,
                  rgba(0,0,0,0) 60px
                )`,
                  clipPath:
                    "polygon(0 0, 100% 0, 100% 98%, 95% 100%, 90% 98%, 85% 100%, 80% 98%, 75% 100%, 70% 98%, 65% 100%, 60% 98%, 55% 100%, 50% 98%, 45% 100%, 40% 98%, 35% 100%, 30% 98%, 25% 100%, 20% 98%, 15% 100%, 10% 98%, 5% 100%, 0 98%)",
                }}
              >
                Meh
              </div>
            </div>
            {!songLoading && currentSong ? (
              <div className="rounded-md bg-black p-2">
                <Image
                  src={currentSong.album_cover}
                  alt={currentSong.name}
                  width={500}
                  height={500}
                />
              </div>
            ) : (
              <div className="rounded-md border-8 border-black bg-blue-950/80 py-[1px]">
                <Image
                  src="/cdspin.gif"
                  alt="Loading..."
                  width={500}
                  height={500}
                  className="rounded-md"
                />
              </div>
            )}
            <div className="relative w-fit overflow-hidden">
              <div className="grid min-h-[516px] min-w-[516px] grid-flow-row grid-cols-3 place-items-center items-start justify-center gap-4 rounded bg-blue-950/80 px-4 pt-10">
                {yesList.map((user) => (
                  <div
                    key={user.id}
                    className="flex h-[120px] w-[120px] flex-col items-center justify-center p-4"
                  >
                    <img
                      src={user.avatar}
                      alt={user.name}
                      width={100}
                      height={100}
                    />
                    <div className="mt-1 min-w-[90px] rounded-3xl px-3 text-center text-3xl font-semibold text-white">
                      {user.name}
                    </div>
                  </div>
                ))}{" "}
              </div>
              <div
                className={`absolute inset-0 flex items-center justify-center rounded bg-red-800 text-5xl font-bold text-white shadow-[inset_0_0_20px_rgba(0,0,0,0.3)] transition-transform duration-1000 ease-in-out ${
                  revealed ? "-translate-y-full" : "translate-y-0"
                }`}
                style={{
                  backgroundImage: `
                   linear-gradient(to bottom, rgba(0,0,0,0.2), rgba(0,0,0,0) 20%, rgba(0,0,0,0.2) 80%, rgba(0,0,0,0.2)),
                   repeating-linear-gradient(
                    90deg,
                    rgba(255,255,255,0.1),
                    rgba(255,255,255,0.1) 30px,
                    rgba(0,0,0,0) 30px,
                    rgba(0,0,0,0) 60px
                  )`,
                  clipPath:
                    "polygon(0 0, 100% 0, 100% 98%, 95% 100%, 90% 98%, 85% 100%, 80% 98%, 75% 100%, 70% 98%, 65% 100%, 60% 98%, 55% 100%, 50% 98%, 45% 100%, 40% 98%, 35% 100%, 30% 98%, 25% 100%, 20% 98%, 15% 100%, 10% 98%, 5% 100%, 0 98%)",
                }}
              >
                Yeah
              </div>
            </div>
          </div>
          {!songLoading && currentSong ? (
            <div className="flex flex-col items-center justify-start">
              <h2
                className={`${nunito.className} text-outline text-[42px] tracking-tighter text-yellow-500`}
              >
                {currentSong.artist}
              </h2>
              <h2
                className={`${nunito.className} text-outline text-[42px] tracking-tighter text-yellow-500`}
              >
                {currentSong.name}
              </h2>
            </div>
          ) : (
            <div className="flex flex-col items-center justify-start">
              <h2
                className={`${nunito.className} text-outline text-[42px] tracking-tighter text-yellow-500`}
              >
                Loading
              </h2>
              <h2
                className={`${nunito.className} text-outline text-[42px] tracking-tighter text-yellow-500`}
              >
                ...
              </h2>
            </div>
          )}
        </div>

        <div
          className={`flex min-h-33 min-w-1 flex-row items-start justify-start gap-10 rounded p-4 ${userList.some((u) => !u.hidden) ? "bg-blue-950/80" : "bg-transparent p-0"} `}
        >
          {userList.map((user) => (
            <div
              key={user.id}
              className={`flex h-[100px] w-[100px] flex-col items-center justify-center p-4 ${user.hidden ? "hidden" : ""}`}
            >
              <img src={user.avatar} alt={user.name} width={75} height={75} />
              <div className="mt-1 min-w-[90px] rounded-3xl px-3 text-center text-3xl font-semibold text-white">
                {user.name}
              </div>
            </div>
          ))}
        </div>
      </main>
    );
  }
}
