import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { closestCenter, DndContext, KeyboardSensor, PointerSensor, useSensor, useSensors } from '@dnd-kit/core';
import {
  arrayMove,
  SortableContext,
  sortableKeyboardCoordinates,
  verticalListSortingStrategy,
} from '@dnd-kit/sortable';
import { AnalyticsOutlined, ViewInAr } from '@mui/icons-material';

import { METRICS_LIST } from '../../../../constants';

import * as selectors from '../../../../redux/selectors';
import * as actions from '../../../../redux/slices';

import SortableItem from '@/modules/@common/dnd/SortableItem/SortableItem';
import DimensionItem from '../DimensionItem';
import MetricItem from '../MetricItem';
import { Button, Paper, Typography } from '@/mui/components';

import styles from './SideBar.module.scss';

function SideBar() {
  const dispatch = useDispatch();

  const dimensionsList = useSelector(selectors.dimensionsListSelector);
  const checkedMetrics = useSelector(selectors.checkedMetricsSelector);
  const checkedDimensions = useSelector(selectors.checkedDimensionsSelector);
  const isReadOnly = useSelector(selectors.isReadOnlySelector);
  const filters = useSelector(selectors.filtersSelector);

  const setField = (o) => dispatch(actions.setFieldAction(o));

  const [expandedMetrics, setExpandedMetrics] = useState([]);

  const sensors = useSensors(
    useSensor(PointerSensor),
    useSensor(KeyboardSensor, {
      coordinateGetter: sortableKeyboardCoordinates,
    }),
  );

  const handleChangeAccordion = (id) => {
    if (expandedMetrics.includes(id)) {
      setExpandedMetrics(expandedMetrics.filter((item) => item !== id));
    } else {
      setExpandedMetrics([...expandedMetrics, id]);
    }
  };

  const handleAllMetrics = () => {
    if (expandedMetrics?.length === METRICS_LIST?.length) {
      setExpandedMetrics([]);
    } else {
      setExpandedMetrics(METRICS_LIST.map((item) => item.id));
    }
  };

  const orderCheckedDimensionsByDimensionsList = (values, list) =>
    list?.filter((item) => values.includes(item.value))?.map((item) => item.value) ?? [];

  const handleDragEnd = ({ active, over }) => {
    const getIndex = (neededIndex) => dimensionsList.findIndex((o) => o.value === neededIndex);
    const oldIndex = getIndex(active.id);
    const newIndex = getIndex(over?.id);
    const newDimensionsList = arrayMove(dimensionsList, oldIndex, newIndex);

    // for correct in checkedDimensions
    const newCheckedDimensions = orderCheckedDimensionsByDimensionsList(checkedDimensions, newDimensionsList);

    dispatch(actions.setFieldAction({ dimensionsList: newDimensionsList, checkedDimensions: newCheckedDimensions }));
  };

  const checkDimension = (value) => {
    dispatch(
      actions.setFieldAction({
        checkedDimensions: orderCheckedDimensionsByDimensionsList([...checkedDimensions, value], dimensionsList),
      }),
    );
  };

  const handleDimensionsChange = (value, deselectWithMetrics) => {
    const isValueChecked = checkedDimensions?.includes(value);
    if (isValueChecked) {
      dispatch(
        actions.setFieldAction({
          checkedDimensions: checkedDimensions.filter((item) => item !== value),
        }),
      );

      // when deselect some dimension (Demand Source) needs to select some metrics
      if (deselectWithMetrics) {
        dispatch(
          actions.setFieldAction({
            checkedMetrics: checkedMetrics.filter((item) => !deselectWithMetrics.includes(item)),
          }),
        );
      }
    } else {
      checkDimension(value);
    }
  };

  return (
    <Paper className={styles.SideBar} elevation={16}>
      <div className={styles.ListWrap}>
        <div className={styles.List}>
          <div className={styles.Header}>
            <div className={styles.TitleWrap}>
              <AnalyticsOutlined fontSize="medium" htmlColor="success.main" />
              <Typography className={styles.Title} variant="captionSmall" color="text.primary" fontWeight={500}>
                Metrics
              </Typography>
            </div>

            <Button variant="text" size="xSmall" color="primary" onClick={handleAllMetrics}>
              {expandedMetrics?.length === METRICS_LIST?.length ? 'Collapse All' : 'Expand All'}
            </Button>
          </div>

          <div className={styles.ListContent}>
            {METRICS_LIST.map((item, index) => (
              <MetricItem
                key={`${+index}-${item.label}`}
                id={item.id}
                label={item.label}
                values={item.values}
                selectWithDimensions={item.selectWithDimensions}
                checkDimension={checkDimension}
                onChangeAccordion={handleChangeAccordion}
                expanded={expandedMetrics.includes(item.id)}
                checkedMetrics={checkedMetrics}
                setField={setField}
                disabled={
                  item.exceptDimensions?.some((value) => checkedDimensions?.includes(value)) ||
                  item.exceptFilters?.some((filterName) => !!filters[`${filterName}_FILTER_VALUES`]?.length) ||
                  item.exceptMetrics?.some((value) => checkedMetrics?.includes(value)) ||
                  isReadOnly
                }
              />
            ))}
          </div>
        </div>
      </div>

      <div className={styles.ListWrap}>
        <div className={styles.List}>
          <div className={styles.Header}>
            <div className={styles.TitleWrap}>
              <ViewInAr fontSize="medium" htmlColor="warning.dark" />
              <Typography className={styles.Title} variant="captionSmall" color="text.primary" fontWeight={500}>
                Dimensions
              </Typography>
            </div>
          </div>

          <div className={styles.ListContent}>
            <DndContext onDragEnd={handleDragEnd} sensors={sensors} collisionDetection={closestCenter}>
              <SortableContext
                droppableId="droppable-metrics"
                items={dimensionsList ? dimensionsList.map((o) => o.value) : []}
                strategy={verticalListSortingStrategy}
              >
                {!!dimensionsList &&
                  dimensionsList.map((item) => (
                    <SortableItem key={item.value} value={item.value}>
                      {(sortableItemProps) => (
                        <div
                          ref={sortableItemProps.dndSetNodeRef}
                          style={sortableItemProps.dndStyle}
                          {...sortableItemProps.dndAttributes}
                          className={styles.MetricListItem}
                        >
                          <DimensionItem
                            label={item.label}
                            isDragging={sortableItemProps.dndIsDragging}
                            checked={checkedDimensions?.includes(item.value)}
                            onChange={() => {
                              handleDimensionsChange(item.value, item.deselectWithMetrics);
                            }}
                            disabled={
                              item.exceptMetrics?.some((value) => checkedMetrics?.includes(value)) ||
                              item.exceptDimensions?.some((value) => checkedDimensions?.includes(value)) ||
                              isReadOnly
                            }
                            dndListeners={sortableItemProps.dndListeners}
                          />
                        </div>
                      )}
                    </SortableItem>
                  ))}
              </SortableContext>
            </DndContext>
          </div>
        </div>
      </div>
    </Paper>
  );
}

export default SideBar;
