import type { Meta, StoryObj } from '@storybook/nextjs-vite'

import { expect, fn } from 'storybook/test'

import { MaterialIcon, MaterialIconProps } from '../Icons/MaterialIcon'
import { IconButton } from './IconButton'
import { config } from './variants'

const meta: Meta<typeof IconButton> = {
  title: 'Core Components/IconButton',
  component: IconButton,
  argTypes: {
    onPress: {
      table: {
        disable: true,
      },
    },
    children: {
      table: {
        disable: true,
      },
    },
    variant: {
      control: 'select',
      options: Object.keys(config.variants.variant),
      table: {
        defaultValue: {
          summary: config.defaultVariants.variant,
        },
        type: {
          summary: Object.keys(config.variants.variant).join(' | '),
        },
      },
    },
    size: {
      control: 'select',
      options: Object.keys(config.variants.size),
      table: {
        defaultValue: {
          summary: config.defaultVariants.size,
        },
        type: {
          summary: Object.keys(config.variants.size).join(' | '),
        },
      },
      description:
        'The size of the `IconButton`. Please note that you control the size of the icon inside the button separately. Please check the examples below for recommended icon sizes for each button size.',
    },
    emphasis: {
      control: 'boolean',
      options: Object.keys(config.variants.emphasis),
      table: {
        defaultValue: {
          summary: config.defaultVariants.emphasis.toString(),
        },
        type: {
          summary: 'boolean',
        },
      },
    },
  },
}

const buttonAndIconSizesMap = Object.keys(config.variants.size).map<{
  size: keyof typeof config.variants.size
  iconSize: number
}>((key) => {
  const typedKey = key as keyof typeof config.variants.size
  switch (typedKey) {
    case 'sm':
      return {
        size: typedKey,
        iconSize: 16,
      }
    case 'md':
      return {
        size: typedKey,
        iconSize: 20,
      }
    case 'lg':
      return {
        size: typedKey,
        iconSize: 24,
      }
    case 'xl':
      return {
        size: typedKey,
        iconSize: 28,
      }
    default:
      return {
        size: typedKey,
        iconSize: 24,
      }
  }
})

const globalStoryPropsInverted = {
  backgrounds: { value: 'scandicPrimaryDark' },
}
export default meta

type Story = StoryObj<typeof IconButton>

function renderAllSizesFn(
  args: Story['args'],
  iconName: MaterialIconProps['icon'] = 'search'
) {
  return (
    <div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>
      {buttonAndIconSizesMap.map(({ size, iconSize }) => (
        <div
          style={{
            display: 'flex',
            flexDirection: 'column',
            alignItems: 'center',
            gap: '8px',
          }}
          key={size}
        >
          <IconButton {...args} size={size} key={size}>
            <MaterialIcon
              icon={iconName}
              size={iconSize}
              color="CurrentColor"
            />
          </IconButton>
          <span>{size}</span>
        </div>
      ))}
    </div>
  )
}

export const Default: Story = {
  args: {
    onPress: fn(),
    children: <MaterialIcon icon="search" size={24} color="CurrentColor" />,
  },
  play: async ({ canvas, userEvent, args }) => {
    await userEvent.click(canvas.getByRole('button'))
    expect(args.onPress).toHaveBeenCalledTimes(1)
  },
}

export const Examples: Story = {
  render: () => {
    return (
      <div style={{ display: 'grid', gap: '16px', justifyContent: 'center' }}>
        <div
          style={{
            padding: '16px',
            borderRadius: '8px',
            border: '1px solid #4D001B',
          }}
        >
          <h3 style={{ marginBottom: '8px' }}>Filled</h3>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
            {renderAllSizesFn({ ...Default.args, variant: 'Filled' })}
          </div>
        </div>
        <div
          style={{
            padding: '16px',
            borderRadius: '8px',
            border: '1px solid #4D001B',
          }}
        >
          <h3 style={{ marginBottom: '8px' }}>Filled with emphasis</h3>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
            {renderAllSizesFn(
              {
                ...Default.args,
                variant: 'Filled',
                emphasis: true,
              },
              'arrow_forward'
            )}
          </div>
        </div>
        <div
          style={{
            padding: '16px',
            borderRadius: '8px',
            border: '1px solid #4D001B',
          }}
        >
          <h3 style={{ marginBottom: '8px' }}>Outlined</h3>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
            {renderAllSizesFn(
              {
                ...Default.args,
                variant: 'Outlined',
              },
              'arrow_forward'
            )}
          </div>
        </div>
        <div
          style={{
            padding: '16px',
            borderRadius: '8px',
            border: '1px solid #4D001B',
          }}
        >
          <h3 style={{ marginBottom: '8px' }}>Elevated</h3>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
            {renderAllSizesFn(
              {
                ...Default.args,
                variant: 'Elevated',
              },
              'arrow_forward'
            )}
          </div>
        </div>
        <div
          style={{
            backgroundColor: '#4D001B',
            color: 'white',
            padding: '16px',
            borderRadius: '8px',
            border: '1px solid #4D001B',
          }}
        >
          <h3 style={{ marginBottom: '8px' }}>Faded</h3>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
            {renderAllSizesFn(
              {
                ...Default.args,
                variant: 'Faded',
              },
              'arrow_forward'
            )}
          </div>
        </div>
        <div
          style={{
            backgroundColor: '#4D001B',
            color: 'white',
            padding: '16px',
            borderRadius: '8px',
            border: '1px solid #4D001B',
          }}
        >
          <h3 style={{ marginBottom: '8px' }}>Muted</h3>
          <div
            style={{
              display: 'flex',
              flexWrap: 'wrap',
              gap: '8px',
            }}
          >
            {renderAllSizesFn(
              {
                ...Default.args,
                variant: 'Muted',
              },
              'arrow_forward'
            )}
          </div>
        </div>
        <div
          style={{
            padding: '16px',
            borderRadius: '8px',
            border: '1px solid #4D001B',
          }}
        >
          <h3 style={{ marginBottom: '8px' }}>Muted with emphasis</h3>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
            {renderAllSizesFn(
              {
                ...Default.args,
                variant: 'Muted',
                emphasis: true,
              },
              'arrow_forward'
            )}
          </div>
        </div>
      </div>
    )
  },
}
export const Filled: Story = {
  args: {
    ...Default.args,
    variant: 'Filled',
  },
  play: async ({ canvas, userEvent, args }) => {
    await userEvent.click(canvas.getByRole('button'))
    expect(args.onPress).toHaveBeenCalledTimes(1)
  },
}

