import clsx from "clsx";
import { FC, ReactNode } from "react";

import {
  BuilderChoiceContract,
  Choice,
  ChoiceData,
  ChoiceUtils,
  Constants,
  FeatureChoiceOption,
  HtmlSelectOptionGroup,
} from "@dndbeyond/character-rules-engine/es";

import { Accordion } from "~/components/Accordion";
import { CollapsibleContent } from "~/components/CollapsibleContent";
import { HtmlContent } from "~/components/HtmlContent";
import { Select } from "~/components/Select";
import { useCharacterEngine } from "~/hooks/useCharacterEngine";
import { useRuleData } from "~/hooks/useRuleData";

import styles from "./styles.module.css";

// TODO this needs to not extend builder contract and options typing needs to be fixed
// TODO scss to styles.module.css
interface Props extends Omit<BuilderChoiceContract, "options"> {
  choice: Choice;
  description?: string;
  descriptionIntro?: string;
  choiceInfo: ChoiceData;
  classId?: number | null;
  maxDescriptionLength?: number;
  showBackgroundProficiencyOptions?: boolean;
  hideWhenOnlyDefaultSelected?: boolean;
  className?: string;
  options: Array<FeatureChoiceOption | HtmlSelectOptionGroup>;
  onChange?: (
    id: string,
    type: number,
    value: any,
    parentChoiceId: string | null
  ) => void;
  collapseDescription?: boolean;
}

export const DetailChoice: FC<Props> = ({
  choice,
  description,
  descriptionIntro,
  optionValue,
  parentChoiceId,
  maxDescriptionLength = 750,
  hideWhenOnlyDefaultSelected = true,
  type,
  className = "",
  options,
  collapseDescription,
  classId = null,
  label,
  subType,
  choiceInfo,
  defaultSubtypes = [],
  showBackgroundProficiencyOptions = false,
  onChange,
  id,
}) => {
  const { entityRestrictionData, ruleData } = useCharacterEngine();
  const { languages } = useRuleData();

  const hasTodo =
    (ChoiceUtils.isInfinite(choice) && !ChoiceUtils.isOptionSelected(choice)) ||
    ChoiceUtils.isTodo(choice);

  const handleChoiceChange = (value: string | number): void => {
    if (onChange && id !== null) {
      onChange(id, type, value, parentChoiceId);
    }
  };

  //Don't render the choice if hideWhenOnlyDefaultSelected is true and the choice is only default selected.
  if (
    hideWhenOnlyDefaultSelected &&
    ChoiceUtils.isOnlyDefaultSelected(choice)
  ) {
    return null;
  }

  // Use the description prop or, if a chosenOption is found and a description wasn't passed in, use the chosenOption description instead.
  let choiceDescription = description;

  //Look for a chosenOption from options that are not already grouped
  const chosenOption = options.find(
    (option) => option["value"] === optionValue
  );

  if (chosenOption) {
    choiceDescription = description || chosenOption["description"];
  }

  const choiceDescriptionIntro = descriptionIntro ? (
    <p className={styles.descriptionIntro}>{descriptionIntro}</p>
  ) : null;

  let choiceNode: ReactNode;
  if (choiceDescription) {
    switch (type) {
      case Constants.BuilderChoiceTypeEnum.ENTITY_SPELL_OPTION:
        choiceNode = (
          <Accordion variant="text" summary="Spell Details" size="xx-small">
            <HtmlContent
              className="detail-choice-description"
              html={choiceDescription}
              withoutTooltips
            />
          </Accordion>
        );
        break;
      default:
        if (collapseDescription) {
          choiceNode = (
            <Accordion variant="text" summary="Show Details" size="xx-small">
              {choiceDescriptionIntro}
              <HtmlContent
                className="detail-choice-description"
                html={choiceDescription}
                withoutTooltips
              />
            </Accordion>
          );
        } else if (choiceDescription.length > maxDescriptionLength) {
          choiceNode = (
            <CollapsibleContent className="detail-choice-description">
              {choiceDescriptionIntro}
              <HtmlContent html={choiceDescription} />
            </CollapsibleContent>
          );
        } else {
          choiceNode = (
            <>
              {choiceDescriptionIntro}
              <HtmlContent
                className="detail-choice-description"
                html={choiceDescription}
                withoutTooltips
              />
            </>
          );
        }
    }
  }

  return (
    <div
      className={clsx([
        "detail-choice",
        hasTodo && "detail-choice--todo",
        parentChoiceId !== null && "detail-choice--child",
        className,
      ])}
    >
      <Select
        value={optionValue}
        placeholder={label ? `- ${label} -` : "- Choose an Option -"}
        options={ChoiceUtils.getSortedRenderOptions(
          options,
          classId,
          subType,
          entityRestrictionData,
          languages ?? [],
          ruleData,
          defaultSubtypes,
          showBackgroundProficiencyOptions,
          choiceInfo,
          optionValue
        )}
        onChange={handleChoiceChange}
        searchThreshold={10}
        isHighlighted={hasTodo}
        name={`detail-choice-select-${choice.id}`}
      />
      {choiceNode}
    </div>
  );
};
