import React, { useState } from 'react';
import { Button, Segment } from 'semantic-ui-react';
import { defineMessages, useIntl } from 'react-intl';
import { isEmpty, without, pickBy } from 'lodash';
import { Accordion } from 'design-react-kit';
import { TextEditorWidget } from 'volto-slate-italia';
import {
  BlocksForm,
  Icon,
  SidebarPortal,
  BlocksToolbar,
  BlockDataForm,
} from '@plone/volto/components';
import {
  emptyBlocksForm,
  getBlocksLayoutFieldname,
  withBlockExtensions,
} from '@plone/volto/helpers';
import { cloneDeepSchema } from '@plone/volto/helpers/Utils/Utils';
import helpSVG from '@plone/volto/icons/help.svg';
import config from '@plone/volto/registry';

import AccordionEdit from './AccordionEdit';
import AccordionFilter from './AccordionFilter';
import EditBlockWrapper from './EditBlockWrapper';
import { AccordionBlockSchema } from './Schema';
import Container from './Container';
import { emptyAccordion, getPanels } from './util';

import './editor.less';
import './view.scss';

const messages = defineMessages({
  SectionHelp: {
    id: 'Section help',
    defaultMessage: 'Section help',
  },
  AccordionBlock: {
    id: 'Accordion block',
    defaultMessage: 'Accordion block',
  },
  Accordion: {
    id: 'Accordion',
    defaultMessage: 'Accordion',
  },
  title: {
    id: 'Title',
    defaultMessage: 'Titolo...',
  },
  description: {
    id: 'Description placeholder',
    defaultMessage: 'Descrizione...',
  },
});