export const FilledDisabled: Story = {
  args: {
    ...Filled.args,
    isDisabled: true,
  },
  play: async ({ canvas, userEvent, args }) => {
    await userEvent.click(canvas.getByRole('button'))
    expect(args.onPress).toHaveBeenCalledTimes(0)
  },
}

export const FilledOnDarkBackground: Story = {
  globals: globalStoryPropsInverted,
  args: {
    ...Filled.args,
  },
  play: async ({ canvas, userEvent, args }) => {
    await userEvent.click(canvas.getByRole('button'))
    expect(args.onPress).toHaveBeenCalledTimes(1)
  },
}

export const FilledWithEmphasis: Story = {
  args: {
    ...Filled.args,
    children: (
      <MaterialIcon icon="arrow_forward" size={24} color="CurrentColor" />
    ),
    emphasis: true,
  },
  play: async ({ canvas, userEvent, args }) => {
    await userEvent.click(canvas.getByRole('button'))
    expect(args.onPress).toHaveBeenCalledTimes(1)
  },
}

export const FilledWithEmphasisDisabled: Story = {
  args: {
    ...FilledWithEmphasis.args,
    isDisabled: true,
  },
  play: async ({ canvas, userEvent, args }) => {
    await userEvent.click(canvas.getByRole('button'))
    expect(args.onPress).toHaveBeenCalledTimes(0)
  },
}

export const Outlined: Story = {
  args: {
    ...Default.args,
    children: (
      <MaterialIcon icon="arrow_forward" size={24} color="CurrentColor" />
    ),
    variant: 'Outlined',
  },
  play: async ({ canvas, userEvent, args }) => {
    await userEvent.click(canvas.getByRole('button'))
    expect(args.onPress).toHaveBeenCalledTimes(1)
  },
}

export const OutlinedDisabled: Story = {
  args: {
    ...Outlined.args,
    isDisabled: true,
  },
  play: async ({ canvas, userEvent, args }) => {
    await userEvent.click(canvas.getByRole('button'))
    expect(args.onPress).toHaveBeenCalledTimes(0)
  },
}

export const Elevated: Story = {
  args: {
    ...Default.args,
    children: (
      <MaterialIcon icon="arrow_forward" size={24} color="CurrentColor" />
    ),
    variant: 'Elevated',
  },
  play: async ({ canvas, userEvent, args }) => {
    await userEvent.click(canvas.getByRole('button'))
    expect(args.onPress).toHaveBeenCalledTimes(1)
  },
}

export const ElevatedDisabled: Story = {
  args: {
    ...Elevated.args,
    isDisabled: true,
  },
  play: async ({ canvas, userEvent, args }) => {
    await userEvent.click(canvas.getByRole('button'))
    expect(args.onPress).toHaveBeenCalledTimes(0)
  },
}

export const Faded: Story = {
  globals: globalStoryPropsInverted,
  args: {
    ...Default.args,
    children: (
      <MaterialIcon icon="arrow_forward" size={24} color="CurrentColor" />
    ),
    variant: 'Faded',
  },
  play: async ({ canvas, userEvent, args }) => {
    await userEvent.click(canvas.getByRole('button'))
    expect(args.onPress).toHaveBeenCalledTimes(1)
  },
}

export const FadedDisabled: Story = {
  globals: globalStoryPropsInverted,
  args: {
    ...Faded.args,
    isDisabled: true,
  },
  play: async ({ canvas, userEvent, args }) => {
    await userEvent.click(canvas.getByRole('button'))
    expect(args.onPress).toHaveBeenCalledTimes(0)
  },
}

export const Muted: Story = {
  globals: globalStoryPropsInverted,
  args: {
    ...Default.args,
    children: (
      <MaterialIcon icon="arrow_forward" size={24} color="CurrentColor" />
    ),
    variant: 'Muted',
  },
  play: async ({ canvas, userEvent, args }) => {
    await userEvent.click(canvas.getByRole('button'))
    expect(args.onPress).toHaveBeenCalledTimes(1)
  },
}

export const MutedDisabled: Story = {
  globals: globalStoryPropsInverted,
  args: {
    ...Muted.args,
    isDisabled: true,
  },
  play: async ({ canvas, userEvent, args }) => {
    await userEvent.click(canvas.getByRole('button'))
    expect(args.onPress).toHaveBeenCalledTimes(0)
  },
}

export const MutedWithEmphasis: Story = {
  args: {
    ...Muted.args,
    emphasis: true,
  },
  play: async ({ canvas, userEvent, args }) => {
    await userEvent.click(canvas.getByRole('button'))
    expect(args.onPress).toHaveBeenCalledTimes(1)
  },
}

export const MutedWithEmphasisDisabled: Story = {
  args: {
    ...MutedWithEmphasis.args,
    isDisabled: true,
  },
  play: async ({ canvas, userEvent, args }) => {
    await userEvent.click(canvas.getByRole('button'))
    expect(args.onPress).toHaveBeenCalledTimes(0)
  },
}
