import { faker } from '@faker-js/faker';
import { action } from '@storybook/addon-actions';
import { Meta, StoryObj } from '@storybook/react';
import React from 'react';
import * as Yup from 'yup';
import { createGroups, generateItemArray } from '../../helpers/storybook';
import { ButtonContext } from '../Buttons';
import { DynamicDataList, DynamicDataListProps } from './DynamicDataList';
import { DynamicListColumn } from './DynamicDataList.model';
import {
  DynamicListDataEntry,
  DynamicListDataEntryProps,
} from './DynamicListDataEntry/DynamicListDataEntry';
import { createInputRenderer } from './DynamicListDataEntry/Renderers/createInputRenderer/createInputRenderer';
import { createSelectRenderer } from './DynamicListDataEntry/Renderers/createSelectRenderer/createSelectRenderer';

interface DynamicListStoryData {
  position?: number;
  id: number;
  desc?: string;
  title: string;
}

type StoryDDLType = typeof DynamicDataList<DynamicListStoryData>;

const defaultColumns: DynamicListColumn<DynamicListStoryData>[] = [
  {
    propertyName: 'id',
    label: 'Id',
    size: '50px',
  },
  {
    propertyName: 'title',
    label: 'Title',
  },
  {
    propertyName: 'desc',
    label: 'Description',
  },
];

const generateData = (amount: number): DynamicListStoryData[] =>
  generateItemArray(amount, (index) => ({
    position: amount - index, // Position and ID is jumbled for demonstration purposes
    id: index,
    desc: `Description ${index}: ${faker.lorem.words(
      faker.datatype.number({ min: 10, max: 50 }),
    )}`,
    title: `Item ${index}: ${faker.random.words(
      faker.datatype.number({ min: 1, max: 3 }),
    )}`,
  }));

const groups = createGroups({
  Content: [
    'columns',
    'value',
    'positionLabel',
    'defaultValuesForNewData',
    'inlineMenuActions',
    'onAddTransformData',
    'rowValidationSchema',
    'customDataEntry',
    'positionPropertyName',
  ],
  Behavior: [
    'allowRowDragging',
    'allowNewData',
    'allowEditing',
    'showHeader',
    'allowAddAndRemove',
    'allowReordering',
    'disabled',
    'maxItemLimit',
    'stickyHeader',
    'onChange',
  ],
  //Content: [],
  Styling: [
    'className',
    'columnGap',
    'rowGap',
    'minimumWidth',
    'headerRowHeight',
    'listRowHeight',
    'listRowActionSize',
    'headerRowActionSize',
    'horizontalTextAlign',
    'verticalTextAlign',
    'textWrap',
    'rowClassNameProvider',
  ],
});

const defaultProps: DynamicDataListProps<DynamicListStoryData> = {
  positionPropertyName: 'position',
  value: generateData(5),
  columns: defaultColumns,
  //TODO: investigate why this is needed - looks like it gets mocked out somehow
  onAddTransformData: (data) => data as DynamicListStoryData,
};

const meta: Meta<StoryDDLType> = {
  title: 'Other Components/DynamicDataList',
  component: DynamicDataList,
  argTypes: {
    ...groups,
    customDataEntry: {
      ...groups.customDataEntry,
      control: false,
    },
    positionLabel: {
      ...groups.positionLabel,
      controls: false,
    },
  },
};
export default meta;

export const Default: StoryObj<StoryDDLType> = {
  args: {
    ...defaultProps,
  },
};

export const UnboundColumn: StoryObj<StoryDDLType> = {
  args: {
    ...defaultProps,
    columns: [
      ...defaultColumns,
      {
        label: 'Unbound',
        render: () => 'Unbound',
        key: 'unbound',
        size: '150px',
      },
    ],
  },
};

const Bold = (value: unknown): React.ReactNode => <b>{value as string}</b>;

export const WithCustomRenderer: StoryObj<StoryDDLType> = {
  name: 'With custom renderer',
  args: {
    ...defaultProps,
    columns: [
      {
        propertyName: 'id',
        label: 'Id',
        size: '50px',
      },
      {
        propertyName: 'title',
        label: 'Title',
        render: Bold,
      },
      {
        propertyName: 'desc',
        label: 'Description',
      },
    ],
  },
};

export const WithInputRenderer: StoryObj<StoryDDLType> = {
  name: 'With input renderer',
  args: {
    ...defaultProps,
    columns: [
      {
        propertyName: 'id',
        label: 'Id',
        size: '50px',
        dataEntryRender: createInputRenderer({
          placeholder: 'Enter Id',
        }),
      },
      {
        propertyName: 'title',
        label: 'Title',
        dataEntryRender: createInputRenderer({
          placeholder: 'Enter Title',
        }),
        onAddTransformer: (val) => (val as string).toUpperCase(),
      },
      {
        propertyName: 'desc',
        label: 'Description',
        dataEntryRender: createInputRenderer(),
      },
    ],
    allowNewData: true,
    defaultValuesForNewData: { desc: 'Description' },
    rowValidationSchema: Yup.object({
      id: Yup.number().required(),
      title: Yup.string().required().max(25).label('Title'),
    }),
  },
};

