import React from 'react';
import PropTypes from 'prop-types';
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 { DragIndicatorRounded, InfoOutlined } from '@mui/icons-material';

import * as selectors from '../../../redux/selectors';
import { setAction } from '../../../redux/slices';

import SortableItem from '@/modules/@common/dnd/SortableItem/SortableItem';
import { FormGroup, FormGroupTitle, FormRowItem, useFormSettings } from '@/modules/@common/Form';
import { IconButton, Link, Paper, Stack, Switch, Tooltip, Typography } from '@/mui/components';

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

const DASHBOARDS_GENERAL_TYPE = 'dashboardsGeneral';
const DASHBOARDS_CUSTOM_TYPE = 'dashboardsCustom';

function TooltipEnhanced({ tooltip }) {
  if (!tooltip?.info) return null;

  const { info, link, linkTitle } = tooltip;

  return (
    <Tooltip
      title={
        <div>
          {info}
          {link && (
            <Link href={link} target="_blank" rel="noreferrer">
              {` ${linkTitle}`}
            </Link>
          )}
        </div>
      }
    >
      <InfoOutlined fontSize="small" htmlColor="info.main" />
    </Tooltip>
  );
}

TooltipEnhanced.propTypes = {
  tooltip: PropTypes.shape({
    info: PropTypes.string.isRequired,
    link: PropTypes.string.isRequired,
    linkTitle: PropTypes.string.isRequired,
  }),
};

function DashboardSection(props) {
  const { size } = useFormSettings();
  const sensors = useSensors(
    useSensor(PointerSensor),
    useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }),
  );

  if (!props.dashboards.length) {
    return null;
  }

  return (
    <>
      <FormGroupTitle>
        <Stack direction="row" alignItems="center" gap={2}>
          {props.title}
          <Tooltip title="Drag and drop to set the order in Analytics menu">
            <InfoOutlined fontSize="small" htmlColor="info.main" />
          </Tooltip>
        </Stack>
      </FormGroupTitle>
      <FormGroup>
        <DndContext
          sensors={sensors}
          collisionDetection={closestCenter}
          onDragEnd={(event) => props.onDragEnd(event, props.type)}
        >
          <SortableContext
            items={props.dashboards.map((dashboard) => dashboard.id)}
            strategy={verticalListSortingStrategy}
          >
            {props.dashboards.map((dashboard) => (
              <SortableItem key={dashboard.id} value={dashboard.id}>
                {(sortableItemProps) => (
                  <FormRowItem key={dashboard.id} gap={6}>
                    <Paper
                      elevation={sortableItemProps.dndIsDragging ? 10 : 1}
                      ref={sortableItemProps.dndSetNodeRef}
                      style={sortableItemProps.dndStyle}
                      {...sortableItemProps.dndAttributes}
                      className={styles.PaperWrapper}
                    >
                      <Stack direction="row" alignItems="center" gap={4} className={styles.ItemWrapper}>
                        <IconButton size={size} component="span" {...sortableItemProps.dndListeners}>
                          <DragIndicatorRounded />
                        </IconButton>
                        <Stack direction="row" alignItems="center" gap={2}>
                          <Switch
                            size={size}
                            checked={Boolean(dashboard.enabled)}
                            onChange={({ target }) =>
                              props.onChange({
                                id: dashboard.id,
                                value: target.checked,
                                type: props.type,
                              })
                            }
                          />
                          <Typography rows={1} title={dashboard.uiName} variant="body2" color="text.primary">
                            {dashboard.uiName}
                          </Typography>
                          <TooltipEnhanced tooltip={dashboard.tooltip} />
                        </Stack>
                      </Stack>
                    </Paper>
                  </FormRowItem>
                )}
              </SortableItem>
            ))}
          </SortableContext>
        </DndContext>
      </FormGroup>
    </>
  );
}

DashboardSection.propTypes = {
  title: PropTypes.string,
  dashboards: PropTypes.arrayOf(
    PropTypes.shape({
      enabled: PropTypes.bool,
      id: PropTypes.string.isRequired,
      checked: PropTypes.bool,
      type: PropTypes.string,
      uiName: PropTypes.string,
      tooltip: PropTypes.shape({
        info: PropTypes.string.isRequired,
        link: PropTypes.string.isRequired,
        linkTitle: PropTypes.string.isRequired,
      }),
    }),
  ).isRequired,
  onChange: PropTypes.func.isRequired,
  type: PropTypes.string.isRequired,
  onDragEnd: PropTypes.func.isRequired,
};

function DashboardsTab() {
  const dispatch = useDispatch();
  const dashboardGeneral = useSelector(selectors.dashboardsGeneralSelector);
  const dashboardCustom = useSelector(selectors.dashboardsCustomSelector);

  const dashboardsMapByType = {
    [DASHBOARDS_GENERAL_TYPE]: dashboardGeneral,
    [DASHBOARDS_CUSTOM_TYPE]: dashboardCustom,
  };

  const handleChange = ({ id, value, type }) => {
    const dashboards = dashboardsMapByType[type];
    const updatedDashboards = dashboards.map((entry) => (entry.id === id ? { ...entry, enabled: value } : entry));

    dispatch(setAction({ [type]: updatedDashboards }));
  };

  const handleDragEnd = ({ active, over }, type) => {
    const dashboards = dashboardsMapByType[type];
    const findIndexById = (id) => dashboards.findIndex((item) => item.id === id);

    const prevIndex = findIndexById(active.id);
    const newIndex = findIndexById(over.id);

    if (prevIndex === -1 || newIndex === -1) return;

    const reorderedDashboards = arrayMove(dashboards, prevIndex, newIndex).map((entity, index) => ({
      ...entity,
      order: index + 1,
    }));

    dispatch(setAction({ [type]: reorderedDashboards }));
  };

  return (
    <>
      <DashboardSection
        title="General Dashboards"
        type={DASHBOARDS_GENERAL_TYPE}
        dashboards={dashboardGeneral}
        onDragEnd={handleDragEnd}
        onChange={handleChange}
      />
      <DashboardSection
        title="Custom Dashboards"
        type={DASHBOARDS_CUSTOM_TYPE}
        dashboards={dashboardCustom}
        onDragEnd={handleDragEnd}
        onChange={handleChange}
      />
    </>
  );
}

export default DashboardsTab;
