/* @aztlan/generator-front 1.1.4 */
import * as React from 'react'
import {
  useState, useInsertionEffect, useCallback,
} from 'react'

import * as PropTypes from 'prop-types'
import { InferProps } from 'prop-types'
import { withWrapper } from '@aztlan/ui'
import { useController } from 'react-hook-form'
import styleNames from '@aztlan/bem'
import { mergeIntervals } from './utils/index.js'

import {
  Item, AddItemForm,
} from './common/index.js'

const baseClassName = styleNames.base
const componentClassName = 'opening-hours-input'

// A varied sample of weekly opening times, can work overnight
// The first number if the opening hour in the week (out of 168)
// and the second number is the closing hour in the week (out of 168)
/**
 * description
 * @param {InferProps<typeof OpeningHoursInput.propTypes>} props -
 * @returns {React.ReactElement} - Rendered OpeningHoursInput
 */
function OpeningHoursInput({
  id,
  className: userClassName,
  style,
  format = 24,
  name,
  registerProps,
  subFormSuffix = 'addOpeningHours',
  nestedSpanContentDesktop,
  nestedSpanLabelDesktop,
}: // ...otherProps

InferProps<typeof OpeningHoursInput.propTypes>): React.ReactElement {
  useInsertionEffect(
    () => {
    // @ts-ignore
      import('./styles.scss')
    }, [],
  )

  const { field } = useController({
    name,
    ...registerProps,
  })

  const {
    value, onChange,
  } = field

  const getRemoveOpeningHours = useCallback(
    (index) => () => {
      onChange(value.filter((
        _, i,
      ) => i !== index))
    },
    [
      value,
      onChange,
    ],
  )

  const addOpeningHours = useCallback(
    (tuple) => {
      const newValue = [
        ...(value || []),
        tuple,
      ]
      const mergedIntervals = mergeIntervals(newValue)
      onChange(mergedIntervals)
    },
    [
      value,
      onChange,
    ],
  )

  const [
    displayOpeningHoursForm,
    setDisplayOpeningHoursForm,
  ] = useState(false)

  const openOpeningHoursForm = useCallback(
    () => setDisplayOpeningHoursForm(true),
    [],
  )

  const closeOpeningHoursForm = useCallback(
    () => setDisplayOpeningHoursForm(false),
    [],
  )

  const subFormName = `_${name}.${subFormSuffix}`

  return (
    <div
      id={id}
      className={[
        baseClassName,
        componentClassName,
        userClassName,
        'grid container',
      ]
        .filter((e) => e)
        .join(' ')}
      style={style}
      // {...otherProps}
    >
      {value?.map((
        e, i,
      ) => {
        const [
          start,
          end,
        ] = e
        return (
          <Item
            key={start}
            start={start}
            end={end}
            format={format}
            remove={getRemoveOpeningHours(i)}
          />
        )
      })}
      {displayOpeningHoursForm && (
        <AddItemForm
          close={closeOpeningHoursForm}
          addOpeningHours={addOpeningHours}
          name={subFormName}
          spanContentDesktop={nestedSpanContentDesktop}
          spanLabelDesktop={nestedSpanLabelDesktop}
        />
      )}
      {!displayOpeningHoursForm && (
        <button
          onClick={openOpeningHoursForm}
          type="button"
        >
          Add opening hours
        </button>
      )}
    </div>
  )
}

OpeningHoursInput.propTypes = {
  /** The HTML id for this element */
  id:PropTypes.string,

  /** The HTML class names for this element */
  className:PropTypes.string,

  /** The React-written, css properties for this element. */
  style:PropTypes.objectOf(PropTypes.string),

  /** The format of the opening hours. */
  format:PropTypes.oneOf([
    12,
    24,
  ]),

  /** The name of the input */
  name:PropTypes.string,

  /** An object of shape [`RegisterOptions`](https://www.react-hook-form.com/ts/#RegisterOptions) that will be passed to the registration func ion of the input */
  registerProps:PropTypes.object,

  /** The suffix of the subform */
  subFormSuffix:PropTypes.string,

  /** The spanContentDesktop */
  nestedSpanContentDesktop:PropTypes.number,

  /** The spanLabelDesktop */
  nestedSpanLabelDesktop:PropTypes.number,
}

export default withWrapper(
  OpeningHoursInput, { nested: true },
)
