import React, { useState } from 'react';
import {
  Accordion,
  Divider,
  Grid,
  Paper,
  Stack,
  Text,
  Title,
  useMantineColorScheme,
} from '@mantine/core';
import {
  closestCenter,
  DndContext,
  DragOverlay,
  MouseSensor,
  TouchSensor,
  useSensor,
  useSensors,
} from '@dnd-kit/core';
import { arrayMove, SortableContext } from '@dnd-kit/sortable';
import { useLocalStorage } from '@mantine/hooks';
import { useTranslation } from 'next-i18next';
import { useConfig } from '../../tools/state';

import { SortableAppShelfItem, AppShelfItem } from './AppShelfItem';
import { ModuleMenu, ModuleWrapper } from '../../modules/moduleWrapper';
import { UsenetModule, TorrentsModule } from '../../modules';
import TorrentsComponent from '../../modules/torrents/TorrentsModule';
import { UsenetComponent } from '../../modules/usenet/UsenetModule';

const AppShelf = (props: any) => {
  const { config, setConfig } = useConfig();
  // Extract all the categories from the services in config
  const categoryList = config.services.reduce((acc, cur) => {
    if (cur.category && !acc.includes(cur.category)) {
      acc.push(cur.category);
    }
    return acc;
  }, [] as string[]);

  const [toggledCategories, setToggledCategories] = useLocalStorage({
    key: 'app-shelf-toggled',
    // This is a bit of a hack to toggle the categories on the first load, return a string[] of the categories
    defaultValue: categoryList,
  });
  const [activeId, setActiveId] = useState(null);
  const { colorScheme } = useMantineColorScheme();

  const { t } = useTranslation('layout/app-shelf');

  const sensors = useSensors(
    useSensor(TouchSensor, {
      activationConstraint: {
        delay: 500,
        tolerance: 5,
      },
    }),
    useSensor(MouseSensor, {
      // Require the mouse to move by 10 pixels before activating
      activationConstraint: {
        delay: 500,
        tolerance: 5,
      },
    })
  );

  function handleDragStart(event: any) {
    const { active } = event;

    setActiveId(active.id);
  }

  function handleDragEnd(event: any) {
    const { active, over } = event;

    if (active.id !== over.id) {
      const newConfig = { ...config };
      const activeIndex = newConfig.services.findIndex((e) => e.id === active.id);
      const overIndex = newConfig.services.findIndex((e) => e.id === over.id);
      newConfig.services = arrayMove(newConfig.services, activeIndex, overIndex);
      setConfig(newConfig);
    }

    setActiveId(null);
  }

  const getItems = (filter?: string) => {
    // If filter is not set, return all the services without a category or a null category
    let filtered = config.services;
    if (!filter) {
      filtered = config.services.filter((e) => !e.category || e.category === null);
    }
    if (filter) {
      filtered = config.services.filter((e) => e.category === filter);
    }

    return (
      <DndContext
        sensors={sensors}
        collisionDetection={closestCenter}
        onDragStart={handleDragStart}
        onDragEnd={handleDragEnd}
      >
        <SortableContext items={config.services}>
          <Grid gutter="xl" align="center">
            {filtered.map((service) => (
              <Grid.Col
                key={service.id}
                span={6}
                xl={config.settings.appCardWidth || 2}
                xs={4}
                sm={3}
                md={3}
              >
                <SortableAppShelfItem service={service} key={service.id} id={service.id} />
              </Grid.Col>
            ))}
          </Grid>
        </SortableContext>
        <DragOverlay
          style={{
            // Add a shadow to the drag overlay
            boxShadow: '0 0 10px rgba(0, 0, 0, 0.5)',
          }}
        >
          {activeId ? (
            <AppShelfItem service={config.services.find((e) => e.id === activeId)} id={activeId} />
          ) : null}
        </DragOverlay>
      </DndContext>
    );
  };

  if (categoryList.length > 0) {
    const noCategory = config.services.filter(
      (e) => e.category === undefined || e.category === null
    );

    const torrentEnabled = config.modules?.[TorrentsModule.id]?.enabled ?? false;
    const usenetEnabled = config.modules?.[UsenetModule.id]?.enabled ?? false;

    const downloadEnabled = usenetEnabled || torrentEnabled;
    // Create an item with 0: true, 1: true, 2: true... For each category
    return (
      // TODO: Style accordion so that the bar is transparent to the user settings
      <Stack>
        <Accordion
          variant="separated"
          radius="lg"
          order={2}
          multiple
          value={toggledCategories}
          onChange={(state) => {
            setToggledCategories([...state]);
          }}
        >
          {categoryList.map((category, idx) => (
            <Accordion.Item
              style={{
                background: `rgba(${colorScheme === 'dark' ? '32, 33, 35,' : '255, 255, 255,'} \
              ${(config.settings.appOpacity || 100) / 100}`,
                borderColor: `rgba(${colorScheme === 'dark' ? '32, 33, 35,' : '233, 236, 239,'} \
              ${(config.settings.appOpacity || 100) / 100}`,
              }}
              key={category}
              value={idx.toString()}
            >
              <Accordion.Control>{category}</Accordion.Control>
              <Accordion.Panel>{getItems(category)}</Accordion.Panel>
            </Accordion.Item>
          ))}
          {/* Return the item for all services without category */}
          {noCategory && noCategory.length > 0 ? (
            <Accordion.Item
              style={{
                background: `rgba(${colorScheme === 'dark' ? '32, 33, 35,' : '255, 255, 255,'} \
            ${(config.settings.appOpacity || 100) / 100}`,
                borderColor: `rgba(${colorScheme === 'dark' ? '32, 33, 35,' : '233, 236, 239,'} \
            ${(config.settings.appOpacity || 100) / 100}`,
              }}
              key="Other"
              value="Other"
            >
              <Accordion.Control>{t('accordions.others.text')}</Accordion.Control>
              <Accordion.Panel>{getItems()}</Accordion.Panel>
            </Accordion.Item>
          ) : null}
          {downloadEnabled ? (
            <Accordion.Item
              style={{
                color: `rgba(${colorScheme === 'dark' ? '32, 33, 35,' : '255, 255, 255,'} \
                ${(config.settings.appOpacity || 100) / 100}`,
                background: `rgba(${colorScheme === 'dark' ? '32, 33, 35,' : '255, 255, 255,'} \
            ${(config.settings.appOpacity || 100) / 100}`,
                borderColor: `rgba(${colorScheme === 'dark' ? '32, 33, 35,' : '233, 236, 239,'} \
            ${(config.settings.appOpacity || 100) / 100}`,
              }}
              key="Downloads"
              value="Your downloads"
            >
              <Accordion.Control>{t('accordions.downloads.text')}</Accordion.Control>
              <Accordion.Panel>
                <Paper radius="lg" style={{ position: 'relative' }}>
                      {torrentEnabled && (
                    <>
                      <Text>{t('accordions.downloads.torrents')}</Text>
                      <ModuleMenu module={TorrentsModule} hovered />
                      <TorrentsComponent />
                    </>
                  )}
                  {usenetEnabled && (
                    <>
                      <Text mt="md">{t('accordions.downloads.usenet')}</Text>
                      <ModuleMenu module={UsenetModule} hovered />
                      <UsenetComponent />
                    </>
                  )}
                </Paper>
              </Accordion.Panel>
            </Accordion.Item>
          ) : null}
        </Accordion>
      </Stack>
    );
  }
  return (
    <Stack>
      {getItems()}
      <ModuleWrapper mt="xl" module={TorrentsModule} />
      <ModuleWrapper mt="xl" module={UsenetModule} />
    </Stack>
  );
};

export default AppShelf;
