import React, { useState, useCallback } from 'react';
import { isSection } from '../../utilities/options.js';
import { arraysAreEqual } from '../../utilities/arrays.js';
import { useDeepEffect } from '../../utilities/use-deep-effect.js';
import { Option } from './components/Option/Option.js';
import { useUniqueId } from '../../utilities/unique-id/hooks.js';
import { Box } from '../Box/Box.js';
import { Bleed } from '../Bleed/Bleed.js';
import { Text } from '../Text/Text.js';

function OptionList({
  options,
  sections,
  title,
  selected,
  allowMultiple,
  role,
  optionRole,
  verticalAlign,
  onChange,
  id: idProp,
  onPointerEnterOption,
  onFocusOption
}) {
  const [normalizedOptions, setNormalizedOptions] = useState(createNormalizedOptions(options, sections, title));
  const id = useUniqueId('OptionList', idProp);
  useDeepEffect(() => {
    setNormalizedOptions(createNormalizedOptions(options || [], sections || [], title));
  }, [options, sections, title], optionArraysAreEqual);
  const handleClick = useCallback((sectionIndex, optionIndex) => {
    const selectedValue = normalizedOptions[sectionIndex].options[optionIndex].value;
    const foundIndex = selected.indexOf(selectedValue);

    if (allowMultiple) {
      const newSelection = foundIndex === -1 ? [selectedValue, ...selected] : [...selected.slice(0, foundIndex), ...selected.slice(foundIndex + 1, selected.length)];
      onChange(newSelection);
      return;
    }

    onChange([selectedValue]);
  }, [normalizedOptions, selected, allowMultiple, onChange]);
  const handlePointerEnter = useCallback((sectionIndex, optionIndex) => {
    if (!onPointerEnterOption) return;
    const selectedValue = normalizedOptions[sectionIndex].options[optionIndex].value;
    onPointerEnterOption(selectedValue);
  }, [normalizedOptions, onPointerEnterOption]);
  const handleFocus = useCallback((sectionIndex, optionIndex) => {
    if (!onFocusOption) return;
    const selectedValue = normalizedOptions[sectionIndex].options[optionIndex].value;
    onFocusOption(selectedValue);
  }, [normalizedOptions, onFocusOption]);
  const optionsExist = normalizedOptions.length > 0;
  const optionsMarkup = optionsExist ? normalizedOptions.map(({
    title,
    options
  }, sectionIndex) => {
    const isFirstOption = sectionIndex === 0;
    const titleMarkup = title ? /*#__PURE__*/React.createElement(Box, {
      paddingBlockStart: isFirstOption ? '2' : '4',
      paddingInlineStart: "2",
      paddingBlockEnd: "2",
      paddingInlineEnd: "2",
      borderColor: "border-subdued",
      borderBlockStartWidth: !isFirstOption ? '1' : undefined
    }, /*#__PURE__*/React.createElement(Text, {
      as: "p",
      variant: "headingXs"
    }, title)) : null;
    const optionsMarkup = options && options.map((option, optionIndex) => {
      const isSelected = selected.includes(option.value);
      const optionId = option.id || `${id}-${sectionIndex}-${optionIndex}`;
      return /*#__PURE__*/React.createElement(Option, Object.assign({
        key: optionId
      }, option, {
        id: optionId,
        section: sectionIndex,
        index: optionIndex,
        onClick: handleClick,
        select: isSelected,
        allowMultiple: allowMultiple,
        verticalAlign: verticalAlign,
        role: optionRole,
        onPointerEnter: handlePointerEnter,
        onFocus: handleFocus
      }));
    });
    return /*#__PURE__*/React.createElement(Box, {
      key: title || `noTitle-${sectionIndex}`,
      as: "li",
      paddingBlockStart: isFirstOption ? undefined : '2'
    }, titleMarkup, /*#__PURE__*/React.createElement(Bleed, {
      marginBlockStart: title ? undefined : '05'
    }, /*#__PURE__*/React.createElement(Box, {
      as: "ul",
      id: `${id}-${sectionIndex}`,
      role: role
    }, optionsMarkup)));
  }) : null;
  return /*#__PURE__*/React.createElement(Box, {
    as: "ul",
    role: role,
    padding: "2"
  }, optionsMarkup);
}

function createNormalizedOptions(options, sections, title) {
  if (options == null) {
    const section = {
      options: [],
      title
    };
    return sections == null ? [] : [section, ...sections];
  }

  if (sections == null) {
    return [{
      title,
      options
    }];
  }

  return [{
    title,
    options
  }, ...sections];
}

function optionArraysAreEqual(firstArray, secondArray) {
  if (isSection(firstArray) && isSection(secondArray)) {
    return arraysAreEqual(firstArray, secondArray, testSectionsPropEquality);
  }

  return arraysAreEqual(firstArray, secondArray);
}

function testSectionsPropEquality(previousSection, currentSection) {
  const {
    options: previousOptions
  } = previousSection;
  const {
    options: currentOptions
  } = currentSection;
  const optionsAreEqual = arraysAreEqual(previousOptions, currentOptions);
  const titlesAreEqual = previousSection.title === currentSection.title;
  return optionsAreEqual && titlesAreEqual;
}

export { OptionList };
