import { Input } from './input.js'
import { Select } from './select.js'
import { Copy } from './copy.js'
import { Errors, Err } from './form-elements/shared.js'
import styled from 'styled-components'
import { inputPattern, noop } from '@navinc/utils'
import { ChangeEventHandler } from 'react'
import { InferComponentProps } from './types.js'

type Field = 'day' | 'month' | 'year'
type Value = { day?: string | number; month?: string | number; year?: string | number }

type DatePickerProps = InferComponentProps<typeof DatePickerWrapper> & {
  errors?: string[]
  fieldsToShow?: Field[]
  hasSpaceForErrors?: boolean
  isInvalid?: boolean
  label?: string
  name?: string
  onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void
  onChange?: (e: { target: { value: Value } }) => void
  value?: Value
}

export const DatePickerWrapper = styled.div`
  div > ${Copy} {
    text-align: left;
  }
`

const StyledCopy = styled(Copy)`
  margin-bottom: 8px;
`

export const DatePickerInputWrapper = styled.div<{ fieldsToShow?: Field[] }>`
  display: grid;
  grid-gap: 12px;
  grid-template-columns: ${({ fieldsToShow = [] }) => {
    if (fieldsToShow.length === 3) {
      return '5fr 2fr 2.5fr'
    } else if (fieldsToShow.length === 2) {
      return '1fr 1fr'
    } else {
      return '1fr'
    }
  }};

  ${Errors} {
    display: none;
  }
`

const months = [
  'January',
  'February',
  'March',
  'April',
  'May',
  'June',
  'July',
  'August',
  'September',
  'October',
  'November',
  'December',
]

export function isDateValid(dateIn?: { year?: string | number; month?: string | number; day?: string | number }) {
  if (!dateIn || !dateIn.year || !dateIn.month || !dateIn.day) return false
  const { year, month, day } = dateIn
  if (year.toString().length !== 4) {
    return false
  }
  const yearNumber = Number(year)
  const monthNumber = Number(month)
  const dayNumber = Number(day)

  const date = new Date(yearNumber, monthNumber - 1, dayNumber)
  return date.getFullYear() === yearNumber && date.getMonth() + 1 === monthNumber && date.getDate() === dayNumber
}

const _DatePicker = ({
  errors = [],
  fieldsToShow = ['day', 'month', 'year'],
  hasSpaceForErrors,
  isInvalid,
  label,
  name,
  onBlur,
  onChange = noop,
  value = {},
  ...rest
}: DatePickerProps) => {
  const onChangeWrapper = (key: Field, val: string | number) => {
    onChange({
      target: {
        value: {
          ...value,
          [key]: val,
        },
      },
    })
  }

  const handleMonthChange: ChangeEventHandler<HTMLSelectElement> = (event) => {
    const monthNumber = months.indexOf(event.target.value) + 1
    const val = monthNumber < 10 ? `0${monthNumber}` : `${monthNumber}`

    onChangeWrapper('month', val)
  }

  const handleDayChange: ChangeEventHandler<HTMLInputElement> = (event) => {
    onChangeWrapper('day', inputPattern(event.target, '99'))
  }

  const handleYearChange: ChangeEventHandler<HTMLInputElement> = (event) => {
    onChangeWrapper('year', inputPattern(event.target, '9999'))
  }

  const isInvalidOrHasErrors = isInvalid || !!errors.length

  return (
    <DatePickerWrapper {...rest}>
      {label && (
        <div>
          <StyledCopy light size="sm">
            {label}
          </StyledCopy>
        </div>
      )}
      <DatePickerInputWrapper fieldsToShow={fieldsToShow}>
        {fieldsToShow.includes('month') && (
          <Select
            data-testid="date_picker:month"
            isInvalid={isInvalidOrHasErrors}
            label="Month"
            name={name}
            options={months}
            onBlur={onBlur}
            onChange={handleMonthChange}
            value={months[parseInt(value.month as string, 10) - 1] ?? 0}
          />
        )}
        {fieldsToShow.includes('day') && (
          <Input
            data-testid="date_picker:day"
            isInvalid={isInvalidOrHasErrors}
            label="Day"
            name="day"
            onBlur={onBlur}
            onChange={handleDayChange}
            // chrome 73 onWheel events became passive
            onWheel={(e) => {
              e.preventDefault()
              ;(e.target as HTMLInputElement).blur()
            }}
            type="number"
            value={value.day || ''}
          />
        )}
        {fieldsToShow.includes('year') && (
          <Input
            data-testid="date_picker:year"
            isInvalid={isInvalidOrHasErrors}
            label="Year"
            name="year"
            onBlur={onBlur}
            onChange={handleYearChange}
            // chrome 73 onWheel events became passive
            onWheel={(e) => {
              e.preventDefault()
              ;(e.target as HTMLInputElement).blur()
            }}
            type="number"
            value={value.year || ''}
          />
        )}
      </DatePickerInputWrapper>
      <Errors hasSpaceForErrors={hasSpaceForErrors} data-testid="date_picker:errors">
        {!!errors.length && errors.map((err, i) => <Err key={`err-${i}`}>{err}</Err>)}
      </Errors>
    </DatePickerWrapper>
  )
}

export const DatePicker = styled(_DatePicker)``
