import type { Meta, StoryObj } from '@storybook/react-webpack5';
import { expect, userEvent, within } from 'storybook/test';

import { withVariantConfig } from '../../.storybook/helpers';
import { Button } from '..';
import { Position } from '../common';

import Popover, { PopoverPreferredPlacement } from './Popover';

const meta = {
  title: 'Dialogs/Popover/Tests',
  component: Popover,
  tags: ['!autodocs', '!manifest'],
} satisfies Meta<typeof Popover>;
export default meta;

type Story = StoryObj<typeof Popover>;

const wait = async (duration = 500) =>
  new Promise<void>((resolve) => {
    setTimeout(resolve, duration);
  });

const createPlacementStory = (
  placement: PopoverPreferredPlacement,
  containerStyle?: React.CSSProperties,
): Story => ({
  parameters: {
    chromatic: {
      delay: 1000,
    },
  },
  render: () => (
    <div
      style={
        containerStyle
          ? { position: 'absolute', ...containerStyle }
          : { display: 'flex', justifyContent: 'center', padding: '150px' }
      }
    >
      <Popover preferredPlacement={placement} title="Info" content="Details">
        <Button v2>{placement}</Button>
      </Popover>
    </div>
  ),
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    await userEvent.click(canvas.getByRole('button'));
  },
});

/**
 * This test insures that there's no unintended page scroll after the popover
 * is closed without selecting an option (e.g. clicking outside).
 * It tests 2 scenarios:
 * 1. when the popover fits naturally on the screen below the trigger
 * 2. when there's not enough space below the trigger and it renders above it
 */
const generateNoScrollTest = (inverted?: boolean): Story => ({
  render: function Render() {
    return (
      <div>
        <style>
          {`
            .storybook-container{
              min-height: unset;
              height: unset;
            }
          `}
        </style>
        {inverted ? <p style={{ height: '70vh', background: 'blanchedalmond' }} /> : null}

        <Popover
          content="Popover content for testing"
          title="Popover Title"
          preferredPlacement="top"
        >
          <Button v2>Open Popover</Button>
        </Popover>

        <p style={{ margin: '1rem 0', height: '150vh', background: 'blanchedalmond' }} />
      </div>
    );
  },
  play: async ({ canvasElement, step }) => {
    const canvas = within(canvasElement);
    const trigger = canvas.getByRole('button', { name: /Open Popover/i });

    await step('Open the popover', async () => {
      await userEvent.click(trigger);
      await wait();
    });

    await step('Close the popover with Escape', async () => {
      await userEvent.keyboard('{Escape}');
      await wait();
    });

    await step('Verify the page has not scrolled', async () => {
      const scrollParent = canvasElement.ownerDocument.documentElement;
      await expect(scrollParent.scrollTop).toBe(0);
    });
  },
});

export const PlacementTop: Story = createPlacementStory(Position.TOP);
export const PlacementRight: Story = createPlacementStory(Position.RIGHT);
export const PlacementBottom: Story = createPlacementStory(Position.BOTTOM);
export const PlacementLeft: Story = createPlacementStory(Position.LEFT);

export const FlipTop: Story = createPlacementStory(Position.TOP, { top: 0, left: '50%' });
export const FlipRight: Story = createPlacementStory(Position.RIGHT, { top: '50%', right: 0 });
export const FlipBottom: Story = createPlacementStory(Position.BOTTOM, { bottom: 0, left: '50%' });
export const FlipLeft: Story = createPlacementStory(Position.LEFT, { top: '50%', left: 0 });

export const NoScrollAfterCloseTop: Story = {
  ...generateNoScrollTest(),
  ...withVariantConfig(['default']),
};

export const NoScrollAfterCloseBottom: Story = {
  ...generateNoScrollTest(true),
  ...withVariantConfig(['default']),
};
