import { type Meta, type StoryObj } from '@storybook/react-vite'
import React, { useRef, useState } from 'react'
import moment from 'moment'

import { DocsTemplate } from '../../../.storybook'
import { toast } from '../Toast/Toast'
import TextInputComponent from './TextInput'
import {
  isEmptyOrWhitespace,
  isValidDateString,
  trimWhitespace,
} from '../DatePicker/DatePickerHelper'

const meta: Meta<typeof TextInputComponent> = {
  title: 'Components/FormComponents/TextInput',
  component: TextInputComponent,
  parameters: {
    design: {
      type: 'figma',
      url: 'https://www.figma.com/design/RvhKD82948FMQnh5MyCi0o/Web-Design-System?node-id=181-145&t=9R4mlUY42yEaNlLp-0',
    },
    docs: {
      page: () => (
        <DocsTemplate
          figmaLink='https://www.figma.com/design/RvhKD82948FMQnh5MyCi0o/Web-Design-System?node-id=181-145&t=9R4mlUY42yEaNlLp-0'
          description={
            <span>
              The <code>Text Input</code> component is a versatile form element
              used to collect various types of user input, such as strings,
              numbers, currency, or percentages. It allows users to enter
              textual or numeric data in a designated field. The{' '}
              <code>Text Input</code> component supports a wide range of input
              types, making it suitable for different data types and form
              scenarios.
            </span>
          }
          infoBullets={[
            <span key='first-bullet'>
              Implement the <code>Text Input</code> component in forms or
              settings sections where users need to enter textual or numeric
              data.
            </span>,
            <span key='second-bullet'>
              Indicate the expected data type or format for the input by
              providing clear labels or placeholder text within the Text Input
              field.
            </span>,
            <span key='third-bullet'>
              Make use of the <code>TextInput</code> component's various input
              types to ensure the correct data type is collected from users.
            </span>,
          ]}
        />
      ),
    },
  },
}

export default meta

type Story = StoryObj<typeof TextInputComponent>

const TextInput = (args: React.ComponentProps<typeof TextInputComponent>) => {
  const [value, setValue] = useState('')
  return (
    <div style={{ width: '300px' }}>
      <TextInputComponent
        {...args}
        value={value}
        callout={(_, val) => setValue(val.toString())}
        clearCallout={() => setValue('')}
      />
    </div>
  )
}

const Template: Story = {
  render: (args) => {
    return <TextInput {...args} />
  },
}

const DateInputStoryComponent = (
  args: React.ComponentProps<typeof TextInputComponent>,
) => {
  const [selectedDate, setSelectedDate] = useState<Date | undefined>(undefined)
  const [inputDate, setInputDate] = useState<string>('')
  const [isDateValid, setIsDateValid] = useState(true)
  const isEditingRef = useRef(false)
  const inputRef = useRef(null)

  // Always return formatted value unless editing
  const getFormattedDateValue = () => {
    if (isEditingRef.current) {
      return inputDate
    } else if (selectedDate) {
      return moment(selectedDate).format('MM/DD/YYYY')
    }
    return ''
  }

  return (
    <div style={{ width: '300px' }}>
      <TextInputComponent
        {...args}
        ref={inputRef}
        value={getFormattedDateValue()}
        hasError={!isDateValid}
        callout={(_, value) => {
          const stringValue = String(value)
          setInputDate(stringValue)
          if (isEmptyOrWhitespace(stringValue)) {
            setIsDateValid(true)
            setSelectedDate(undefined)
            isEditingRef.current = false
            return
          }
          const isValidDate = isValidDateString(stringValue)
          if (isValidDate) {
            setIsDateValid(true)
            const newDate = moment(
              trimWhitespace(stringValue),
              'MM/DD/YYYY',
            ).toDate()
            setSelectedDate(newDate)
            isEditingRef.current = false
            toast({
              type: 'info',
              message: `Date selected: ${moment(newDate).format('MM/DD/YYYY')}`,
            })
          } else {
            isEditingRef.current = true
            setIsDateValid(false)
            setSelectedDate(undefined)
          }
        }}
        clearCallout={() => {
          setInputDate('')
          setSelectedDate(undefined)
          setIsDateValid(true)
          isEditingRef.current = false
        }}
      />
    </div>
  )
}

