import { useState } from 'react';
import { userEvent, within, expect } from '@storybook/test';
import { Meta, StoryObj } from '@storybook/react';
import PrimitiveButton from '../src';

const meta = {
  title: 'Primitives/Button/Tests',
  component: PrimitiveButton,
  args: {
    children: 'Button text',
  },
  tags: ['autodocs'],
} satisfies Meta<typeof PrimitiveButton>;

export default meta;

type Story = StoryObj<typeof meta>;

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

export const ClickInteraction: Story = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    const button = canvas.getByRole('button');
    await userEvent.click(button);
    await expect(button).toHaveTextContent('Clicked!');
  },
  render: function Render(args) {
    const [clicked, setClicked] = useState(false);

    return (
      <PrimitiveButton {...args} onClick={() => setClicked(true)}>
        {clicked ? 'Clicked!' : 'Button text'}
      </PrimitiveButton>
    );
  },
};

export const FocusInteraction: Story = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    const button = canvas.getByRole('button');
    await userEvent.tab();
    await expect(button).toHaveFocus();
    await expect(button).toHaveTextContent('Focused!');
  },
  render: function Render(args) {
    const [focused, setFocused] = useState(false);

    return (
      <PrimitiveButton {...args} onFocus={() => setFocused(true)}>
        {focused ? 'Focused!' : 'Button text'}
      </PrimitiveButton>
    );
  },
};

export const BlurInteraction: Story = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    const button = canvas.getByRole('button');
    await userEvent.tab();
    await expect(button).toHaveFocus();
    await userEvent.tab();
    await expect(button).not.toHaveFocus();
    await expect(button).toHaveTextContent('Blurred!');
  },
  render: function Render(args) {
    const [blurred, setBlurred] = useState(false);

    return (
      <PrimitiveButton {...args} onBlur={() => setBlurred(true)}>
        {blurred ? 'Blurred!' : 'Button text'}
      </PrimitiveButton>
    );
  },
};

export const MouseEnterInteraction: Story = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    const button = canvas.getByRole('button');
    await userEvent.hover(button);
    await expect(button).toHaveTextContent('Hovered!');
  },
  render: function Render(args) {
    const [hovered, setHovered] = useState(false);

    return (
      <PrimitiveButton {...args} onMouseEnter={() => setHovered(true)}>
        {hovered ? 'Hovered!' : 'Button text'}
      </PrimitiveButton>
    );
  },
};

export const MouseLeaveInteraction: Story = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    const button = canvas.getByRole('button');
    await userEvent.unhover(button);
    await expect(button).toHaveTextContent('Left!');
  },
  render: function Render(args) {
    const [left, setLeft] = useState(false);

    return (
      <PrimitiveButton {...args} onMouseLeave={() => setLeft(true)}>
        {left ? 'Left!' : 'Button text'}
      </PrimitiveButton>
    );
  },
};

export const KeyDownInteraction: Story = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    const button = canvas.getByRole('button');
    await userEvent.type(button, '{enter}');
    await expect(button).toHaveTextContent('Key Pressed!');
  },
  render: function Render(args) {
    const [keyPressed, setKeyPressed] = useState(false);

    return (
      <PrimitiveButton {...args} onKeyDown={() => setKeyPressed(true)}>
        {keyPressed ? 'Key Pressed!' : 'Button text'}
      </PrimitiveButton>
    );
  },
};

export const DisabledClickInteraction: Story = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    const button = canvas.getByRole('button');
    await userEvent.click(button);
    await expect(button).toHaveTextContent('Button text');
  },
  render: function Render(args) {
    return (
      <PrimitiveButton {...args} disabled>
        Button text
      </PrimitiveButton>
    );
  },
};

export const DisabledFocusInteraction: Story = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    const button = canvas.getByRole('button');
    await userEvent.tab();
    await expect(button).not.toHaveFocus();
  },
  render: function Render(args) {
    return (
      <PrimitiveButton {...args} disabled>
        Button text
      </PrimitiveButton>
    );
  },
};

export const DisabledBlurInteraction: Story = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    const button = canvas.getByRole('button');
    await userEvent.tab();
    await expect(button).not.toHaveFocus();
  },
  render: function Render(args) {
    return (
      <PrimitiveButton {...args} disabled>
        Button text
      </PrimitiveButton>
    );
  },
};

export const DisabledKeyDownInteraction: Story = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    const button = canvas.getByRole('button');
    await userEvent.type(button, '{enter}');
    await expect(button).toHaveTextContent('Button text');
  },
  render: function Render(args) {
    return (
      <PrimitiveButton {...args} disabled>
        Button text
      </PrimitiveButton>
    );
  },
};

export const DisabledMouseEnterInteraction: Story = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    const button = canvas.getByRole('button');
    await userEvent.hover(button);
    await expect(button).toHaveTextContent('Button text');
  },
  render: function Render(args) {
    return (
      <PrimitiveButton {...args} disabled>
        Button text
      </PrimitiveButton>
    );
  },
};

export const DisabledMouseLeaveInteraction: Story = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    const button = canvas.getByRole('button');
    await userEvent.unhover(button);
    await expect(button).toHaveTextContent('Button text');
  },
  render: function Render(args) {
    return (
      <PrimitiveButton {...args} disabled>
        Button text
      </PrimitiveButton>
    );
  },
};
