import type { PickerOption } from 'vant/lib/picker/types'
import type { DateTimePickerColumnType } from './types'
import { formatDateStr } from '@daysnap/utils'

export type RequiredParams<T> = T extends (...args: infer P) => infer R
  ? (...args: { [K in keyof P]-?: NonNullable<P[K]> }) => R
  : never

export type Filter = (
  columnType: string,
  options: PickerOption[],
  values?: string[],
) => PickerOption[]
export type TimeFilter = RequiredParams<Filter>
export type Formatter = (type: string, option: PickerOption) => PickerOption

export function padZero(num: number | string, targetLength = 2): string {
  let str = num + ''

  while (str.length < targetLength) {
    str = '0' + str
  }

  return str
}

export function times<T>(n: number, iteratee: (index: number) => T) {
  if (n < 0) {
    return []
  }

  const result: T[] = Array(n)

  let index = -1
  while (++index < n) {
    result[index] = iteratee(index)
  }

  return result
}

export const genOptions = <T extends string>(
  min: number,
  max: number,
  type: T,
  formatter: Formatter,
  filter?: Filter | TimeFilter,
  values?: string[],
) => {
  const options = times(max - min + 1, (index) => {
    const value = padZero(min + index)
    return formatter(type, {
      text: value,
      value,
    })
  })
  return filter ? filter(type, options, values!) : options
}

export const getMonthEndDay = (year: number, month: number): number =>
  32 - new Date(year, month - 1, 32).getDate()

export const isSameValue = (newValue: unknown, oldValue: unknown) =>
  JSON.stringify(newValue) === JSON.stringify(oldValue)

export const clamp = (num: number, min: number, max: number): number =>
  Math.min(Math.max(num, min), max)

export const formatValueRange = (values: string[], columns: PickerOption[][]) =>
  values.map((value, index) => {
    const column = columns[index]
    if (column.length) {
      const minValue = +column[0].value!
      const maxValue = +column[column.length - 1].value!
      return padZero(clamp(+value, minValue, maxValue))
    }
    return value
  })

export const getDefaultValue = (types: DateTimePickerColumnType[], time?: string) => {
  const date = time && time !== '' ? formatDateStr(time) : new Date()

  const year = date.getFullYear() + ''
  const month = padZero(date.getMonth() + 1)
  const day = padZero(date.getDate())
  const hour = padZero(date.getHours())
  const minute = padZero(date.getMinutes())
  const second = padZero(date.getSeconds())

  return types.map((type) => {
    switch (type) {
      case 'year':
        return year
      case 'month':
        return month
      case 'day':
        return day
      case 'hour':
        return hour
      case 'minute':
        return minute
      case 'second':
        return second
      default:
        return []
    }
  }) as string[]
}
