import { faker } from '@faker-js/faker';
import { action } from '@storybook/addon-actions';
import { Meta, StoryObj } from '@storybook/react';
import React, { useMemo } from 'react';
import { MemoryRouter } from 'react-router-dom';
import {
  createGroups,
  generateItemArray,
  randomDate,
} from '../../../helpers/storybook';
import { Data } from '../../../types/data';
import { FilterType, FilterTypes } from '../../Filters/Filters.model';
import { IconName } from '../../Icons';
import { ExplorerBulkAction, ExplorerDataProvider } from '../Explorer.model';
import { NavigationExplorer } from '../NavigationExplorer/NavigationExplorer';
import {
  createInMemoryDataProvider,
  findAnywhereInStringCaseInsensitive,
} from '../helpers/InMemoryDataProvider';

interface NavExplorerStoryData {
  id: number;
  title: string;
  desc: string;
}

type NavExplorerStoryType = typeof NavigationExplorer<NavExplorerStoryData>;

const groups = createGroups({
  Content: [
    'dataProvider',
    'columns',
    'title',
    'stationKey',
    'actions',
    'bulkActions',
    'defaultFilterValues',
    'defaultSortOrder',
    'filterOptions',
    'generateItemLink',
    'inlineMenuActions',
    'keyProperty',
    'calculateNavigateUrl',
  ],
  Behavior: [
    'selectionMode',
    'enableSelectAll',
    'loadingTriggerOffset',
    'modalMode',
    'onBulkActionsToggled',
    'onItemClicked',
    'openBulkActionsOnStart',
    'persistExplorerStates',
    'onCreateAction',
  ],
  Styling: [
    'className',
    'columnGap',
    'headerRowHeight',
    'listRowHeight',
    'minimumWidth',
    'rowGap',
    'verticalTextAlign',
    'horizontalTextAlign',
    'headerRowActionSize',
    'listRowActionSize',
  ],
});

const meta: Meta<NavExplorerStoryType> = {
  title: 'Primary Components/Station Controls/Explorer/Navigation Explorer',
  component: NavigationExplorer,
  argTypes: {
    ...groups,
  },
};
export default meta;

const generateData = (
  amount: number,
  { startIndex = 1, usePrefix = true } = {},
): NavExplorerStoryData[] =>
  generateItemArray(amount, (i) => {
    const index = i + startIndex;
    return {
      id: index,
      desc: `${usePrefix ? `Description ${index}: ` : ''}${faker.lorem.words(
        faker.datatype.number({ min: 10, max: 20 }),
      )}`,
      date: randomDate(new Date(2019, 0, 1)),
      title: `${usePrefix ? `Index ${index}: ` : ''}${faker.random.words(
        faker.datatype.number({ min: 1, max: 3 }),
      )}`,
    };
  });

const freeTextFilter: FilterType<NavExplorerStoryData> = {
  label: 'Title',
  property: 'title',
  type: FilterTypes.FreeText,
};

const optionFilter: FilterType<NavExplorerStoryData> = {
  label: 'Description',
  property: 'desc',
  type: FilterTypes.Options,
  options: [
    {
      label: "Containing 'ax'",
      value: 'ax',
    },
    {
      label: "Containing 'en'",
      value: 'en',
    },
  ],
};

const generateBulkActions = <T extends Data>(
  amount: number,
): ExplorerBulkAction<T>[] =>
  generateItemArray(amount, (index) => ({
    label: `Bulk Action ${index + 1}`,
    onClick: (args) => {
      action('bulkActionClicked')(args);
      return slowFunc();
    },
    icon: IconName.ChevronRight,
  }));

const slowFunc = (): Promise<unknown> => {
  return new Promise((resolve) => setTimeout(resolve, 1000));
};

export const NavExplorer: StoryObj<NavExplorerStoryType> = {
  name: 'Navigation Explorer',
  decorators: [
    // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
    (Story) => (
      <MemoryRouter>
        <Story />
      </MemoryRouter>
    ),
  ],
  args: {
    title: 'Navigation Explorer',
    columns: [
      {
        propertyName: 'id',
        label: 'Id',
        size: '50px',
      },
      {
        propertyName: 'title',
        label: 'Title',
      },
      {
        propertyName: 'desc',
        label: 'Description',
      },
    ],
    stationKey: 'StoryBookExplorer_NavigationExplorer',
    filterOptions: [freeTextFilter, optionFilter],
    bulkActions: generateBulkActions(4),
    calculateNavigateUrl: (rowData) => `/details/${rowData.id}`,
  },
  render: (args) =>
    React.createElement(() => {
      const dataProvider: ExplorerDataProvider<NavExplorerStoryData> =
        useMemo(() => {
          const pageSize = 20;

          const actualProvider =
            createInMemoryDataProvider<NavExplorerStoryData>(
              generateData(100, { usePrefix: false }),
              {
                filterFunctions: {
                  title: findAnywhereInStringCaseInsensitive,
                  desc: findAnywhereInStringCaseInsensitive,
                },
              },
            );
          return {
            loadData: async (config) => {
              // Report the call
              action('loadData')(config);

              const currentPage = (config.pagingInformation as number) ?? 0;

              // Use the in memory provider to do the heavy lifting
              const { totalCount, filteredCount, data } =
                await actualProvider.loadData(config);

              // Apply paging to the results
              return {
                totalCount: totalCount,
                filteredCount: filteredCount,
                data: data.slice(
                  pageSize * currentPage,
                  pageSize * (currentPage + 1),
                ),
                pagingInformation: currentPage + 1,
                hasMoreData: currentPage < 9,
              };
            },
          };
        }, []);

      return (
        <NavigationExplorer<NavExplorerStoryData>
          {...args}
          dataProvider={dataProvider}
        />
      );
    }),
};