const Edit = (props) => {
  const [selectedBlock, setSelectedBlock] = useState({});
  const [multiSelected, setMultiSelected] = useState([]);
  const [filterValue, setFilterValue] = useState('');
  const {
    block,
    data,
    onChangeBlock,
    onChangeField,
    pathname,
    selected,
    manage,
    formDescription,
    openObjectBrowser,
  } = props;

  const intl = useIntl();
  const properties = isEmpty(data?.data?.blocks)
    ? emptyAccordion(3)
    : data.data;
  const metadata = props.metadata || props.properties;
  const [currentUid, setCurrentUid] = useState('');

  const onSelectBlock = (uid, id, isMultipleSelection, event, activeBlock) => {
    let newMultiSelected = [];
    let selected = id;

    if (Object.values(activeBlock || {})?.length > 0) {
      activeBlock = Object.values(activeBlock)[0];
    }
    if (data?.data?.blocks?.hasOwnProperty(uid) && isMultipleSelection) {
      selected = null;
      const blocksLayoutFieldname = getBlocksLayoutFieldname(
        data.data.blocks[uid],
      );

      const blocks_layout = data.data.blocks[uid][blocksLayoutFieldname].items;

      if (event.shiftKey) {
        const anchor =
          multiSelected.length > 0
            ? blocks_layout.indexOf(multiSelected[0])
            : blocks_layout.indexOf(activeBlock);
        const focus = blocks_layout.indexOf(id);
        if (anchor === focus) {
          newMultiSelected = [id];
        } else if (focus > anchor) {
          newMultiSelected = [...blocks_layout.slice(anchor, focus + 1)];
        } else {
          newMultiSelected = [...blocks_layout.slice(focus, anchor + 1)];
        }
      }
      if ((event.ctrlKey || event.metaKey) && !event.shiftKey) {
        if (multiSelected.includes(id)) {
          selected = null;
          newMultiSelected = without(multiSelected, id);
        } else {
          newMultiSelected = [...(multiSelected || []), id];
        }
      }
    }

    setSelectedBlock({ [uid]: selected });
    setCurrentUid(uid);
    setMultiSelected(newMultiSelected);
  };

  const searchElementInMultiSelection = (uid, blockprops) => {
    return !!multiSelected.find((el) => el === blockprops.block);
  };

  const applySchemaEnhancer = (originalSchema) => {
    let schema, schemaEnhancer;
    const formData = data;
    const { blocks } = config;

    const blockType = formData['@type'];
    const variations = blocks?.blocksConfig[blockType]?.variations || [];

    if (variations.length === 0) {
      // No variations present but anyways
      // finalize the schema with a schemaEnhancer in the block config is present
      schemaEnhancer = blocks.blocksConfig?.[blockType]?.schemaEnhancer;
      if (schemaEnhancer)
        schema = schemaEnhancer({ schema: originalSchema, formData, intl });
    }

    const activeItemName = formData?.variation;
    let activeItem = variations.find((item) => item.id === activeItemName);
    if (!activeItem) activeItem = variations.find((item) => item.isDefault);

    schemaEnhancer = activeItem?.['schemaEnhancer'];

    schema = schemaEnhancer
      ? schemaEnhancer({
          schema: cloneDeepSchema(originalSchema),
          formData,
          intl,
        })
      : cloneDeepSchema(originalSchema);

    return schema;
  };

  /**
   * Will set field values from schema, by matching the default values
   * @returns {Object} defaultValues
   */
  const setInitialData = () => {
    const accordionSchema = applySchemaEnhancer(AccordionBlockSchema({ intl }));
    const defaultValues = Object.keys(accordionSchema.properties).reduce(
      (accumulator, currentVal) => {
        return accordionSchema.properties[currentVal].default
          ? {
              ...accumulator,
              [currentVal]: accordionSchema.properties[currentVal].default,
            }
          : accumulator;
      },
      {},
    );

    return {
      ...defaultValues,
      ...data,
      data: {
        ...properties,
      },
    };
  };

  React.useEffect(() => {
    if (isEmpty(data?.data)) {
      onChangeBlock(block, setInitialData());
    }
    /* eslint-disable-next-line */
  }, []);

  React.useEffect(() => {
    properties.blocks_layout.items.map((item) => {
      if (isEmpty(properties.blocks[item]?.blocks)) {
        return onChangeBlock(block, {
          ...data,
          data: {
            ...properties,
            blocks: {
              ...properties.blocks,
              [item]: emptyBlocksForm(),
            },
          },
        });
      }
      return undefined;
    });
  }, [
    onChangeBlock,
    properties,
    selectedBlock,
    block,
    data,
    properties.blocks,
  ]);

  const blockState = {};
  const panelData = properties;
  const panels = getPanels(panelData);

  const handleTitleChange = (e, value) => {
    const [uid, panel] = value;
    const modifiedBlock = {
      ...panel,
      title: e.target.value,
      '@type': 'accordionPanel',
    };
    onChangeBlock(block, {
      ...data,
      data: {
        ...panelData,
        blocks: {
          ...panelData.blocks,
          [uid]: modifiedBlock,
        },
      },
    });
  };

  const handleFilteredValueChange = (value) => {
    setFilterValue(value);
  };

  // Get editing instructions from block settings or props
  let instructions = data?.instructions?.data || data?.instructions;
  if (!instructions || instructions === '<p><br/></p>') {
    instructions = formDescription;
  }

  const changeBlockData = (newBlockData) => {
    const selectedIndex =
      data.data.blocks[currentUid].blocks_layout.items.indexOf(
        Object.values(selectedBlock)[0],
      ) + 1;
    let pastedBlocks = Object.entries(newBlockData.blocks).filter((block) => {
      let key = block[0];

      return !data?.data?.blocks[currentUid].blocks_layout.items.find(
        (x) => x === key,
      );
    });

    let blockLayout = pastedBlocks.map((el) => el[0]);

    onChangeBlock(block, {
      ...data,
      data: {
        blocks: {
          ...data.data.blocks,
          [currentUid]: {
            ...data.data.blocks[currentUid],
            ...newBlockData,
            blocks_layout: {
              items: [
                ...data.data.blocks[currentUid].blocks_layout.items.slice(
                  0,
                  selectedIndex,
                ),
                ...blockLayout,
                ...data.data.blocks[currentUid].blocks_layout.items.slice(
                  selectedIndex,
                ),
              ],
            },
          },
        },
        blocks_layout: data.data.blocks_layout,
      },
    });
  };

  const blockConfig = config.blocks.blocksConfig.accordion;
  const blocksConfig = blockConfig.blocksConfig || props.blocksConfig;
  // The accordion is able to get the allowedBlocks info from the custom DX layout
  // Fallback to the blockConfig one

  const allowedBlocks = data.allowedBlocks || blockConfig.allowedBlocks;

  const allowedBlocksConfig = allowedBlocks
    ? pickBy(blocksConfig, (value, key) => allowedBlocks.includes(key))
    : blocksConfig;

  const schema = AccordionBlockSchema({ intl });

  //handle collapsed items
  const [activeIndex, setActiveIndex] = React.useState([0]);

  React.useEffect(() => {
    return data.collapsed ? setActiveIndex([]) : setActiveIndex([0]);
  }, [data.collapsed]);

  const setActiveItem = (index) => {
    if (data.non_exclusive) {
      const newIndex =
        activeIndex.indexOf(index) === -1
          ? [...activeIndex, index]
          : activeIndex;

      setActiveIndex(newIndex);
    } else {
      setActiveIndex([index]);
    }
  };
  const toggleItem = (e, itemProps) => {
    const { index } = itemProps;
    if (data.non_exclusive) {
      const newIndex =
        activeIndex.indexOf(index) === -1
          ? [...activeIndex, index]
          : activeIndex.filter((item) => item !== index);

      setActiveIndex(newIndex);
    } else {
      const newIndex =
        activeIndex.indexOf(index) === -1
          ? [index]
          : activeIndex.filter((item) => item !== index);
      setActiveIndex(newIndex);
    }
  };

  //edit title and description
  const [selectedField, setSelectedField] = React.useState('title');

  const editBlockHeader = (
    <>
      <h2 className="headline mb-0">
        <TextEditorWidget
          {...props}
          showToolbar={false}
          data={data}
          key="title"
          fieldName="title"
          selected={selectedField === 'title'}
          setSelected={(f) => {
            setSelectedField(f);
            setActiveIndex([]);
          }}
          placeholder={intl.formatMessage(messages.title)}
          focusNextField={() => {
            setSelectedField('description');
          }}
        />
      </h2>

      <div className="description">
        <TextEditorWidget
          {...props}
          showToolbar={true}
          data={data}
          fieldName="description"
          selected={selectedField === 'description'}
          setSelected={(f) => {
            setSelectedField(f);
            setActiveIndex([]);
          }}
          placeholder={intl.formatMessage(messages.description)}
          focusPrevField={() => {
            setSelectedField('title');
          }}
          focusNextField={() => {
            setSelectedField(null);
            setActiveIndex([0]);
          }}
        />
      </div>
    </>
  );
  return (
    <div className="accordion-block">
      <fieldset>
        <legend
          onClick={() => {
            setSelectedBlock({});
            props.setSidebarTab(1);
          }}
          aria-hidden="true"
        >
          Accordion
        </legend>
        <Container data={data} headerChildren={editBlockHeader}>
          {data.filtering && (
            <AccordionFilter
              block={block}
              config={blockConfig}
              data={data}
              filterValue={filterValue}
              handleFilteredValueChange={handleFilteredValueChange}
            />
          )}
          <Accordion id={block + '-accordion'}>
            {/* iconLeft={true} */}
            {panels
              .filter(
                (panel) =>
                  !data.filtering ||
                  filterValue === '' ||
                  (filterValue !== '' &&
                    panel[1].title
                      ?.toLowerCase()
                      .includes(filterValue.toLowerCase())),
              )
              .map(([uid, panel], index) => (
                <AccordionEdit
                  uid={uid}
                  panel={panel}
                  panelData={panelData}
                  handleTitleChange={handleTitleChange}
                  handleTitleClick={() => {
                    setActiveItem(index);
                    setSelectedBlock({});
                  }}
                  data={data}
                  index={index}
                  key={`accordion-${index}`}
                  isActive={activeIndex.includes(index)}
                  toggle={toggleItem}
                >
                  <BlocksForm
                    errors={props.errors}
                    key={uid}
                    title={data.placeholder}
                    description={instructions}
                    manage={manage}
                    blocksConfig={allowedBlocksConfig}
                    metadata={metadata}
                    properties={isEmpty(panel) ? emptyBlocksForm() : panel}
                    selectedBlock={selected ? selectedBlock[uid] : null}
                    onSelectBlock={(id, l, e) => {
                      const isMultipleSelection = e
                        ? e.shiftKey || e.ctrlKey || e.metaKey
                        : false;
                      onSelectBlock(
                        uid,
                        id,
                        isMultipleSelection,
                        e,
                        selectedBlock,
                      );
                    }}
                    onChangeFormData={(newFormData) => {
                      onChangeBlock(block, {
                        ...data,
                        data: {
                          ...panelData,
                          blocks: {
                            ...panelData.blocks,
                            [uid]: newFormData,
                          },
                        },
                      });
                    }}
                    onChangeField={(id, value) => {
                      if (['blocks', 'blocks_layout'].indexOf(id) > -1) {
                        blockState[id] = value;
                        onChangeBlock(block, {
                          ...data,
                          data: {
                            ...panelData,
                            blocks: {
                              ...panelData.blocks,
                              [uid]: {
                                ...panelData.blocks?.[uid],
                                ...blockState,
                              },
                            },
                          },
                        });
                      } else {
                        onChangeField(id, value);
                      }
                    }}
                    pathname={pathname}
                  >
                    {({ draginfo }, editBlock, blockProps) => {
                      return (
                        <EditBlockWrapper
                          draginfo={draginfo}
                          blockProps={blockProps}
                          disabled={data.disableInnerButtons}
                          multiSelected={searchElementInMultiSelection(
                            uid,
                            blockProps,
                          )}
                          extraControls={
                            <>
                              {instructions && (
                                <>
                                  <Button
                                    icon
                                    basic
                                    title={intl.formatMessage(
                                      messages.SectionHelp,
                                    )}
                                    onClick={() => {
                                      setSelectedBlock({});
                                      const tab = manage ? 0 : 1;
                                      props.setSidebarTab(tab);
                                    }}
                                  >
                                    <Icon
                                      name={helpSVG}
                                      className=""
                                      size="19px"
                                    />
                                  </Button>
                                </>
                              )}
                            </>
                          }
                        >
                          {editBlock}
                        </EditBlockWrapper>
                      );
                    }}
                  </BlocksForm>
                </AccordionEdit>
              ))}
            {selected ? (
              <BlocksToolbar
                selectedBlock={Object.keys(selectedBlock)[0]}
                formData={data?.data?.blocks?.[currentUid]}
                selectedBlocks={multiSelected}
                onSetSelectedBlocks={(blockIds) => {
                  setMultiSelected(blockIds);
                }}
                onSelectBlock={(id, l, e) => {
                  const isMultipleSelection = e
                    ? e.shiftKey || e.ctrlKey || e.metaKey
                    : false;

                  onSelectBlock(id, isMultipleSelection, e, selectedBlock);
                }}
                onChangeBlocks={(newBlockData) => {
                  changeBlockData(newBlockData);
                }}
              />
            ) : (
              ''
            )}
          </Accordion>

          <SidebarPortal
            selected={selected && !Object.keys(selectedBlock).length}
          >
            {instructions && (
              <Segment attached>
                <div dangerouslySetInnerHTML={{ __html: instructions }} />
              </Segment>
            )}
            {!data?.readOnlySettings && (
              <BlockDataForm
                schema={schema}
                title={schema.title}
                onChangeField={(id, value) => {
                  onChangeBlock(block, {
                    ...data,
                    [id]: value,
                  });
                }}
                formData={data}
                block={block}
                blocksConfig={blocksConfig}
                onChangeBlock={onChangeBlock}
                openObjectBrowser={openObjectBrowser}
              />
            )}
          </SidebarPortal>
        </Container>
      </fieldset>
    </div>
  );
};

export default withBlockExtensions(Edit);
