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

import {
  Action,
  ActionUtils,
  characterActions,
  FeatManager,
  HelperUtils,
  RaceUtils,
  RacialTrait,
  RacialTraitUtils,
  Spell,
  SpellUtils,
} 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 {
  PaneComponentEnum,
  PaneIdentifiersRacialTrait,
} from "~/subApps/sheet/components/Sidebar/types";
import { SpeciesTraitFeatureSnippet } 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 { PaneInitFailureContent } from "../../components/PaneInitFailureContent";

interface Props extends HTMLAttributes<HTMLDivElement> {
  identifiers: PaneIdentifiersRacialTrait | null;
}

export const SpeciesTraitPane: FC<Props> = ({ identifiers, ...props }) => {
  const dispatch = useDispatch();
  const {
    race: species,
    feats,
    snippetData,
    ruleData,
    abilityLookup,
    originRef: dataOriginRefData,
    proficiencyBonus,
    characterTheme: theme,
  } = useCharacterEngine();

  const { characterFeaturesManager } = useContext(
    CharacterFeaturesManagerContext
  );
  const isReadonly = useSelector(appEnvSelectors.getIsReadonly);

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

  const speciesTrait = species
    ? RaceUtils.getVisibleRacialTraits(species).find(
        (trait) => identifiers?.id === RacialTraitUtils.getId(trait)
      )
    : null;

  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);
    if (mappingId !== null && mappingEntityTypeId !== null) {
      dispatch(
        characterActions.spellUseSet(
          mappingId,
          mappingEntityTypeId,
          uses,
          SpellUtils.getDataOriginType(spell)
        )
      );
    }
  };

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

  const handleSpeciesTraitShow = (speciesTrait: RacialTrait): void => {
    paneHistoryStart(
      PaneComponentEnum.SPECIES_TRAIT_DETAIL,
      PaneIdentifierUtils.generateRacialTrait(
        RacialTraitUtils.getId(speciesTrait)
      )
    );
  };

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

  const handleChoiceChange = (
    choiceId: string,
    type: number,
    value: any
  ): void => {
    if (!species || !speciesTrait) {
      return;
    }

    dispatch(
      characterActions.racialTraitChoiceSetRequest(
        RacialTraitUtils.getId(speciesTrait),
        type,
        choiceId,
        HelperUtils.parseInputInt(value)
      )
    );
  };

  if (species === null || !speciesTrait) {
    return <PaneInitFailureContent />;
  }

  const portrait = RaceUtils.getPortraitAvatarUrl(species);

  return (
    <div key={RacialTraitUtils.getId(speciesTrait)} {...props}>
      <Header
        parent={RaceUtils.getFullName(species)}
        preview={portrait && <Preview imageUrl={portrait} />}
      >
        {RacialTraitUtils.getName(speciesTrait)}
      </Header>
      <SpeciesTraitFeatureSnippet
        speciesTrait={speciesTrait}
        onActionUseSet={handleActionUseSet}
        onActionClick={handleActionShow}
        onSpellUseSet={handleSpellUseSet}
        onSpellClick={handleSpellDetailShow}
        onFeatureClick={handleSpeciesTraitShow}
        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={RacialTraitUtils.getChoices(speciesTrait)}
        onChoiceChange={handleChoiceChange}
        collapseDescription={true}
        showHeading={true}
      />
    </div>
  );
};
