import clsx from 'clsx';
import React, { useEffect } from 'react';
import { noop } from '../../helpers/utils';
import { Accordion, AccordionItem } from '../Accordion';
import { Button, ButtonContext } from '../Buttons';
import { Select } from '../FormElements';
import { SelectOption } from '../FormElements/Select/Select';
import { IconName } from '../Icons';
import classes from './FieldSelection.scss';

interface FieldSelectionProps {
  name?: string;
  className?: string;
  onFieldAdded?: (field: string) => void;
  onFieldRemoved?: (field: string) => void;
}

interface FieldDefinition {
  index: number;
  value: string;
  label: string;
  child: JSX.Element;
}

export const FieldSelection: React.FC<FieldSelectionProps> = ({
  name,
  className,
  onFieldAdded = noop,
  onFieldRemoved = noop,
  children,
}) => {
  useEffect(() => {
    const fields: FieldDefinition[] = [];
    React.Children.forEach(children, (child, index) => {
      if (
        React.isValidElement<{ label: string; name: string }>(child) &&
        child.props.name
      ) {
        fields.push({
          index,
          value: child.props.name,
          label: child.props.label,
          child: React.cloneElement<{ label: string }>(child, {
            label: 'Value',
          }),
        });
      }
    });

    setAvailableFields(fields);
  }, [children]);

  const [availableFields, setAvailableFields] = React.useState<
    FieldDefinition[]
  >([]);

  const [selectedFields, setSelectedFields] = React.useState<FieldDefinition[]>(
    [],
  );

  return (
    <Accordion
      className={clsx(classes.container, className)}
      expandedByDefault={true}
      header={
        <FieldSelectionHeader
          name={name}
          fields={availableFields}
          onAddField={(value) => {
            const newField = availableFields.find(
              (field) => field.value === value,
            );

            if (newField) {
              setAvailableFields((currentFields) =>
                currentFields.filter((field) => field.value !== value),
              );
              setSelectedFields((currentFields) => [
                ...currentFields,
                newField,
              ]);
              onFieldAdded(newField.value);
            }
          }}
        />
      }
    >
      {selectedFields.map((field) => (
        <AccordionItem
          key={field.value}
          header={
            <FieldSelectionItemHeader
              label={field.label as string}
              onRemoveField={() => {
                setSelectedFields((currentFields) =>
                  currentFields.filter((f) => f.value !== field.value),
                );
                setAvailableFields((currentFields) =>
                  [...currentFields, field].sort((a, b) => a.index - b.index),
                );
                onFieldRemoved(field.value);
              }}
            />
          }
        >
          <div className={classes.content}>{field.child}</div>
        </AccordionItem>
      ))}
    </Accordion>
  );
};

const FieldSelectionHeader: React.FC<{
  name?: string;
  fields: SelectOption[];
  onAddField: (value: string) => void;
}> = ({ name, fields, onAddField }) => {
  const [value, setValue] = React.useState<string>();

  useEffect(() => {
    if (value) {
      onAddField(value);
      setValue(undefined);
    }
  }, [onAddField, value]);

  return (
    <div className={classes.selectionHeader}>
      <Select
        label="Field"
        name={name ?? 'field'}
        placeholder="Select Field"
        options={fields}
        disabled={fields.length === 0}
        inlineMode={true}
        onChange={(e) => setValue(e.currentTarget.value)}
        value={value}
      />
    </div>
  );
};

const FieldSelectionItemHeader: React.FC<{
  label: string;
  onRemoveField: () => void;
}> = ({ label, onRemoveField }) => {
  return (
    <div className={classes.header}>
      {label}
      <Button
        icon={IconName.X}
        buttonContext={ButtonContext.Icon}
        onButtonClicked={(e) => {
          e.stopPropagation();
          onRemoveField();
        }}
        dataTestId="remove-field-button"
      />
    </div>
  );
};
