import clsx from "clsx";
import { FC, HTMLAttributes, useEffect, useState } from "react";
import { useSelector } from "react-redux";

import {
  ApiAdapterUtils,
  apiCreatorSelectors,
  CharClass,
  Choice,
  ChoiceUtils,
  ClassDefinitionContract,
  ClassUtils,
  Constants,
  Feat,
  FeatUtils,
} from "@dndbeyond/character-rules-engine";

import { Heading } from "~/subApps/sheet/components/Sidebar/components/Heading";
import { appEnvSelectors } from "~/tools/js/Shared/selectors";
import { AppLoggerUtils } from "~/tools/js/Shared/utils";
import LoadingPlaceholder from "~/tools/js/smartComponents/LoadingPlaceholder";
import { DataLoadingStatusEnum } from "~/tools/js/smartComponents/componentConstants";

import { FeatureChoice } from "./FeatureChoice";
import styles from "./styles.module.css";

export interface FeatureChoicesProps extends HTMLAttributes<HTMLDivElement> {
  choices: Array<Choice>;
  showHeading?: boolean;
  onChoiceChange: (
    choiceId: string,
    type: number,
    value: any,
    parentChoiceId: string | null
  ) => void;
  collapseDescription?: boolean;
  charClass?: CharClass;
  shouldFetch?: boolean; // Optional prop to control fetching behavior
}

export const FeatureChoices: FC<FeatureChoicesProps> = ({
  className,
  choices,
  showHeading,
  onChoiceChange,
  collapseDescription,
  charClass,
  shouldFetch = true, // Default to true if not provided
  ...props
}) => {
  const isReadonly = useSelector(appEnvSelectors.getIsReadonly);
  const loadAvailableFeats = useSelector(
    apiCreatorSelectors.makeLoadAvailableFeats
  );
  const loadAvailableSubclasses = useSelector(
    apiCreatorSelectors.makeLoadAvailableSubclasses
  );

  const [subclassData, setSubclassData] = useState<
    Array<ClassDefinitionContract>
  >([]);
  const [featsData, setFeatsData] = useState<Array<Feat>>([]);
  const [featLoadingStatus, setFeatLoadingStatus] =
    useState<DataLoadingStatusEnum>(DataLoadingStatusEnum.NOT_INITIALIZED);
  const [subclassLoadingStatus, setSubclassLoadingStatus] =
    useState<DataLoadingStatusEnum>(DataLoadingStatusEnum.NOT_INITIALIZED);

  const hasFeatChoice = choices.some(
    (choice) =>
      ChoiceUtils.getType(choice) ===
      Constants.BuilderChoiceTypeEnum.FEAT_CHOICE_OPTION
  );

  const hasSubclassChoice = choices.some(
    (choice) =>
      ChoiceUtils.getType(choice) ===
      Constants.BuilderChoiceTypeEnum.SUB_CLASS_OPTION
  );

  useEffect(() => {
    if (
      hasFeatChoice &&
      shouldFetch &&
      featLoadingStatus === DataLoadingStatusEnum.NOT_INITIALIZED
    ) {
      setFeatLoadingStatus(DataLoadingStatusEnum.LOADING);

      loadAvailableFeats()
        .then((response) => {
          let featsData: Array<Feat> = [];

          const data = ApiAdapterUtils.getResponseData(response);
          if (data !== null) {
            featsData = data.map((definition) =>
              FeatUtils.simulateFeat(definition)
            );
          }

          setFeatsData(featsData);
          setFeatLoadingStatus(DataLoadingStatusEnum.LOADED);
        })
        .catch(AppLoggerUtils.handleAdhocApiError);
    }

    if (
      charClass &&
      hasSubclassChoice &&
      shouldFetch &&
      subclassLoadingStatus === DataLoadingStatusEnum.NOT_INITIALIZED
    ) {
      setSubclassLoadingStatus(DataLoadingStatusEnum.LOADING);
      loadAvailableSubclasses(ClassUtils.getId(charClass))
        .then((response) => {
          let subclassData: Array<ClassDefinitionContract> = [];

          const data = ApiAdapterUtils.getResponseData(response);
          if (data !== null) {
            subclassData = data;
          }

          setSubclassData(subclassData);
          setSubclassLoadingStatus(DataLoadingStatusEnum.LOADED);
        })
        .catch(AppLoggerUtils.handleAdhocApiError);
    }
  }, [
    hasFeatChoice,
    hasSubclassChoice,
    subclassLoadingStatus,
    featLoadingStatus,
    charClass,
    loadAvailableFeats,
    loadAvailableSubclasses,
    shouldFetch,
  ]);

  const isDataLoaded = (): boolean => {
    if (hasSubclassChoice) {
      if (subclassLoadingStatus !== DataLoadingStatusEnum.LOADED) {
        return false;
      }
    }
    if (hasFeatChoice) {
      if (featLoadingStatus !== DataLoadingStatusEnum.LOADED) {
        return false;
      }
    }

    return true;
  };

  return !isReadonly && choices.length > 0 ? (
    <div className={clsx([styles.featureChoices, className])} {...props}>
      <>
        {showHeading && (
          <Heading className={styles.heading}>{`Option${
            choices.length > 1 ? "s" : ""
          }`}</Heading>
        )}
        {isDataLoaded() ? (
          choices.map((choice) => (
            <FeatureChoice
              charClass={charClass}
              choice={choice}
              featsData={featsData}
              subclassData={subclassData}
              className={styles.choice}
              key={ChoiceUtils.getId(choice)}
              onChoiceChange={onChoiceChange}
              collapseDescription={collapseDescription}
            />
          ))
        ) : (
          <LoadingPlaceholder />
        )}
      </>
    </div>
  ) : null;
};
