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

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

function PlayerList(props: PlayerListProps) {
  return (
    <ReactSortable
      {...props}
      animation={200}
      swapThreshold={0.2}
      style={{ minHeight: props.list && props.list?.length < 1 ? 64 : 32 }}
    >
      {props.list?.map((item, index) => (
        <div key={item.id} className="item">
          {props.orderedList
            ? index + 1 + ". " + item.display_name
            : item.display_name}
        </div>
      ))}
    </ReactSortable>
  );
}

const LoadButton = (props: ButtonHTMLAttributes<HTMLButtonElement>) => {
  return (
    <button {...props} style={{ padding: "4px 16px" }}>
      🗃️ restore previous
    </button>
  );
};

const ClearButton = (props: ButtonHTMLAttributes<HTMLButtonElement>) => {
  return (
    <button {...props} style={{ padding: "4px 16px" }}>
      🗑️ start over
    </button>
  );
};

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 ChemistryDnD({ 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]);

  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([]);
        }}
      />
      {loading ? (
        <span className="loader" style={{ width: 300 }} />
      ) : (
        <div className="container">
          <div className="box three">
            <h2>😬</h2>
            {playersLeft.length < 1 && (
              <span className="grey hint">
                drag people here that you'd rather not play with
              </span>
            )}
            <PlayerList
              list={playersLeft}
              setList={setPlayersLeft}
              group={"shared"}
              className="dragbox"
            />
          </div>
          <div className="box three">
            <h2>🤷</h2>
            <PlayerList
              list={playersMiddle}
              setList={setPlayersMiddle}
              group={"shared"}
              className="middle dragbox"
            />
          </div>
          <div className="box three">
            <h2>😍</h2>
            {playersRight.length < 1 && (
              <span className="grey hint">
                drag people here that you love playing with from best to ... ok
              </span>
            )}
            <PlayerList
              list={playersRight}
              setList={setPlayersRight}
              group={"shared"}
              className="dragbox"
              orderedList
            />
          </div>
        </div>
      )}

      <button className="submit wavering" onClick={() => handleSubmit()}>
        💾 <span className="submit_text">submit</span>
      </button>
      <dialog
        ref={dialogRef}
        id="ChemistryDialog"
        onClick={(event) => {
          event.currentTarget.close();
        }}
      >
        {dialog}
      </dialog>
    </>
  );
}

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]);

  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([]);
        }}
      />
      <div className="container">
        <div className="box one">
          <PlayerList
            list={availablePlayers}
            setList={setAvailablePlayers}
            group={"type-shared"}
            className="dragbox reservoir"
          />
        </div>
      </div>
      <div className="container">
        <div className="box three">
          <h4>handler</h4>
          {handlers.length < 1 && (
            <span className="grey hint">
              drag people here that you like to see as handlers
            </span>
          )}
          <PlayerList
            list={handlers}
            setList={setHandlers}
            group={"type-shared"}
            className="dragbox"
          />
        </div>
        <div className="box three">
          <h4>combi</h4>
          {combis.length < 1 && (
            <span className="grey hint">
              drag people here that switch between handling and cutting
            </span>
          )}
          <PlayerList
            list={combis}
            setList={setCombis}
            group={"type-shared"}
            className="middle dragbox"
          />
        </div>
        <div className="box three">
          <h4>cutter</h4>
          {cutters.length < 1 && (
            <span className="grey hint">
              drag people here that you think are the best cutters
            </span>
          )}
          <PlayerList
            list={cutters}
            setList={setCutters}
            group={"type-shared"}
            className="dragbox"
          />
        </div>
      </div>
      <button className="submit wavering" onClick={() => handleSubmit()}>
        💾 <span className="submit_text">submit</span>
      </button>
      <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);

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

  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");
  }

  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;
      setRankedPlayers(filterSort(players, mvps.mvps));
      setAvailablePlayers(
        players.filter((user) => !mvps.mvps.includes(user.id))
      );
    }
    setLoading(false);
  }

  return (
    <>
      <HeaderControl
        onLoad={handleGet}
        onClear={() => {
          setAvailablePlayers(players);
          setRankedPlayers([]);
        }}
      />
      {loading ? (
        <span className="loader" style={{ width: 300 }} />
      ) : (
        <div className="container">
          <div className="box two">
            <h2>🥏🏃</h2>
            {availablePlayers.length < 1 && (
              <span className="grey hint">all sorted 👍</span>
            )}
            <PlayerList
              list={availablePlayers}
              setList={setAvailablePlayers}
              group={{
                name: "mvp-shared",
                pull: function (to) {
                  return to.el.classList.contains("putclone") ? "clone" : true;
                },
              }}
              className="dragbox"
            />
          </div>
          <div className="box two">
            <h1>🏆</h1>
            {rankedPlayers.length < 1 && (
              <span className="grey hint">
                carefully place as many of the <i>Most Valuable Players</i>{" "}
                (according to your humble opinion) in this box
              </span>
            )}
            <PlayerList
              list={rankedPlayers}
              setList={setRankedPlayers}
              group={{
                name: "mvp-shared",
                pull: function (to) {
                  return to.el.classList.contains("putclone") ? "clone" : true;
                },
              }}
              className="dragbox"
              orderedList
            />
          </div>
        </div>
      )}

      <button className="submit wavering" onClick={() => handleSubmit()}>
        💾 <span className="submit_text">submit</span>
      </button>
      <dialog
        ref={dialogRef}
        id="MVPDialog"
        onClick={(event) => {
          event.currentTarget.close();
        }}
      >
        {dialog}
      </dialog>
    </>
  );
}

interface HeaderControlProps {
  onLoad: () => void;
  onClear: () => void;
}
function HeaderControl({ onLoad, onClear }: HeaderControlProps) {
  return (
    <>
      <div>
        <ClearButton onClick={onClear} />
        <LoadButton onClick={onLoad} />
      </div>
      <div>
        <span className="grey">
          assign as many or as few players as you want and don't forget to{" "}
          <b>submit</b> 💾 when you're done :)
        </span>
      </div>
    </>
  );
}

export default function Rankings() {
  const { user, teams, players } = useSession();

  const tabs = [
    { id: "Chemistry", label: "🧪 Chemistry" },
    { id: "Type", label: "🃏 Type" },
    { id: "MVP", label: "🏆 MVP" },
  ];

  return (
    <>
      {user && teams && players ? (
        <TabController tabs={tabs}>
          <ChemistryDnD {...{ user, teams, players }} />
          <TypeDnD {...{ user, teams, players }} />
          <MVPDnD {...{ user, teams, players }} />
        </TabController>
      ) : (
        <span className="loader" />
      )}
    </>
  );
}