const genericProps = {
  callout: (stateName: string | number | undefined, value: string | number) =>
    toast({
      type: 'info',
      message: `callout stateName: ${stateName}, value: ${value}`,
    }),
  debounce: 1000,
  value: '',
}

export const Basic: Story = {
  ...Template,
  args: {
    ...genericProps,
    id: 'text',
    type: 'text',
    labelText: 'Basic Text Input',
    stateName: 'basic_text_state',
  },
}

export const RequiredLabel: Story = {
  ...Template,
  args: {
    ...genericProps,
    id: 'text',
    type: 'text',
    labelText: 'Label With Tooltip',
    stateName: 'required_state',
    required: true,
  },
}

export const LabelTooltip: Story = {
  ...Template,
  args: {
    ...genericProps,
    id: 'text',
    type: 'text',
    labelText: 'Label With Tooltip',
    stateName: 'label_tooltip_state',
    labelTooltip: {
      tooltipContent: 'This is a tooltip.',
    },
  },
}

export const RightLabel: Story = {
  ...Template,
  args: {
    ...genericProps,
    id: 'text',
    type: 'text',
    labelText: 'Label With Tooltip',
    labelTooltip: {
      tooltipContent: 'This is a tooltip.',
    },
    stateName: 'right_label_state',
    rightLabel: 'Right Label',
  },
}

export const NumericTextInput: Story = {
  ...Template,
  args: {
    ...genericProps,
    id: 'number',
    type: 'number',
    labelText: 'Basic Number Input',
    stateName: 'basic_number_state',
  },
}

export const EmailInput: Story = {
  ...Template,
  args: {
    ...genericProps,
    id: 'email',
    type: 'email',
    labelText: 'Email Input',
    stateName: 'email_input_state',
  },
}

export const PasswordInput: Story = {
  ...Template,
  args: {
    ...genericProps,
    id: 'password',
    type: 'password',
    labelText: 'Password Input',
    stateName: 'password_input_state',
  },
}

export const CurrencyTextInput: Story = {
  ...Template,
  args: {
    ...genericProps,
    id: 'number',
    type: 'number',
    labelText: 'Currency Input',
    stateName: 'currency_input_state',
    numberFormat: {
      type: 'currency',
      currencySymbol: '$',
    },
  },
}

export const PercentageTextInput: Story = {
  ...Template,
  args: {
    ...genericProps,
    id: 'number',
    type: 'number',
    labelText: 'Percentage Input',
    stateName: 'percentage_input_state',
    numberFormat: {
      type: 'percentage',
    },
    inputLabel: '%',
  },
}

export const Textarea: Story = {
  ...Template,
  args: {
    ...genericProps,
    id: 'textarea',
    type: 'textarea',
    labelText: 'Textarea',
    stateName: 'textarea_input_state',
  },
}

export const TextareaAutoresize: Story = {
  ...Template,
  args: {
    ...genericProps,
    id: 'textarea',
    type: 'textarea',
    labelText: 'Textarea',
    autoResize: true,
    stateName: 'textarea_input_state',
  },
}

export const ReturnCallout: Story = {
  ...Template,
  args: {
    ...genericProps,
    id: 'text',
    type: 'text',
    labelText: 'Basic Text Input',
    stateName: 'basic_text_state',
    onReturnCallout: () => {
      toast({
        type: 'info',
        message: 'Return / Enter key pressed!',
      })
    },
  },
}

export const SymbologyPrefixStripping: Story = {
  ...Template,
  args: {
    ...genericProps,
    id: 'symbology',
    type: 'text',
    labelText: 'Scan input (symbology prefix stripping)',
    stateName: 'symbology_state',
    placeholder: 'Try pasting ~ABarcode123 or ]C1Barcode123',
    shouldStripSymbologyPrefix: true,
  },
}

export const DateInput: Story = {
  render: (args) => <DateInputStoryComponent {...args} />,
  args: {
    id: 'date',
    type: 'date-single',
    labelText: 'Date Input',
    stateName: 'date_input_state',
    placeholder: 'MM/DD/YYYY',
    clear: true,
  },
}
