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

import { withVariantConfig } from '../../.storybook/helpers';
import CheckboxButton from './CheckboxButton';

export default {
  component: CheckboxButton,
  title: 'Actions/CheckboxButton/Tests',
  tags: ['!autodocs', '!manifest'],
} satisfies Meta<typeof CheckboxButton>;

type Story = StoryObj<typeof CheckboxButton>;

/** All checkbox states across all themes. */
export const Variants: Story = {
  render: function Render() {
    const [unchecked, setUnchecked] = useState(false);
    const [checked, setChecked] = useState(true);
    const [indeterminate, setIndeterminate] = useState(false);
    return (
      <div style={{ display: 'flex', gap: '16px', alignItems: 'center', padding: '16px' }}>
        <CheckboxButton
          aria-label="Unchecked"
          checked={unchecked}
          onChange={() => setUnchecked((v) => !v)}
        />
        <CheckboxButton
          aria-label="Checked"
          checked={checked}
          onChange={() => setChecked((v) => !v)}
        />
        <CheckboxButton
          aria-label="Indeterminate"
          checked={indeterminate}
          indeterminate
          onChange={() => setIndeterminate((v) => !v)}
        />
        <CheckboxButton
          aria-label="Disabled unchecked"
          checked={false}
          disabled
          onChange={() => {}}
        />
        <CheckboxButton aria-label="Disabled checked" checked disabled onChange={() => {}} />
      </div>
    );
  },
  ...withVariantConfig(['default', 'dark', 'bright-green', 'forest-green']),
};

/**
 * `Space` toggles when focused (requires `onChange`). Tab skips disabled checkboxes.
 * Indeterminate resolves to checked on first `Space`, then toggles normally.
 */
export const KeyboardInteraction: Story = {
  render: function Render() {
    const [unchecked, setUnchecked] = useState(false);
    const [checked, setChecked] = useState(true);
    const [indeterminate, setIndeterminate] = useState(false);
    const [disabledUnchecked] = useState(false);
    const [disabledChecked] = useState(true);

    const row: React.CSSProperties = {
      display: 'flex',
      alignItems: 'center',
      gap: '8px',
    };

    const label: React.CSSProperties = {
      fontSize: '14px',
      color: '#4a5568',
      width: '140px',
    };

    return (
      <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
        <div style={row}>
          <CheckboxButton
            aria-label="Unchecked"
            checked={unchecked}
            onChange={() => setUnchecked((v: boolean) => !v)}
          />
          <span style={label}>Unchecked</span>
        </div>
        <div style={row}>
          <CheckboxButton
            aria-label="Checked"
            checked={checked}
            onChange={() => setChecked((v: boolean) => !v)}
          />
          <span style={label}>Checked</span>
        </div>
        <div style={row}>
          <CheckboxButton
            aria-label="Indeterminate"
            checked={indeterminate}
            indeterminate
            onChange={() => setIndeterminate((v: boolean) => !v)}
          />
          <span style={label}>Indeterminate</span>
        </div>
        <div style={row}>
          <CheckboxButton
            aria-label="Disabled unchecked"
            checked={disabledUnchecked}
            disabled
            onChange={() => {}}
          />
          <span style={label}>Disabled unchecked</span>
        </div>
        <div style={row}>
          <CheckboxButton
            aria-label="Disabled checked"
            checked={disabledChecked}
            disabled
            onChange={() => {}}
          />
          <span style={label}>Disabled checked</span>
        </div>
      </div>
    );
  },
  play: async ({ canvasElement, step }) => {
    const wait = async (ms: number) =>
      new Promise<void>((resolve) => {
        setTimeout(resolve, ms);
      });
    const canvas = within(canvasElement);

    await step('tab to Unchecked and toggle on then off', async () => {
      await userEvent.tab();
      const cb = canvas.getByRole('checkbox', { name: /^unchecked$/i });
      await expect(cb).toHaveFocus();
      await wait(400);
      await userEvent.keyboard(' ');
      await expect(cb).toBeChecked();
      await wait(400);
      await userEvent.keyboard(' ');
      await expect(cb).not.toBeChecked();
    });

    await wait(400);

    await step('tab to Checked and toggle off then on', async () => {
      await userEvent.tab();
      const cb = canvas.getByRole('checkbox', { name: /^checked$/i });
      await expect(cb).toHaveFocus();
      await wait(400);
      await userEvent.keyboard(' ');
      await expect(cb).not.toBeChecked();
      await wait(400);
      await userEvent.keyboard(' ');
      await expect(cb).toBeChecked();
    });

    await wait(400);

    await step('tab to Indeterminate and toggle on then off', async () => {
      await userEvent.tab();
      const cb = canvas.getByRole('checkbox', { name: /^indeterminate$/i });
      await expect(cb).toHaveFocus();
      await wait(400);
      await userEvent.keyboard(' ');
      await expect(cb).toBeChecked();
      await wait(400);
      await userEvent.keyboard(' ');
      await expect(cb).not.toBeChecked();
    });

    await wait(400);

    await step('tab skips both disabled checkboxes — focus leaves the component', async () => {
      await userEvent.tab();
      const disabledUnchecked = canvas.getByRole('checkbox', { name: /disabled unchecked/i });
      const disabledChecked = canvas.getByRole('checkbox', { name: /disabled checked/i });
      await expect(disabledUnchecked).not.toHaveFocus();
      await expect(disabledChecked).not.toHaveFocus();
    });
  },
};

/** Base checkbox states in right-to-left layout. */
export const RTL: Story = {
  render: function Render() {
    const [unchecked, setUnchecked] = useState(false);
    const [checked, setChecked] = useState(true);
    const [indeterminate, setIndeterminate] = useState(false);
    return (
      <div style={{ display: 'flex', gap: '16px', alignItems: 'center', padding: '16px' }}>
        <CheckboxButton
          aria-label="Unchecked"
          checked={unchecked}
          onChange={() => setUnchecked((v) => !v)}
        />
        <CheckboxButton
          aria-label="Checked"
          checked={checked}
          onChange={() => setChecked((v) => !v)}
        />
        <CheckboxButton
          aria-label="Indeterminate"
          checked={indeterminate}
          indeterminate
          onChange={() => setIndeterminate((v) => !v)}
        />
        <CheckboxButton
          aria-label="Disabled unchecked"
          checked={false}
          disabled
          onChange={() => {}}
        />
        <CheckboxButton aria-label="Disabled checked" checked disabled onChange={() => {}} />
      </div>
    );
  },
  ...withVariantConfig(['rtl']),
};

/** Checkbox states at 400% zoom for accessibility testing. */
export const Zoom400: Story = {
  render: () => (
    <div style={{ display: 'flex', gap: '16px', alignItems: 'center', padding: '16px' }}>
      <CheckboxButton aria-label="Unchecked" checked={false} onChange={() => {}} />
      <CheckboxButton aria-label="Checked" checked onChange={() => {}} />
      <CheckboxButton
        aria-label="Indeterminate"
        checked={false}
        indeterminate
        onChange={() => {}}
      />
    </div>
  ),
  ...withVariantConfig(['400%']),
};
