import { useEffect, useRef, useState } from "react";
import { ReactSortable, ReactSortableProps } from "react-sortablejs";
import { apiAuth, User } from "./api";
import { TeamState, useSession } from "./Session";
import TabController from "./TabController";
import { Chemistry, MVPRanking, PlayerType } from "./types";
import Loading from "./Loading";

type PlayerListProps = Partial<ReactSortableProps<any>> & {
  orderedList?: boolean;
  gender?: boolean;
};

function PlayerList(props: PlayerListProps) {
  const fmps = props.list?.filter((item) => item.gender === "fmp").length;
  return (
    <ReactSortable
      {...props}
      className="buttons is-centered is-clearfix"
      direction={"vertical"}
      animation={200}
      swapThreshold={1}
      handle=".handle"
      draggable=".handle"
    >
      {props.list &&
        props.list.map((item, index) => (
          <div className="handle" key={item.id}>
            <button
              className={
                "button is-primary is-light " +
                (props.gender ? item.gender : "")
              }
            >
              {props.orderedList
                ? props.gender
                  ? index +
                    1 -
                    (item.gender !== "fmp" ? fmps! : 0) +
                    ". " +
                    item.display_name
                  : index + 1 + ". " + item.display_name
                : item.display_name}
            </button>
          </div>
        ))}
    </ReactSortable>
  );
}

function PlayerMenuList(props: PlayerListProps) {
  const fmps = props.list?.filter((item) => item.gender === "fmp").length;
  return (
    <ReactSortable
      {...props}
      className="menu-list"
      animation={200}
      swapThreshold={1}
    >
      {props.list &&
        props.list.map((item, index) => (
          <p
            key={item.id}
            className={
              "menu-item is-primary is-light " +
              (props.gender ? item.gender : "")
            }
          >
            {props.orderedList
              ? props.gender
                ? index +
                  1 -
                  (item.gender !== "fmp" ? fmps! : 0) +
                  ". " +
                  item.display_name
                : index + 1 + ". " + item.display_name
              : item.display_name}
          </p>
        ))}
    </ReactSortable>
  );
}

function filterSort(list: User[], ids: number[]): User[] {
  const objectMap = new Map(list.map((obj) => [obj.id, obj]));
  const filteredAndSortedObjects = ids
    .map((id) => objectMap.get(id))
    .filter((obj) => obj !== undefined);
  return filteredAndSortedObjects;
}

interface PlayerInfoProps {
  user: User;
  teams: TeamState;
  players: User[];
}

function TypeDnD({ user, teams, players }: PlayerInfoProps) {
  const [availablePlayers, setAvailablePlayers] = useState<User[]>(players);
  const [handlers, setHandlers] = useState<User[]>([]);
  const [combis, setCombis] = useState<User[]>([]);
  const [cutters, setCutters] = useState<User[]>([]);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    handleGet();
  }, [players, teams]);

  const [dialog, setDialog] = useState("dialog");
  const dialogRef = useRef<HTMLDialogElement>(null);

  async function handleSubmit() {
    if (dialogRef.current) dialogRef.current.showModal();
    setDialog("sending...");
    let handlerlist = handlers.map(({ id }) => id);
    let combilist = combis.map(({ id }) => id);
    let cutterlist = cutters.map(({ id }) => id);
    const data = {
      user: user.id,
      handlers: handlerlist,
      combis: combilist,
      cutters: cutterlist,
      team: teams.activeTeam,
    };
    const response = await apiAuth("playertype", data, "PUT");
    setDialog(response || "try sending again");
  }

  async function handleGet() {
    setLoading(true);
    const data = await apiAuth(`playertype/${teams.activeTeam}`, null, "GET");
    if (data.detail) {
      console.log(data.detail);
      setAvailablePlayers(players);
      setHandlers([]);
      setCombis([]);
      setCutters([]);
    } else {
      const playertype = data as PlayerType;
      setAvailablePlayers(
        players.filter(
          (player) =>
            !playertype.handlers.includes(player.id) &&
            !playertype.combis.includes(player.id) &&
            !playertype.cutters.includes(player.id)
        )
      );
      setHandlers(filterSort(players, playertype.handlers));
      setCombis(filterSort(players, playertype.combis));
      setCutters(filterSort(players, playertype.cutters));
    }
    setLoading(false);
  }

  return (
    <>
      <HeaderControl
        onLoad={handleGet}
        onClear={() => {
          setAvailablePlayers(players);
          setHandlers([]);
          setCombis([]);
          setCutters([]);
        }}
        onSubmit={handleSubmit}
      />
      <div className="columns container is-multiline is-mobile is-1-mobile">
        <div className="column is-full is-flex is-justify-content-center">
          <div className="box" style={{ maxWidth: 800 }}>
            <p className="subtitle is-6 is-uppercase has-text-weight-light">
              available players
            </p>
            <PlayerList
              list={availablePlayers}
              setList={setAvailablePlayers}
              group={"type-shared"}
              className="dragbox reservoir"
            />
          </div>
        </div>
      </div>
      <div className="column">
        <div className="columns">
          <div className="column">
            <div className="box">
              <p className="subtitle is-6 is-uppercase has-text-weight-light">
                handler
              </p>
              <PlayerList
                list={handlers}
                setList={setHandlers}
                group={"type-shared"}
                className="dragbox"
              />
            </div>
          </div>
          <div className="column">
            <div className="box">
              <p className="subtitle is-6 is-uppercase has-text-weight-light">
                combi
              </p>
              <PlayerList
                list={combis}
                setList={setCombis}
                group={"type-shared"}
                className="middle dragbox"
              />
            </div>
          </div>
          <div className="column">
            <div className="box">
              <p className="subtitle is-6 is-uppercase has-text-weight-light">
                cutter
              </p>
              <PlayerList
                list={cutters}
                setList={setCutters}
                group={"type-shared"}
                className="dragbox"
              />
            </div>
          </div>
        </div>
      </div>
      <dialog
        ref={dialogRef}
        id="PlayerTypeDialog"
        onClick={(event) => {
          event.currentTarget.close();
        }}
      >
        {dialog}
      </dialog>
    </>
  );
}

