import Handsontable from 'handsontable'
import { datetimeValidator } from '../validations/hot-custom-validators'

/**
 * Cell types for the date/time/datetime columns after the HOT 17 migration.
 *
 * All three DISPLAY the raw stored ISO string verbatim — `YYYY-MM-DD`,
 * `HH:mm:ss`, `YYYY-MM-DD HH:mm:ss` — via an identity `valueFormatter`, so the
 * cell text is stable and locale-independent. The native picker editors still
 * follow the OS regional format while open; only the painted cell is ISO.
 * The stored/submitted value is unchanged.
 *
 * `intl-date` and `intl-time` are HOT built-ins; we re-register them by spreading
 * the built-in definition (keeping its native picker editor + ISO validator) and
 * swapping only the `valueFormatter` for the identity one. `intl-datetime` has no
 * built-in — it pairs a native `datetime-local` picker with the identity
 * formatter. valueFormatter is applied render-only (tableView), so copy/paste and
 * the stored value are untouched.
 */

/** Identity formatter — display the stored ISO string as-is (no localization). */
const isoPassthrough = (value: any): any => value

const SPACE_ISO = /^(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}(?::\d{2})?)$/

const BaseTextEditor = Handsontable.editors.getEditor('text') as any
const baseTextRenderer = Handsontable.renderers.getRenderer('text')

class IntlDatetimeEditor extends BaseTextEditor {
  createElements() {
    super.createElements('input')
    this.TEXTAREA.setAttribute('type', 'datetime-local')
    this.TEXTAREA.setAttribute('step', '1') // allow seconds
  }

  // Stored `YYYY-MM-DD HH:mm:ss` → native input `YYYY-MM-DDTHH:mm:ss`.
  setValue(value: any) {
    const match = typeof value === 'string' ? value.match(SPACE_ISO) : null
    super.setValue(match ? `${match[1]}T${match[2]}` : value)
  }

  // Native input `YYYY-MM-DDTHH:mm[:ss]` → stored `YYYY-MM-DD HH:mm:ss`.
  getValue() {
    const raw: string = super.getValue()
    if (typeof raw !== 'string' || raw.indexOf('T') === -1) return raw
    const [date, time] = raw.split('T')
    const withSeconds = time.length === 5 ? `${time}:00` : time // pad HH:mm
    return `${date} ${withSeconds}`
  }

  open() {
    super.open()
    try {
      this.TEXTAREA.showPicker()
    } catch {
      /* showPicker requires a user gesture; ignore when called programmatically */
    }
  }

  // The base text editor's focus() calls select() + setSelectionRange to place
  // the caret, but a native `datetime-local` input does not support text
  // selection and throws `InvalidStateError`. Just focus the input.
  focus() {
    this.TEXTAREA.focus()
  }
}

/**
 * Re-registers a built-in HOT cell type (`intl-date` / `intl-time`) with only its
 * `valueFormatter` swapped for the ISO passthrough — the native picker editor and
 * ISO validator are reused from the built-in definition. Idempotent: a second
 * call reads back our already-overridden type, which still carries the original
 * editor/validator.
 */
const overrideWithPassthrough = (type: string) => {
  const builtin = Handsontable.cellTypes.getCellType(type) as any
  Handsontable.cellTypes.registerCellType(type, {
    ...builtin,
    valueFormatter: isoPassthrough
  })
}

/**
 * Registers the Intl date/time/datetime cell types. Idempotent — safe to call
 * per DcValidator construction. All three display the stored ISO value verbatim.
 */
export const registerIntlCellTypes = () => {
  overrideWithPassthrough('intl-date')
  overrideWithPassthrough('intl-time')

  Handsontable.cellTypes.registerCellType('intl-datetime', {
    // IntlDatetimeEditor extends the (loosely-typed) text editor returned by
    // getEditor('text'); cast to satisfy registerCellType's editor signature.
    editor: IntlDatetimeEditor as any,
    renderer: baseTextRenderer,
    validator: datetimeValidator,
    valueFormatter: isoPassthrough
  } as any)
}
