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

import { Calendar } from './calendar'
import { expect, userEvent, screen } from 'storybook/test'
import { useState } from 'react'

const meta = {
  title: 'Calendar',
  component: Calendar,
  tags: ['autodocs'],
  parameters: {
    layout: 'centered',
  },
  argTypes: {
    buttonVariant: {
      control: 'select',
      options: [
        undefined,
        'default',
        'secondary',
        'destructive',
        'outline',
        'ghost',
        'link',
        'outlineInvert',
        'extraGhost',
        'extraGhost2',
        'neutral',
      ],
    },
    showYearNavigation: {
      control: 'boolean',
    },
    mode: {
      control: 'select',
      options: ['single', 'multiple', 'range'],
    },
    showOutsideDays: {
      control: 'boolean',
      defaultValue: true,
    },
    captionLayout: {
      control: 'select',
      options: ['label', 'dropdown', 'dropdown-months', 'dropdown-years'],
      defaultValue: 'label',
    },
    formatters: {
      control: 'object',
    },
    components: {
      control: 'object',
    },
    disabled: {
      control: 'object',
    },
    fromYear: {
      control: 'number',
    },
    toYear: {
      control: 'number',
    },
  },
} satisfies Meta<typeof Calendar>
export default meta

type Story = StoryObj<typeof meta>

type DateRange = {
  from?: Date
  to?: Date
}

export const Default: Story = {
  args: {
    mode: 'single',
    showOutsideDays: true,
    captionLayout: 'label',
    formatters: {
      // used by this Calendar (and merged with the built-in formatMonthDropdown)
      formatMonthDropdown: (date: Date) => date.toLocaleString('en-US', { month: 'long' }), // "January", "February", ...

      // typical DayPicker formatter names you can override:
      formatWeekdayName: (date: Date) => date.toLocaleDateString('en-US', { weekday: 'short' }), // "Mon", "Tue", ...

      formatDay: (date: Date) => date.toLocaleDateString('en-US', { day: 'numeric' }), // "01"
    },
  },
  render: (args) => <Calendar {...args} data-testid="default-calendar" />,
  play: async () => {
    const calendar = screen.getByTestId('default-calendar')
    const dayButton = calendar.querySelector('button[aria-label*="13"]') as HTMLElement
    await userEvent.click(dayButton)
    expect(dayButton).toHaveAttribute('data-selected-single', 'true')
  },
}

export const Multiple: Story = {
  args: {
    mode: 'multiple',
  },
  render: (args) => <Calendar {...args} data-testid="default-calendar" />,
}

function RangeCalendarStory(args: any) {
  const [range, setRange] = useState<DateRange | undefined>(undefined)
  return (
    <Calendar
      mode="range"
      buttonVariant={args.buttonVariant}
      data-testid="default-calendar"
      selected={range?.from && range?.to ? { from: range.from, to: range.to } : undefined}
      onSelect={(value: { from?: Date; to?: Date } | undefined) => {
        if (value?.from == null) {
          setRange(undefined)
        } else {
          const newRange = { from: value.from, to: value.to ?? value.from }
          setRange(newRange)
        }
      }}
    />
  )
}
export const RangeWithAlternatingSelection: Story = {
  render: (args) => <RangeCalendarStory {...args} />,
}

export const WithDisabledRange: Story = {
  render: () => {
    return (
      <Calendar
        disabled={(date) => date > new Date() || date < new Date(new Date().setMonth(new Date().getMonth() - 3))}
        data-testid="default-calendar"
      />
    )
  },
  play: async () => {
    const calendar = screen.getByTestId('default-calendar')
    const today = new Date()
    const future = new Date(today)
    future.setDate(today.getDate() + 2)
    const futureDate = future.toLocaleDateString()
    // Use data-day attribute to find the specific button for the future date
    // This is more reliable than using aria-label with partial string matching
    const disabledDayButton = calendar.querySelector(`button[data-day="${futureDate}"]`) as HTMLElement

    // Previous approach had a bug: aria-label*="${dayNumber}" would match any date containing that number
    // For example, dayNumber=25 would incorrectly match "September 28th 2025" because it contains "25"
    // const dayNumber = future.getDate()
    // const disabledDayButton = calendar.querySelector(`button[aria-label*="${dayNumber}"]`) as HTMLElement
    await expect(disabledDayButton).toHaveAttribute('disabled')
    await userEvent.click(disabledDayButton, { pointerEventsCheck: 0 })
    await expect(disabledDayButton).toHaveAttribute('disabled') // still disabled after click
  },
}

export const WithDropdowns: Story = {
  render: () => {
    return <Calendar data-testid="default-calendar" captionLayout="dropdown" />
  },
}
