import clsx from "clsx";
import { useContext, useEffect, useRef, useState } from "react";
import ReactDOM from "react-dom";
import { useSelector } from "react-redux";

import {
  ConfigUtils,
  Constants,
  CampaignUtils,
  characterEnvSelectors,
} from "@dndbeyond/character-rules-engine/es";
import { Platform } from "@dndbeyond/event-pipeline-lib/shared";
import D20 from "@dndbeyond/fontawesome-cache/svgs/light/dice-d20.svg";
import { GameLogContext } from "@dndbeyond/game-log-components";
import { getMessageBroker } from "@dndbeyond/message-broker-lib";
import {
  CustomDiceRoller,
  rollerImport,
} from "@dndbeyond/pocket-dimension-dice/components/CustomDiceRoller";
import "@dndbeyond/pocket-dimension-dice/components/CustomDiceRoller/index.css";
import { Context as DiceWorkerContext } from "@dndbeyond/pocket-dimension-dice/context";
import { instrumentDiceClear } from "@dndbeyond/pocket-dimension-dice/helpers/bi/instrumentDiceClear";
import { instrumentDiceContainerClose } from "@dndbeyond/pocket-dimension-dice/helpers/bi/instrumentDiceContainerClose";
import { instrumentDiceContainerOpen } from "@dndbeyond/pocket-dimension-dice/helpers/bi/instrumentDiceContainerOpen";
import { instrumentDiceRoll } from "@dndbeyond/pocket-dimension-dice/helpers/bi/instrumentDiceRoll";
import { useDiceSets } from "@dndbeyond/pocket-dimension-dice/hooks/useDiceSets";
import { useUserDiceDataStore } from "@dndbeyond/pocket-dimension-dice/hooks/useUserDiceDataStore";
import { AnchoredPopover } from "@dndbeyond/ttui/components/AnchoredPopover";

import { Button } from "~/components/Button";
import { useAuth } from "~/contexts/Authentication";
import { useCharacterEngine } from "~/hooks/useCharacterEngine";
import { useDispatch } from "~/hooks/useDispatch";

import { appEnvSelectors } from "../../selectors";
import styles from "./DiceContainer.module.css";

const location = "characterSheet";

export default function DiceContainer({ canShow = true, isVttView = false }) {
  const { nodeEnv, env } = useContext(DiceWorkerContext);
  const dispatch = useDispatch();
  const diceEnabled = useSelector(appEnvSelectors.getDiceEnabled);
  const diceFeatureConfiguration = useSelector(
    appEnvSelectors.getDiceFeatureConfiguration
  );
  const { campaign, characterName } = useCharacterEngine();
  const user = useAuth();
  const [{ entityId }] = useContext(GameLogContext);
  const canvasContainer = useRef<HTMLDivElement | null>(null);
  const [isCustomDiceRollerOpen, setIsCustomDiceRollerOpen] = useState(false);
  const diceSets = useDiceSets(nodeEnv, env);
  const setId = useUserDiceDataStore(
    (state) => state.getUserDiceData(Number(user?.id))?.setId
  );
  const dmId = campaign
    ? String(CampaignUtils.getDmUserId(campaign))
    : undefined;
  const isSheet =
    useSelector(characterEnvSelectors.getContext) ===
    Constants.AppContextTypeEnum.SHEET;

  useEffect(() => {
    getMessageBroker().then((mb) => {
      if (mb && user?.id) {
        if (campaign) {
          mb.gameId = CampaignUtils.getId(campaign).toString();
        } else {
          mb.gameId = undefined;
        }

        mb.userId = user.id;
      }
      ConfigUtils.configureRulesEngine({ messageBroker: mb });
    });
  }, [
    campaign,
    diceFeatureConfiguration.apiEndpoint,
    diceFeatureConfiguration.assetBaseLocation,
    diceFeatureConfiguration.enabled,
    diceFeatureConfiguration.trackingId,
    dispatch,
    isSheet,
    user?.id,
  ]);

  if (isVttView) return null;

  return ReactDOM.createPortal(
    <div className={"dice-rolling-panel"} ref={canvasContainer}>
      {canShow && diceEnabled && (
        <AnchoredPopover
          offset={16}
          open={isCustomDiceRollerOpen}
          allowedPlacements={["top-start"]}
          referenceComponent={
            <Button
              className={clsx([
                styles.button,
                isCustomDiceRollerOpen && styles.customDiceRollOpen,
              ])}
              onClick={() => {
                setIsCustomDiceRollerOpen(!isCustomDiceRollerOpen);

                // isCustomDiceRollerOpen is the previous state here
                if (isCustomDiceRollerOpen) {
                  instrumentDiceContainerClose(
                    user,
                    Platform.Web,
                    location,
                    campaign?.id,
                    undefined,
                    env
                  );
                } else {
                  instrumentDiceContainerOpen(
                    user,
                    Platform.Web,
                    location,
                    campaign?.id,
                    undefined,
                    env
                  );
                }
              }}
              themed
              onMouseEnter={rollerImport}
            >
              <D20 />
            </Button>
          }
          floatingArrow
          floatingArrowClassName={styles.floatingArrow}
        >
          {diceSets && (
            <CustomDiceRoller
              rollCallback={() => setIsCustomDiceRollerOpen(false)}
              onClose={() => setIsCustomDiceRollerOpen(false)}
              diceSets={diceSets}
              gameId={campaign?.id}
              visible={isCustomDiceRollerOpen}
              setId={setId}
              entityType="character"
              entityId={entityId}
              name={characterName ?? undefined}
              rollInstrumentationCallback={(eventPayload) =>
                instrumentDiceRoll(
                  user,
                  eventPayload,
                  Platform.Web,
                  location,
                  campaign?.id,
                  undefined,
                  env
                )
              }
              clearDiceCallback={() =>
                instrumentDiceClear(
                  user,
                  Platform.Web,
                  location,
                  campaign?.id,
                  undefined,
                  env
                )
              }
              dmId={dmId}
            />
          )}
        </AnchoredPopover>
      )}
      {/* We want this one so it is sticking around, 
            also this is where the canvas goes when we append */}
      {/* <canvas className={'dice-rolling-panel__container'} ref={canvas} /> */}
    </div>,
    document.body
  );
}
