import { StoryObj, type Decorator } from '@storybook/react-webpack5';
import type { ListItemProps } from '../ListItem';
import { LISTITEM_CQ } from '../constants';

type Story = StoryObj<ListItemProps>;

/**
 * Recent storybook versions render the full source including all story parameters which
 * creates noise, this simple workaround only shows the render function.
 * This is a workaround for the issue.
 * @see https://github.com/storybookjs/storybook/issues/22281
 */
export const storySourceWithoutNoise = (config: Story): Story => {
  const newConfig: Story = {
    ...config,
    parameters: {
      ...config.parameters,
      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
      docs: {
        ...config.parameters?.docs,
        // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
        source: {
          // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
          ...config.parameters?.docs?.source,
          type: 'code',
          transform: (code: string) =>
            code
              // eslint-disable-next-line regexp/no-super-linear-backtracking
              .replace(/storySourceWithoutNoise\(\{.+render\s?:\s+(.*)\}\)$/gms, '$1'),
        },
      },
    },
  };

  return newConfig;
};

/**
 * In order to make preview controls work correctly, we have to refresh the render
 * by swapping the `key`. This is a workaround for the Storybook's limitation.
 */
export const withoutKey: Decorator = (Story, { args }) => {
  const key = [
    args.previewInteractivity,
    args?.disabled ? 'disabled' : 'enabled',
    args?.disabledPromptMessage ? 'withReason' : 'withoutReason',
    args?.inverted ? 'desc' : 'asc',
  ].join('-');

  return <Story key={key} />;
};

export const withSizedContainer =
  (size: 'small' | 'medium' | 'large' | number = 'large', border = true): Decorator =>
  (Story, { args }) => {
    const width =
      typeof size === 'number'
        ? size
        : {
            small: LISTITEM_CQ.MIN,
            medium: Math.round((LISTITEM_CQ.MAX - LISTITEM_CQ.MIN) / 2 + LISTITEM_CQ.MIN),
            large: LISTITEM_CQ.MAX + 1,
          }[size];
    return (
      <div
        style={{
          width,
          border: border ? '1px dashed #ccc' : undefined,
        }}
      >
        <Story />
      </div>
    );
  };

/**
 * Not all stories need access to all controls as it causes unnecessary UI noise.
 */
export const disableControls =
  (hiddenByDefault: string[] = []) =>
  (hiddenForStory: string[] = []) => {
    const hiddenControls = hiddenByDefault.concat(hiddenForStory);
    return Object.fromEntries(hiddenControls.map((item) => [item, { table: { disable: true } }]));
  };
