/**
 * Copyright (c) 2022 - present TinyVue Authors.
 * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
 *
 * Use of this source code is governed by an MIT-style license.
 *
 * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
 * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
 * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
 *
 */

import { DATEPICKER, toDate1 } from '@opentiny/utils'
import { arrayFindIndex, coerceTruthyValueToArray, arrayFind } from '../date-table'

export const getIsDefault =
  ({ props }) =>
  (year) => {
    const { defaultValue } = props

    return Array.isArray(defaultValue)
      ? defaultValue.some((v) => v && v.getFullYear() === year)
      : defaultValue && defaultValue.getFullYear() === year
  }

export const getIsDisabled =
  ({ props }) =>
  (year) => {
    const MONTHS = Array.from({length: 12}, (_, i) => i);

    return typeof props.disabledDate === 'function'
      ? MONTHS.every(month => 
          props.disabledDate(new Date(year, month, 1))
        )
      : false
  }

export const getIsCurrent =
  ({ props }) =>
  (year) => {
    const execDate = typeof props.value === 'object' ? props.value : toDate1(props.value)

    return arrayFindIndex(coerceTruthyValueToArray(execDate), (date) => date.getFullYear() === year) >= 0
  }

export const clearDate = (date) => {
  return new Date(date.getFullYear(), date.getMonth())
}

export const getMonthTimestamp = (time) => {
  if (typeof time === 'number' || typeof time === 'string') {
    return clearDate(new Date(time)).getTime()
  }

  if (time instanceof Date) {
    return clearDate(time).getTime()
  }

  return NaN
}

export const getRows =
  ({ props, state, vm }) =>
  () => {
    const { tableRows } = state
    const { minDate, maxDate, disabledDate, startYear, selectionMode } = props
    const selectedDate = []
    const now = new Date().getFullYear()

    for (let i = 0; i < 3; i++) {
      const row = tableRows[i]

      for (let j = 0; j < 4; j++) {
        let cell = row[j]

        if (!cell) {
          cell = {
            type: DATEPICKER.Normal,
            row: i,
            column: j,
            inRange: false,
            start: false,
            end: false
          }
        }

        const year = startYear + (cell.row * 4 + cell.column)
        const isToday = year === now

        cell.text = year
        cell.type = isToday ? DATEPICKER.Today : DATEPICKER.Normal
        if (props.selectionMode.startsWith('year')) {
          cell.disabled = typeof disabledDate === 'function' && disabledDate(new Date(year, 0, 1, 0))
        }

        if (selectionMode === DATEPICKER.YearRange) {
          const minYear = typeof minDate === 'object' && minDate ? minDate.getFullYear() : minDate
          const maxYear = typeof maxDate === 'object' && maxDate ? maxDate.getFullYear() : maxDate
          cell.start = minYear === year
          cell.end = maxYear === year
          cell.inRange = (year > minYear && year < maxYear) || [minYear, maxYear].includes(year)
          cell.selected = arrayFind(
            selectedDate,
            (item) => (typeof item === 'object' ? item.getFullYear() : item) === year
          )
        }

        vm.$set(row, j, cell)
      }
    }

    return tableRows
  }

export const markRange =
  ({ props, state }) =>
  (min, max) => {
    const rows = state.rows
    const [minDate, maxDate] = [min, max].sort((a, b) => (a && a < b ? -1 : 1))
    const minYear = typeof minDate === 'object' && minDate ? minDate.getFullYear() : minDate
    const maxYear = typeof maxDate === 'object' && maxDate ? maxDate.getFullYear() : maxDate

    if (props.selectionMode === DATEPICKER.YearRange) {
      for (let i = 0, len = rows.length; i < len; i++) {
        const row = rows[i]

        for (let j = 0, l = row.length; j < l; j++) {
          const cell = row[j]
          const year = cell.text
          cell.start = minYear && minYear === year
          cell.end = maxYear && maxYear === year
          cell.inRange = (year > minYear && year < maxYear) || cell.start || cell.end
          cell.selected = cell.inRange
        }
      }
    }
  }

export const watchDate =
  ({ api, props }) =>
  (value, oldvalue) => {
    if (value !== oldvalue) {
      api.markRange(props.minDate, props.maxDate)
    }
  }

export const handleYearTableClick =
  ({ emit, props }) =>
  (event) => {
    const target = event.target
    const { selectionMode, readonly } = props
    if (readonly) {
      return
    }

    if (target.tagName === 'A') {
      if (target.hasAttribute('aria-disabled')) {
        return
      }

      const year = Number(target.textContent || target.innerText)

      if (selectionMode === DATEPICKER.Years) {
        const years = Array.isArray(props.value) ? props.value.map((v) => v.getFullYear()) : []

        const index = years.indexOf(year)

        if (index === -1) {
          years.push(year)
        } else {
          years.splice(index, 1)
        }

        emit('pick', years.slice())
      } else if (selectionMode === DATEPICKER.YearRange) {
        let { minDate, maxDate } = props

        if (props.rangeState.selecting) {
          props.rangeState.selecting = false

          if (year < minDate) {
            maxDate = minDate
            minDate = year
          } else {
            maxDate = year
          }
        } else {
          props.rangeState.selecting = true
          minDate = year
          maxDate = null
        }

        emit('pick', { minDate, maxDate })
      } else {
        emit('pick', year)
      }
    }
  }

const getTarget = (evt) => {
  let target = evt.target
  const tagName = target.tagName

  if (tagName === 'A') {
    target = target.parentNode.parentNode
  }

  if (tagName === 'DIV') {
    target = target.parentNode
  }

  if (tagName !== 'TD') {
    return
  }

  return target
}

export const handleMouseMove =
  ({ emit, props, state }) =>
  (event) => {
    const { selectionMode, startYear, rangeState, minDate, maxDate } = props

    if (selectionMode !== DATEPICKER.YearRange || !rangeState.selecting) {
      return
    }

    const target = getTarget(event)

    if (!target) {
      return
    }

    const row = target.parentNode.rowIndex
    const column = target.cellIndex

    if (state.rows[row][column].disabled || minDate === maxDate) {
      return
    }

    if (row !== state.lastRow || column !== state.lastColumn) {
      state.lastColumn = column
      state.lastRow = row

      const year = startYear + row * 4 + column

      emit('changerange', {
        minDate,
        maxDate,
        rangeState: {
          selecting: true,
          endDate: year
        }
      })
    }
  }