const stringToNumberTransformer = (value: string): number => Number(value);
export const WithSelectInputRenderer: StoryObj<StoryDDLType> = {
  name: 'With select input renderer',
  args: {
    ...defaultProps,
    columns: [
      {
        propertyName: 'id',
        label: 'Id',
        size: '100px',
        dataEntryRender: createSelectRenderer({
          options: [
            { value: '10', label: '10' },
            { value: '11', label: '11' },
            { value: '12', label: '12' },
          ],
          // defaultValue: '12',
          placeholder: 'Enter Id',
          transform: stringToNumberTransformer,
        }),
      },
      {
        propertyName: 'title',
        label: 'Title',
        dataEntryRender: createSelectRenderer({
          options: [
            { value: 'item 10', label: 'Item 10' },
            { value: 'item 11', label: 'Item 11' },
            { value: 'item 12', label: 'Item 12' },
          ],
          placeholder: 'Enter Title',
        }),
      },
      {
        propertyName: 'desc',
        label: 'Description',
        dataEntryRender: createSelectRenderer({
          options: [
            { value: 'description 10', label: 'Description 10' },
            { value: 'description 11', label: 'Description 11' },
            { value: 'description 12', label: 'Description 12' },
          ],
          placeholder: 'Enter Description',
        }),
      },
    ],
    allowNewData: true,
    rowValidationSchema: Yup.object({
      id: Yup.number().required(),
      title: Yup.string().required().max(25).label('Title'),
    }),
  },
};

const CustomDynamicListDataEntry: React.FC<
  DynamicListDataEntryProps<DynamicListStoryData>
> = (props) => {
  const { onActionClicked, ...rest } = props;

  return (
    <DynamicListDataEntry
      {...rest}
      onActionClicked={(data) => {
        onActionClicked && onActionClicked({ ...generateData(1)[0], ...data });
      }}
      actionButtonContext={ButtonContext.Active}
    />
  );
};
export const WithCustomDataEntry: StoryObj<StoryDDLType> = {
  name: 'With custom data entry',
  args: {
    ...defaultProps,
    allowNewData: true,
    customDataEntry: CustomDynamicListDataEntry,
    //TODO: investigate why this is needed - looks like it gets mocked out somehow
    onAddTransformData: (data) => data as DynamicListStoryData,
  },
};

export const ManyRows: StoryObj<StoryDDLType> = {
  name: 'Many rows',
  args: {
    ...defaultProps,
    columns: [
      {
        propertyName: 'id',
        label: 'Id',
        dataEntryRender: createInputRenderer({
          placeholder: 'Enter Id',
        }),
      },
      {
        propertyName: 'title',
        label: 'Title',
        dataEntryRender: createInputRenderer({
          placeholder: 'Enter Title',
        }),
      },
      {
        propertyName: 'desc',
        label: 'Description',
        dataEntryRender: createInputRenderer(),
      },
    ],
    defaultValuesForNewData: { desc: 'Description' },
    rowValidationSchema: Yup.object({
      id: Yup.number().required(),
      title: Yup.string().required().max(25).label('Title'),
    }),
    value: generateData(100),
    allowNewData: true,
  },
};

export const GapsInData: StoryObj<StoryDDLType> = {
  name: 'Gaps in data',
  args: {
    ...defaultProps,
    value: [
      {
        position: 1,
        id: 1,
        desc: 'Description 1',
        title: 'Title 1',
      },
      {
        position: 2,
        id: 2,
        desc: 'Description 2',
        title: 'Title 2',
      },
      {
        position: 5,
        id: 5,
        desc: 'Description 5',
        title: 'Title 5',
      },
      {
        position: 6,
        id: 6,
        desc: 'Description 6',
        title: 'Title 6',
      },
      {
        position: 7,
        id: 7,
        desc: 'Description 7',
        title: 'Title 7',
      },
      {
        position: 8,
        id: 8,
        desc: 'Description 8',
        title: 'Title 8',
      },
      {
        position: 20,
        id: 20,
        desc: 'Description 20 Description 20Description 20Description 20Description 20Description 20Description 20Description 20Description 20',
        title: 'Title 20',
      },
      {
        position: 100,
        id: 100,
        desc: 'Description 100',
        title: 'Title 100',
      },
    ],
  },
};

export const WithInlineMenu: StoryObj<StoryDDLType> = {
  name: 'With inline menu',
  args: {
    ...defaultProps,
    inlineMenuActions: (_) => [
      {
        label: 'Action 1',
        onActionSelected: action('onChange'),
      },
      {
        label: 'Action 2',
        onActionSelected: action('onChange'),
        confirmationMode: 'Simple',
      },
      {
        label: 'Action 3',
        onActionSelected: action('onChange'),
        confirmationMode: 'Advanced',
      },
    ],
  },
};

export const Editable: StoryObj<StoryDDLType> = {
  name: 'Editable',
  args: {
    ...defaultProps,
    columns: [
      {
        propertyName: 'id',
        label: 'Id',
        size: '50px',
        dataEntryRender: createInputRenderer({
          placeholder: 'Enter Id',
        }),
      },
      {
        propertyName: 'title',
        label: 'Title',
        dataEntryRender: createInputRenderer({
          placeholder: 'Enter Title',
        }),
      },
      {
        propertyName: 'desc',
        label: 'Description',
        dataEntryRender: createInputRenderer(),
      },
    ],
    allowNewData: true,
    allowEditing: true,
    defaultValuesForNewData: { desc: 'Description' },
    rowValidationSchema: Yup.object({
      id: Yup.number().required(),
      title: Yup.string().required().max(25).label('Title'),
    }),
  },
};
