import { FC, HTMLAttributes, useContext } from "react";
import { useDispatch, useSelector } from "react-redux";

import { FeatManager } from "@dndbeyond/character-rules-engine";

import { FeatureChoices } from "~/components/FeatureChoices";
import { useSidebar } from "~/contexts/Sidebar";
import { useCharacterEngine } from "~/hooks/useCharacterEngine";
import { Header } from "~/subApps/sheet/components/Sidebar/components/Header";
import { Preview } from "~/subApps/sheet/components/Sidebar/components/Preview";
import { ClassFeatureSnippet } from "~/tools/js/CharacterSheet/components/FeatureSnippet";
import { CharacterFeaturesManagerContext } from "~/tools/js/Shared/managers/CharacterFeaturesManagerContext";
import { appEnvSelectors } from "~/tools/js/Shared/selectors";
import { PaneIdentifierUtils } from "~/tools/js/Shared/utils";
import {
  Action,
  CharClass,
  ClassFeature,
  InfusionChoice,
  Spell,
} from "~/types";

import { PaneInitFailureContent } from "../../components/PaneInitFailureContent";
import { PaneComponentEnum, PaneIdentifiersClassFeature } from "../../types";

interface Props extends HTMLAttributes<HTMLDivElement> {
  identifiers: PaneIdentifiersClassFeature | null;
}
export const ClassFeaturePane: FC<Props> = ({ identifiers, ...props }) => {
  const dispatch = useDispatch();
  const {
    infusionChoiceUtils,
    actionUtils,
    characterActions,
    spellUtils,
    classUtils,
    classFeatureUtils,
    classes,
    feats,
    snippetData,
    ruleData,
    abilityLookup,
    proficiencyBonus,
    originRef: dataOriginRefData,
    characterTheme: theme,
    helperUtils,
  } = useCharacterEngine();

  const { characterFeaturesManager } = useContext(
    CharacterFeaturesManagerContext
  );

  const {
    pane: { paneHistoryPush },
  } = useSidebar();

  const isReadonly = useSelector(appEnvSelectors.getIsReadonly);

  const charClass = identifiers?.classMappingId
    ? classes.find(
        (charClass) =>
          identifiers.classMappingId === classUtils.getMappingId(charClass)
      )
    : null;

  const classFeature =
    charClass?.classFeatures.find(
      (feature) => identifiers?.id === classFeatureUtils.getId(feature)
    ) ?? null;

  const handleInfusionChoiceShow = (infusionChoice: InfusionChoice): void => {
    const choiceKey = infusionChoiceUtils.getKey(infusionChoice);
    if (choiceKey !== null) {
      paneHistoryPush(
        PaneComponentEnum.INFUSION_CHOICE,
        PaneIdentifierUtils.generateInfusionChoice(choiceKey)
      );
    }
  };

  const handleChoiceChange = (
    id: string,
    type: number,
    value: any,
    parentChoiceId: string | null
  ): void => {
    if (!charClass || !classFeature) {
      return;
    }
    dispatch(
      characterActions.classFeatureChoiceSetRequest(
        classUtils.getActiveId(charClass),
        classFeatureUtils.getId(classFeature),
        type,
        id,
        helperUtils.parseInputInt(value),
        parentChoiceId
      )
    );
  };

  const handleActionUseSet = (action: Action, uses: number): void => {
    const id = actionUtils.getId(action);
    const entityTypeId = actionUtils.getEntityTypeId(action);
    if (id !== null && entityTypeId !== null) {
      dispatch(
        characterActions.actionUseSet(
          id,
          entityTypeId,
          uses,
          actionUtils.getDataOriginType(action)
        )
      );
    }
  };

  const handleSpellUseSet = (spell: Spell, uses: number): void => {
    const mappingId = spellUtils.getMappingId(spell);
    const mappingEntityTypeId = spellUtils.getMappingEntityTypeId(spell);
    const dataOriginType = spellUtils.getDataOriginType(spell);

    if (mappingId && mappingEntityTypeId && dataOriginType) {
      dispatch(
        characterActions.spellUseSet(
          mappingId,
          mappingEntityTypeId,
          uses,
          dataOriginType
        )
      );
    }
  };

  const handleSpellDetailShow = (spell: Spell): void => {
    const mappingId = spellUtils.getMappingId(spell);
    if (mappingId !== null) {
      paneHistoryPush(
        PaneComponentEnum.CHARACTER_SPELL_DETAIL,
        PaneIdentifierUtils.generateCharacterSpell(mappingId)
      );
    }
  };

  const handleClassFeatureShow = (
    feature: ClassFeature,
    charClass: CharClass
  ): void => {
    paneHistoryPush(
      PaneComponentEnum.CLASS_FEATURE_DETAIL,
      PaneIdentifierUtils.generateClassFeature(
        classFeatureUtils.getId(feature),
        classUtils.getMappingId(charClass)
      )
    );
  };

  const handleActionShow = (action: Action): void => {
    const mappingId = actionUtils.getMappingId(action);
    const mappingEntityTypeId = actionUtils.getMappingEntityTypeId(action);

    if (mappingId !== null && mappingEntityTypeId !== null) {
      paneHistoryPush(
        PaneComponentEnum.ACTION,
        PaneIdentifierUtils.generateAction(mappingId, mappingEntityTypeId)
      );
    }
  };

  const handleFeatShow = (feat: FeatManager): void => {
    paneHistoryPush(
      PaneComponentEnum.FEAT_DETAIL,
      PaneIdentifierUtils.generateFeat(feat.getId())
    );
  };

  if (!charClass || !classFeature) {
    return <PaneInitFailureContent />;
  }

  return (
    <div
      key={`${classUtils.getMappingId(charClass)}-${classFeatureUtils.getId(
        classFeature
      )}`}
      {...props}
    >
      <Header
        parent={classUtils.getName(charClass)}
        preview={<Preview imageUrl={classUtils.getPortraitUrl(charClass)} />}
      >
        {classFeatureUtils.getName(classFeature)}
      </Header>
      <ClassFeatureSnippet
        charClass={charClass}
        feature={classFeature}
        onActionUseSet={handleActionUseSet}
        onActionClick={handleActionShow}
        onSpellClick={handleSpellDetailShow}
        onSpellUseSet={handleSpellUseSet}
        onFeatureClick={handleClassFeatureShow}
        onInfusionChoiceClick={handleInfusionChoiceShow}
        showHeader={false}
        showDescription={true}
        feats={feats}
        snippetData={snippetData}
        ruleData={ruleData}
        abilityLookup={abilityLookup}
        dataOriginRefData={dataOriginRefData}
        isReadonly={isReadonly}
        proficiencyBonus={proficiencyBonus}
        theme={theme}
        onFeatClick={handleFeatShow}
        featuresManager={characterFeaturesManager}
      />
      <FeatureChoices
        choices={classFeatureUtils.getChoices(classFeature)}
        charClass={charClass}
        onChoiceChange={handleChoiceChange}
        collapseDescription={true}
        showHeading={true}
      />
    </div>
  );
};