function MVPDnD({ user, teams, players }: PlayerInfoProps) {
  const [availablePlayers, setAvailablePlayers] = useState<User[]>(players);
  const [rankedPlayers, setRankedPlayers] = useState<User[]>([]);
  const [loading, setLoading] = useState(false);
  const [mixed, setMixed] = useState(false);

  useEffect(() => {
    const activeTeam = teams.teams.find((team) => team.id == teams.activeTeam);
    activeTeam && setMixed(activeTeam.mixed);
    handleGet();
  }, [players, teams]);

  useEffect(() => {
    handleGet();
    // setMixedList(rankedPlayers);
  }, [mixed]);

  const [dialog, setDialog] = useState("dialog");
  const dialogRef = useRef<HTMLDialogElement>(null);

  async function handleSubmit() {
    if (dialogRef.current) dialogRef.current.showModal();
    setDialog("sending...");
    let mvps = rankedPlayers.map(({ id }) => id);
    const data = { user: user.id, mvps: mvps, team: teams.activeTeam };
    const response = await apiAuth("mvps", data, "PUT");
    response ? setDialog(response) : setDialog("try sending again");
  }

  const setMixedList = (newList: User[]) =>
    mixed
      ? setRankedPlayers(
          newList.sort((a, b) =>
            a.gender && b.gender ? a.gender.localeCompare(b.gender) : -1
          )
        )
      : setRankedPlayers(newList);

  async function handleGet() {
    setLoading(true);
    const data = await apiAuth(`mvps/${teams.activeTeam}`, null, "GET");
    if (data.detail) {
      console.log(data.detail);
      setAvailablePlayers(players);
      setRankedPlayers([]);
    } else {
      const mvps = data as MVPRanking;
      setMixedList(filterSort(players, mvps.mvps));
      setAvailablePlayers(
        players.filter((user) => !mvps.mvps.includes(user.id))
      );
    }
    setLoading(false);
  }

  return (
    <>
      <HeaderControl
        onLoad={handleGet}
        onClear={() => {
          setAvailablePlayers(players);
          setRankedPlayers([]);
        }}
        onSubmit={handleSubmit}
      />
      {loading ? (
        Loading
      ) : (
        <div className="columns container is-mobile is-1-mobile">
          <div className="column">
            <div className="box">
              <p className="subtitle is-6 is-uppercase has-text-weight-light">
                available players
              </p>
              <PlayerList
                list={availablePlayers}
                setList={setAvailablePlayers}
                group={{
                  name: "mvp-shared",
                }}
                className="dragbox"
                gender={mixed}
              />
            </div>
          </div>
          <div className="column">
            <div className="box">
              <p className="subtitle is-2 has-text-centered is-uppercase has-text-weight-light">
                🏆
              </p>
              <div className="menu">
                <PlayerMenuList
                  list={rankedPlayers}
                  setList={setMixedList}
                  group={{
                    name: "mvp-shared",
                  }}
                  className="dragbox"
                  orderedList
                  gender={mixed}
                />
              </div>
            </div>
          </div>
        </div>
      )}

      <dialog
        ref={dialogRef}
        id="MVPDialog"
        onClick={(event) => {
          event.currentTarget.close();
        }}
      >
        {dialog}
      </dialog>
    </>
  );
}

