import { userEvent, within, expect } from 'storybook/test';
import { action } from 'storybook/actions';
import { withVariantConfig } from '../../.storybook/helpers';
import { lorem20 } from '../test-utils';
import { wait } from '../test-utils/wait';
import Button from '../button';
import { Snackbar, type SnackbarProps } from './Snackbar';
import { SnackbarConsumer } from './SnackbarContext';
import SnackbarProvider from './SnackbarProvider';

export default {
  title: 'Dialogs/Snackbar/Tests',
  component: Snackbar,
  argTypes: {},
  tags: ['!autodocs', '!manifest'],
};

const launchSnackbar = async (canvasElement: HTMLElement) => {
  await wait(0);
  const canvas = within(canvasElement);
  await userEvent.click(canvas.getByRole('button'));
};

type Args = Partial<SnackbarProps> & {
  extraContext: React.ReactNode;
  timeout: number;
};

const TIMEOUT = 10000000;

const Default = {
  args: {
    timeout: TIMEOUT,
  } as Args,
  play: async ({ canvasElement }: { canvasElement: HTMLElement }) => {
    await launchSnackbar(canvasElement);
  },
  render: (args: Args) => {
    return (
      <SnackbarProvider timeout={args.timeout}>
        <SnackbarConsumer>
          {({ createSnackbar }) => (
            <>
              <Button
                v2
                block
                onClick={() => {
                  createSnackbar({
                    action: {
                      label: 'View',
                      onClick: () => action('View button clicked.'),
                    },
                    text: <span>Some text</span>,
                  });
                }}
              >
                Show Snackbar
              </Button>
              {args.extraContext}
            </>
          )}
        </SnackbarConsumer>
      </SnackbarProvider>
    );
  },
};

export const Basic = {
  ...Default,
  args: {
    ...Default.args,
  },
};

export const Mobile = {
  ...Default,
  args: {
    ...Default.args,
  },
  ...withVariantConfig(['mobile'], Default),
};

const switchToDarkMode = async (context: { canvasElement: HTMLElement }) => {
  await Default.play(context);

  // the snackbar is outside the storybook dom so dark mode doesn't apply
  const body = document.querySelector('div.np-theme-personal');
  if (body) {
    body.setAttribute('class', 'np-theme-personal--dark');
  }
  const snackbar = document.querySelector('div.snackbar');
  if (snackbar) {
    snackbar.setAttribute('class', 'snackbar np-theme-personal--dark');
  }
};

export const DarkMode = {
  ...Default,
  args: {
    ...Default.args,
  },
  play: switchToDarkMode,
  ...withVariantConfig(['dark'], Default),
};

const switchToRTL = async (context: { canvasElement: HTMLElement }) => {
  await Default.play(context);
  // the snackbar is outside the storybook dom so the RTL variant doesn't apply
  const body = document.querySelector('div.storybook-container');
  if (body) {
    body.setAttribute('dir', 'rtl');
  }
  const snackbar = document.querySelector('div.snackbar');
  if (snackbar) {
    snackbar.setAttribute('dir', 'rtl');
  }
};

export const RTL = {
  ...Default,
  args: {
    ...Default.args,
  },
  play: switchToRTL,
  ...withVariantConfig(['rtl'], Default),
};

export const RTLMobile = {
  ...Default,
  args: {
    ...RTL.args,
  },
  play: switchToRTL,
  ...withVariantConfig(['rtl', 'mobile'], Default),
};

export const Zoom400 = {
  ...Default,
  args: {
    ...Default.args,
    extraContext: (
      <div className="p-t-3">
        Snackbar isn&#39;t transparent (I&#39;m going to make this text very long so that it will
        fill up the entire page and go behind the snackbar. This way, when you look at it you will
        easily be able to tell if the snackbar is transparent and recognize the bug because we
        don&#39;t want it to be transparent. Transparent is bad. When we first did rebrand we had a
        lot of problems with transparencies. {lorem20}
      </div>
    ),
  },
  ...withVariantConfig(['400%'], Default),
};

/**
 * Snackbar is only shown once even if trigger is clicked many times
 */
export const MultipleClicks = {
  ...Default,
  args: {
    ...Default.args,
  },
  play: async ({ canvasElement }: { canvasElement: HTMLElement }) => {
    const canvas = within(canvasElement);
    for (let i = 0; i < 8; i += 1) {
      await userEvent.click(canvas.getByRole('button'));
    }

    await expect(within(document.body).getAllByRole('alert')).toHaveLength(1);
  },
};
