import { faker } from '@faker-js/faker';
import { action } from '@storybook/addon-actions';
import { Meta, StoryObj } from '@storybook/react';
import { noop } from 'lodash';
import React, { useMemo } from 'react';
import { MemoryRouter } from 'react-router';
import {
  createGroups,
  generateItemArray,
  randomDate,
} from '../../../helpers/storybook';
import { FilterType, FilterTypes } from '../../Filters/Filters.model';
import { IconName } from '../../Icons';
import {
  ExplorerDataProvider,
  ExplorerDataProviderConfiguration,
} from '../Explorer.model';
import { SelectionExplorer } from '../SelectionExplorer/SelectionExplorer';
import {
  createInMemoryDataProvider,
  findAnywhereInStringCaseInsensitive,
} from '../helpers/InMemoryDataProvider';

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

type SelectionExplorerStoryType =
  typeof SelectionExplorer<SelectExplorerStoryData>;

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

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

const generateData = (
  amount: number,
  { startIndex = 1, usePrefix = true } = {},
): SelectExplorerStoryData[] =>
  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 generateDataProvider =
  (): ExplorerDataProvider<SelectExplorerStoryData> => {
    const pageSize = 20;

    const actualProvider = createInMemoryDataProvider<SelectExplorerStoryData>(
      generateData(100, {
        usePrefix: false,
      }),
      {
        filterFunctions: {
          title: findAnywhereInStringCaseInsensitive,
          desc: findAnywhereInStringCaseInsensitive,
        },
      },
    );
    return {
      loadData: async (
        config: ExplorerDataProviderConfiguration<SelectExplorerStoryData>,
      ) => {
        // 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,
        };
      },
    };
  };

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

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

export const Default: StoryObj<SelectionExplorerStoryType> = {
  args: {
    title: 'Selection Explorer',
    columns: [
      {
        propertyName: 'id',
        label: 'Id',
        size: '50px',
      },
      {
        propertyName: 'title',
        label: 'Title',
      },
      {
        propertyName: 'desc',
        label: 'Description',
      },
    ],
    stationKey: 'StoryBookExplorer_SelectExplorer',
    filterOptions: [freeTextFilter, optionFilter],
    allowBulkSelect: false,
    enableSelectAll: true,
  },
  render: (args) =>
    React.createElement(() => {
      const dataProvider: ExplorerDataProvider<SelectExplorerStoryData> =
        useMemo(generateDataProvider, []);

      return (
        <SelectionExplorer<SelectExplorerStoryData>
          {...args}
          dataProvider={dataProvider}
        />
      );
    }),
};

export const WithOpenDetailsInlineAction: StoryObj<SelectionExplorerStoryType> =
  {
    args: {
      ...Default.args,
      stationKey: 'SelectionStoryBookExplorer_WithOpenDetailsInlineAction',
      generateItemLink: () => `#`,
    },
    render: (args) =>
      React.createElement(() => {
        const dataProvider: ExplorerDataProvider<SelectExplorerStoryData> =
          useMemo(generateDataProvider, []);

        return (
          <MemoryRouter>
            <SelectionExplorer<SelectExplorerStoryData>
              {...args}
              dataProvider={dataProvider}
            />
          </MemoryRouter>
        );
      }),
  };

export const WithInlineActions: StoryObj<SelectionExplorerStoryType> = {
  args: {
    ...Default.args,
    stationKey: 'SelectionStoryBookExplorer_WithInlineActions',
    inlineMenuActions: () => {
      return [
        {
          label: 'Navigation Action',
          icon: IconName.NavigateRight,
          path: '#',
        },
        {
          label: 'Context Action',
          icon: IconName.Ellipsis,
          onActionSelected: noop,
        },
      ];
    },
  },
  render: (args) =>
    React.createElement(() => {
      const dataProvider: ExplorerDataProvider<SelectExplorerStoryData> =
        useMemo(generateDataProvider, []);

      return (
        <MemoryRouter>
          <SelectionExplorer<SelectExplorerStoryData>
            {...args}
            dataProvider={dataProvider}
          />
        </MemoryRouter>
      );
    }),
};
