import clsx from "clsx";
import { orderBy } from "lodash";
import { ChangeEvent, FC, HTMLAttributes, ReactNode } from "react";

import { Accordion, AccordionProps } from "../Accordion";
import { Checkbox } from "../Checkbox";
import styles from "./styles.module.css";

export interface CheckboxInfo {
  description?: string;
  disabled?: boolean;
  initiallyEnabled: boolean;
  label: string;
  onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
  onChangeConfirm?: (
    newIsEnabled: boolean,
    accept: () => void,
    reject: () => void
  ) => void;
  sortOrder?: number;
  value?: string | number;
}

interface CheckboxGroupProps
  extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
  accordionDefaultOpen?: boolean;
  accordionSummary?: string;
  checkboxes: Array<CheckboxInfo>;
  disabled?: boolean;
  description?: ReactNode;
  name: string;
  onToggleAll?: (e: ChangeEvent<HTMLInputElement>) => void;
  showAccordion?: boolean;
  themed?: boolean;
  toggleAllLabel?: string;
  title: ReactNode;
  variant?: "default" | "inline" | "collapse";
}

export const CheckboxGroup: FC<CheckboxGroupProps> = ({
  accordionSummary = "Options",
  accordionDefaultOpen,
  checkboxes,
  className,
  disabled,
  description,
  name,
  onToggleAll,
  showAccordion,
  themed,
  title,
  toggleAllLabel = "Enable All Options",
  variant = "default",
  ...props
}) => {
  const isInlineVariant = variant === "inline";
  const isCollapseVariant = variant === "collapse";
  const sortedCheckboxes = orderBy(checkboxes, "sortOrder");

  const allChecksEnabled = sortedCheckboxes.every(
    (checkbox) => checkbox.initiallyEnabled
  );

  // Determine whether to render a div or an Accordion
  const ContentWrapper = showAccordion ? Accordion : "div";
  // Set props specific to Accordion if needed
  const accordionProps = showAccordion
    ? {
        summary: accordionSummary,
        forceShow: accordionDefaultOpen,
        variant: "text",
      }
    : {};

  const checkboxList = sortedCheckboxes.map((checkbox, i) => {
    const id = `${name}-${i}`;

    return (
      <div
        key={i}
        className={styles.checkboxOption}
        data-testid="form-checkbox-group"
      >
        <Checkbox
          className={styles.checkbox}
          id={id}
          name={name}
          checked={checkbox.initiallyEnabled}
          disabled={disabled || checkbox.disabled}
          themed={themed}
          onChange={checkbox.onChange}
          onChangeConfirm={checkbox.onChangeConfirm}
          value={checkbox.value}
        />
        <div className={styles.optionContent}>
          <label className={styles.label} htmlFor={id}>
            {checkbox.label}
          </label>
          {checkbox.description && (
            <div
              className={styles.description}
              dangerouslySetInnerHTML={{ __html: checkbox.description }}
            />
          )}
        </div>
      </div>
    );
  });

  /** Handle Collapse Variant separately since it's structure is different */
  if (isCollapseVariant)
    return (
      <Accordion
        className={clsx([
          styles.checkboxGroup,
          styles.collapse,
          themed && styles.themed,
          className,
        ])}
        summary={<p className={styles.checkboxGroupTitle}>{title}</p>}
        variant="text"
        forceShow={accordionDefaultOpen}
        {...props}
      >
        {description && (
          <div className={styles.checkboxGroupDescription}>{description}</div>
        )}
        {onToggleAll && (
          <Checkbox
            className={clsx([styles.checkbox, styles.toggleAll])}
            id={`${name}-toggle-all`}
            checked={allChecksEnabled}
            aria-label="Check/Uncheck all"
            onChange={onToggleAll}
            themed={themed}
            label={toggleAllLabel}
          />
        )}
        {checkboxList}
      </Accordion>
    );

  return (
    <div
      className={clsx([
        styles.checkboxGroup,
        styles[variant],
        themed && styles.themed,
        className,
      ])}
      {...props}
    >
      <header>
        <div className={styles.checkboxGroupHeader}>
          <p className={styles.checkboxGroupTitle}>{title}</p>
          {isInlineVariant && checkboxes.length < 2 && (
            <Checkbox
              className={styles.checkbox}
              id={`${name}-0`}
              name={name}
              checked={checkboxes[0].initiallyEnabled}
              disabled={disabled || checkboxes[0].disabled}
              themed={themed}
              onChange={checkboxes[0].onChange}
              onChangeConfirm={checkboxes[0].onChangeConfirm}
              value={checkboxes[0].value}
            />
          )}
        </div>
        {description && (
          <div className={styles.checkboxGroupDescription}>{description}</div>
        )}
      </header>
      {!isInlineVariant && onToggleAll && (
        <Checkbox
          className={clsx([styles.checkbox, styles.toggleAll])}
          id={`${name}-toggle-all`}
          checked={allChecksEnabled}
          aria-label="Check/Uncheck all"
          onChange={onToggleAll}
          themed={themed}
          label={toggleAllLabel}
        />
      )}
      {!isInlineVariant && (
        <ContentWrapper
          className={styles.checkboxOptions}
          {...(accordionProps as AccordionProps)}
        >
          {checkboxList}
        </ContentWrapper>
      )}
    </div>
  );
};