function ChemistryDnDMobile({ user, teams, players }: PlayerInfoProps) {
  var otherPlayers = players.filter((player) => player.id !== user.id);
  const [playersLeft, setPlayersLeft] = useState<User[]>([]);
  const [playersMiddle, setPlayersMiddle] = useState<User[]>(otherPlayers);
  const [playersRight, setPlayersRight] = useState<User[]>([]);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    handleGet();
  }, [players, teams]);

  const [dialog, setDialog] = useState("dialog");
  const dialogRef = useRef<HTMLDialogElement>(null);

  async function handleSubmit() {
    if (dialogRef.current) dialogRef.current.showModal();
    setDialog("sending...");
    let left = playersLeft.map(({ id }) => id);
    let middle = playersMiddle.map(({ id }) => id);
    let right = playersRight.map(({ id }) => id);
    const data = {
      user: user.id,
      hate: left,
      undecided: middle,
      love: right,
      team: teams.activeTeam,
    };
    const response = await apiAuth("chemistry", data, "PUT");
    setDialog(response || "try sending again");
  }

  async function handleGet() {
    setLoading(true);
    const data = await apiAuth(`chemistry/${teams.activeTeam}`, null, "GET");
    if (data.detail) {
      console.log(data.detail);
      setPlayersRight([]);
      setPlayersMiddle(otherPlayers);
      setPlayersLeft([]);
    } else {
      const chemistry = data as Chemistry;
      setPlayersLeft(filterSort(otherPlayers, chemistry.hate));
      setPlayersMiddle(
        otherPlayers.filter(
          (player) =>
            !chemistry.hate.includes(player.id) &&
            !chemistry.love.includes(player.id)
        )
      );
      setPlayersRight(filterSort(otherPlayers, chemistry.love));
    }
    setLoading(false);
  }

  return (
    <>
      <HeaderControl
        onLoad={handleGet}
        onClear={() => {
          setPlayersRight([]);
          setPlayersMiddle(otherPlayers);
          setPlayersLeft([]);
        }}
        onSubmit={handleSubmit}
      />
      {loading ? (
        Loading
      ) : (
        <div className="columns container is-multiline is-mobile is-1-mobile">
          <div className="column is-full is-flex is-justify-content-center">
            <div className="box" style={{ maxWidth: 800 }}>
              <p className="subtitle is-6 is-uppercase has-text-weight-light">
                neutral
              </p>
              <PlayerList
                list={playersMiddle}
                setList={setPlayersMiddle}
                group={"shared"}
              />
            </div>
          </div>
          <div className="column">
            <div className="columns is-mobile">
              <div className="column">
                <div className="box">
                  <p className="subtitle is-6 is-uppercase has-text-weight-light">
                    rather not
                  </p>
                  <PlayerList
                    list={playersLeft}
                    setList={setPlayersLeft}
                    group={"shared"}
                  />
                </div>
              </div>
              <div className="column">
                <div className="box">
                  <p className="subtitle is-6 is-uppercase has-text-weight-light">
                    ♥️
                  </p>
                  <PlayerList
                    list={playersRight}
                    setList={setPlayersRight}
                    group={"shared"}
                    orderedList
                  />
                </div>
              </div>
            </div>
          </div>
        </div>
      )}
      <dialog
        ref={dialogRef}
        id="ChemistryDialog"
        onClick={(event) => {
          event.currentTarget.close();
        }}
      >
        {dialog}
      </dialog>
    </>
  );
}

interface HeaderControlProps {
  onLoad: () => void;
  onClear: () => void;
  onSubmit: () => void;
}
function HeaderControl({ onLoad, onClear, onSubmit }: HeaderControlProps) {
  return (
    <div className="buttons is-centered">
      <button className="button is-small is-light" onClick={onLoad}>
        🗃️ &nbsp; restore previous
      </button>
      <button className="button is-small is-light" onClick={onClear}>
        🗑️&nbsp; start over
      </button>
      <button className="button is-small is-light" onClick={onSubmit}>
        💾 &nbsp; submit
      </button>
    </div>
  );
}

export default function Rankings() {
  const { user, teams, players } = useSession();
  const tabs = [
    { id: "Chemistry", label: "🧪 Chemistry" },
    { id: "MVP", label: "🏆 MVP" },
    { id: "Type", label: "🃏 Type" },
  ];

  return (
    <section className="section">
      <div className="container block">
        <p className="notification is-warning is-light">
          assign as many or as few players as you want and don't forget to 💾
          <strong> submit</strong> when you're done :)
        </p>
        {user && teams && players ? (
          <TabController tabs={tabs}>
            <ChemistryDnDMobile {...{ user, teams, players }} />
            <MVPDnD {...{ user, teams, players }} />
            <TypeDnD {...{ user, teams, players }} />
          </TabController>
        ) : (
          Loading
        )}
      </div>
    </section>
  );
}
