import { html, nothing, PropertyValues } from 'lit'
import { customElement, property, state } from 'lit/decorators.js'
import { Ref, createRef, ref } from 'lit/directives/ref.js'
import { ifDefined } from 'lit/directives/if-defined.js'
import { classMap } from 'lit/directives/class-map.js'
import { PktInputElement } from '@/base-elements/input-element'
import { slotContent } from '@/directives/slot-content'
import { ElementProps } from '@/types/typeUtils'
import strings from '@/translations/no.json'
import { isValidTimeString, timeToMinutes } from 'shared-utils/timepicker/time-utils'
import { getMinuteStep, getHourOptions, getMinuteOptions } from 'shared-utils/timepicker/options'
import { stepTime } from 'shared-utils/timepicker/stepper'
import '@/components/icon'
import '@/components/input-wrapper'

type Props = ElementProps<PktTimepicker, 'value' | 'hidePicker' | 'stepArrows'>

export interface IPktTimepicker {
  value?: string
  min?: string
  max?: string
  step?: number
  name?: string
  id?: string
  disabled?: boolean
  required?: boolean
  hidePicker?: boolean
  stepArrows?: boolean
  fullwidth?: boolean
  label?: string | null
  helptext?: string
  helptextDropdown?: string
  helptextDropdownButton?: string | null
  hasError?: boolean
  errorMessage?: string
  requiredTag?: boolean
  requiredText?: string
  optionalTag?: boolean
  optionalText?: string
  tagText?: string | null
  inline?: boolean
}

export class PktTimepicker extends PktInputElement<Props> {
  hiddenInputRef: Ref<HTMLInputElement> = createRef()
  hoursInputRef: Ref<HTMLInputElement> = createRef()
  minutesInputRef: Ref<HTMLInputElement> = createRef()
  buttonRef: Ref<HTMLButtonElement> = createRef()

  /**
   * Exposes hiddenInputRef as inputRef so the base class validate() method
   * triggers our manageValidity override automatically after every onChange call.
   * The hidden input itself is never used for reporting — see manageValidity below.
   */
  get inputRef() {
    return this.hiddenInputRef
  }

  /**
   * Overrides the base class manageValidity to solve a focusability problem:
   * the browser requires the third argument to setValidity (the "anchor") to be
   * a visible, focusable element — it focuses that element when navigating to an
   * invalid field. Our hidden input[type=time] cannot receive focus, so passing it
   * as the anchor would silently fail with "form control is not focusable".
   */
  protected override manageValidity(
    _input?: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement,
  ): void {
    const anchor = this.hoursInputRef.value
    if (!anchor) return

    if (this.required && !this.value) {
      this.internals.setValidity({ valueMissing: true }, strings.forms.messages.required, anchor)
      this._setAriaInvalid(true)
      return
    }

    if (!this.value) {
      this.internals.setValidity({})
      this._setAriaInvalid(false)
      return
    }

    const totalMinutes = timeToMinutes(this.value)
    const minuteStep = getMinuteStep(this.step)

    if (this.min && totalMinutes < timeToMinutes(String(this.min))) {
      this.internals.setValidity(
        { rangeUnderflow: true },
        strings.forms.messages.rangeUnderflowMin.replace('{min}', String(this.min)),
        anchor,
      )
      this._setAriaInvalid(true)
      return
    }

    if (this.max && totalMinutes > timeToMinutes(String(this.max))) {
      this.internals.setValidity(
        { rangeOverflow: true },
        strings.forms.messages.rangeOverflowMax.replace('{max}', String(this.max)),
        anchor,
      )
      this._setAriaInvalid(true)
      return
    }

    if (this.step && totalMinutes % minuteStep !== 0) {
      const stepMessage =
        minuteStep === 60
          ? strings.forms.messages.timeStepMismatchHour
          : minuteStep === 30
            ? strings.forms.messages.timeStepMismatchHalfHour
            : strings.forms.messages.timeStepMismatch.replace(
                '{step}',
                `${minuteStep}, ${minuteStep * 2}, ${minuteStep * 3}`,
              )
      this.internals.setValidity({ stepMismatch: true }, stepMessage, anchor)
      this._setAriaInvalid(true)
      return
    }

    this.internals.setValidity({})
    this._setAriaInvalid(false)
  }

  @property({ type: String, reflect: true }) value: string = ''

  @property({ type: Boolean, reflect: true, attribute: 'hide-picker' })
  hidePicker: boolean = false

  @property({ type: Boolean, reflect: true, attribute: 'step-arrows' })
  stepArrows: boolean = false

  @state() private _hours: string = ''
  @state() private _minutes: string = ''
  @state() private _isOpen: boolean = false

  private _hoursDigitCount: number = 0
  private _hoursFirstDigit: number = -1
  private _minutesDigitCount: number = 0
  private _minutesFirstDigit: number = -1
  private _hasFocus: boolean = false

  private _setAriaInvalid(invalid: boolean): void {
    if (!this.touched && invalid) return
    const hours = this.hoursInputRef.value
    const minutes = this.minutesInputRef.value
    if (invalid) {
      hours?.setAttribute('aria-invalid', 'true')
      minutes?.setAttribute('aria-invalid', 'true')
    } else {
      hours?.removeAttribute('aria-invalid')
      minutes?.removeAttribute('aria-invalid')
    }
  }

  private _outsideClickHandler = (e: MouseEvent) => {
    if (!this.contains(e.target as Node)) {
      this._closePopup()
    }
  }

  private _handleComponentFocusIn = (): void => {
    if (!this._hasFocus) {
      this._hasFocus = true
      this.onFocus()
    }
  }

  private _handleComponentFocusOut = (e: FocusEvent): void => {
    if (!this.contains(e.relatedTarget as Node)) {
      this._hasFocus = false
      this.onBlur()
    }
  }

  connectedCallback(): void {
    super.connectedCallback()
    this.addEventListener('focusin', this._handleComponentFocusIn)
    this.addEventListener('focusout', this._handleComponentFocusOut)
    document.addEventListener('click', this._outsideClickHandler)
  }

  disconnectedCallback(): void {
    super.disconnectedCallback()
    this.removeEventListener('focusin', this._handleComponentFocusIn)
    this.removeEventListener('focusout', this._handleComponentFocusOut)
    document.removeEventListener('click', this._outsideClickHandler)
  }

  protected override willUpdate(changedProperties: PropertyValues): void {
    super.willUpdate(changedProperties)
    if (changedProperties.has('value')) {
      this._syncDisplayFromValue()
    }
  }

  protected updated(changedProperties: PropertyValues): void {
    super.updated(changedProperties)
    this.classList.toggle('pkt-timepicker--stepper', this.stepArrows)
    this.classList.toggle('pkt-timepicker--fullwidth', this.fullwidth)
    if (changedProperties.has('step') && this.step !== null && !this._isValidStep(this.step)) {
      // eslint-disable-next-line no-console
      console.warn(
        `pkt-timepicker: step="${this.step}" er ikke en gyldig verdi. Step må være et multiplum av 60 (hele minutter) eller nøyaktig 3600 (hel time).`,
      )
    }
  }

  protected formResetCallback(): void {
    super.formResetCallback()
    this._hours = ''
    this._minutes = ''
    this._isOpen = false
  }

  private _isValidStep(s: number): boolean {
    return s === 3600 || (s < 3600 && 3600 % s === 0 && s % 60 === 0)
  }

  private _syncDisplayFromValue(): void {
    const parsed = isValidTimeString(this.value) ? this.value.split(':') : null
    if (parsed) {
      this._hours = parsed[0]
      this._minutes = parsed[1]
    } else {
      this._hours = ''
      this._minutes = ''
    }
  }

  private _syncValueFromDisplay(): void {
    if (this._hours !== '' && this._minutes !== '') {
      const newValue = `${this._hours}:${this._minutes}`
      if (newValue !== this.value) {
        this.value = newValue
        this.onChange(newValue)
      }
    } else if (this.value !== '') {
      this.value = ''
      this.onChange('')
    }
  }

  private get _minuteStep(): number {
    return getMinuteStep(this.step)
  }

  private get _hourOptions(): number[] {
    return getHourOptions(this.min, this.max)
  }

  private get _minuteOptions(): number[] {
    return getMinuteOptions(this.step)
  }

  private _openPopup(): void {
    this._isOpen = true
    this.updateComplete.then(() => {
      this._scrollToSelected()
      this._focusSelectedOrFirst('hour')
    })
  }

  private _closePopup(): void {
    this._isOpen = false
    this._syncValueFromDisplay()
  }

  private _togglePopup(): void {
    this._isOpen ? this._closePopup() : this._openPopup()
  }

  private _scrollToSelected(): void {
    const popup = this.querySelector('.pkt-timepicker-popup')
    if (!popup) return
    popup.querySelectorAll('.pkt-timepicker-popup__col').forEach((col) => {
      const selected = col.querySelector('.pkt-timepicker-popup__option--selected')
      if (selected) {
        selected.scrollIntoView({ block: 'center' })
      }
    })
  }

  private _focusSelectedOrFirst(type: 'hour' | 'minute'): void {
    const popup = this.querySelector('.pkt-timepicker-popup')
    if (!popup) return
    const cols = popup.querySelectorAll('.pkt-timepicker-popup__col')
    const col = type === 'hour' ? cols[0] : cols[1]
    if (!col) return
    const selected = col.querySelector(
      '.pkt-timepicker-popup__option--selected',
    ) as HTMLElement | null
    const first = col.querySelector('.pkt-timepicker-popup__option') as HTMLElement | null
    ;(selected || first)?.focus()
  }

  private _handleHoursKeydown = (e: KeyboardEvent): void => {
    const input = e.target as HTMLInputElement
    switch (e.key) {
      case 'ArrowUp': {
        e.preventDefault()
        const h = this._hours !== '' ? parseInt(this._hours, 10) : 0
        this._hours = String((h + 1) % 24).padStart(2, '0')
        this._syncValueFromDisplay()
        this.onInput()
        break
      }
      case 'ArrowDown': {
        e.preventDefault()
        const h = this._hours !== '' ? parseInt(this._hours, 10) : 0
        this._hours = String((h - 1 + 24) % 24).padStart(2, '0')
        this._syncValueFromDisplay()
        this.onInput()
        break
      }
      case 'ArrowRight':
        e.preventDefault()
        this.minutesInputRef.value?.focus()
        break
      case 'Backspace':
      case 'Delete':
        this._hoursDigitCount = 0
        this._hoursFirstDigit = -1
        break
      case 'Tab':
        break
      case 'Enter': {
        e.preventDefault()
        const form = this.internals.form as HTMLFormElement
        if (form) form.requestSubmit()
        else input.blur()
        break
      }
      default:
        if (/^\d$/.test(e.key)) {
          e.preventDefault()
          const digit = parseInt(e.key, 10)
          if (this._hoursDigitCount === 0) {
            this._hoursFirstDigit = digit
            this._hours = String(digit).padStart(2, '0')
            this._hoursDigitCount = 1
            this.onInput()
            if (digit >= 3) {
              this._hoursFirstDigit = -1
              this._hoursDigitCount = 0
              this._syncValueFromDisplay()
              this.minutesInputRef.value?.focus()
            }
          } else {
            const combined = this._hoursFirstDigit * 10 + digit
            this._hours =
              combined <= 23 ? String(combined).padStart(2, '0') : String(digit).padStart(2, '0')
            this._hoursFirstDigit = -1
            this._hoursDigitCount = 0
            this._syncValueFromDisplay()
            this.onInput()
            this.minutesInputRef.value?.focus()
          }
        } else {
          e.preventDefault()
        }
    }
  }

  private _handleHoursBlur = (): void => {
    if (this._hours !== '') {
      this._hours = String(parseInt(this._hours, 10)).padStart(2, '0')
    }
    this._hoursDigitCount = 0
    this._hoursFirstDigit = -1
    this._syncValueFromDisplay()
  }

  private _handleMinutesKeydown = (e: KeyboardEvent): void => {
    const input = e.target as HTMLInputElement
    switch (e.key) {
      case 'ArrowUp': {
        e.preventDefault()
        const m = this._minutes !== '' ? parseInt(this._minutes, 10) : 0
        this._minutes = String((m + this._minuteStep) % 60).padStart(2, '0')
        this._syncValueFromDisplay()
        this.onInput()
        break
      }
      case 'ArrowDown': {
        e.preventDefault()
        const m = this._minutes !== '' ? parseInt(this._minutes, 10) : 0
        this._minutes = String((m - this._minuteStep + 60) % 60).padStart(2, '0')
        this._syncValueFromDisplay()
        this.onInput()
        break
      }
      case 'ArrowLeft':
        e.preventDefault()
        this.hoursInputRef.value?.focus()
        break
      case 'Backspace':
      case 'Delete':
        this._minutesDigitCount = 0
        this._minutesFirstDigit = -1
        break
      case 'Tab':
        break
      case 'Enter': {
        e.preventDefault()
        const form = this.internals.form as HTMLFormElement
        if (form) form.requestSubmit()
        else input.blur()
        break
      }
      default:
        if (/^\d$/.test(e.key)) {
          e.preventDefault()
          const digit = parseInt(e.key, 10)
          if (this._minutesDigitCount === 0) {
            this._minutesFirstDigit = digit
            this._minutes = String(digit).padStart(2, '0')
            this._minutesDigitCount = 1
            this.onInput()
            if (digit >= 6) {
              this._minutesFirstDigit = -1
              this._minutesDigitCount = 0
              this._syncValueFromDisplay()
            }
          } else {
            const combined = this._minutesFirstDigit * 10 + digit
            this._minutes =
              combined <= 59 ? String(combined).padStart(2, '0') : String(digit).padStart(2, '0')
            this._minutesFirstDigit = -1
            this._minutesDigitCount = 0
            this._syncValueFromDisplay()
            this.onInput()
          }
        } else {
          e.preventDefault()
        }
    }
  }

  private _handleMinutesBlur = (): void => {
    if (this._minutes !== '') {
      this._minutes = String(parseInt(this._minutes, 10)).padStart(2, '0')
    }
    this._minutesDigitCount = 0
    this._minutesFirstDigit = -1
    this._syncValueFromDisplay()
  }

  private _handleOptionClick(value: number, type: 'hour' | 'minute'): void {
    const padded = String(value).padStart(2, '0')
    if (type === 'hour') {
      this._hours = padded
      // Keep popup open, move focus to minute column
      this.updateComplete.then(() => this._focusSelectedOrFirst('minute'))
    } else {
      this._minutes = padded
      this._closePopup()
      this.buttonRef.value?.focus()
    }
  }

  private _focusOptionAndSync(option: HTMLElement | undefined, type: string): void {
    if (!option) return
    const val = parseInt(option.dataset.value ?? '0', 10)
    if (type === 'hour') this._hours = String(val).padStart(2, '0')
    else this._minutes = String(val).padStart(2, '0')
    option.focus()
  }

  private _handlePopupKeydown = (e: KeyboardEvent): void => {
    const focused = document.activeElement as HTMLElement
    const col = focused.closest('.pkt-timepicker-popup__col')
    if (!col) return
    const options = Array.from(col.querySelectorAll<HTMLElement>('.pkt-timepicker-popup__option'))
    const currentIdx = options.indexOf(focused)
    const type = focused.dataset.type ?? ''

    switch (e.key) {
      case 'ArrowDown':
        e.preventDefault()
        this._focusOptionAndSync(options[Math.min(currentIdx + 1, options.length - 1)], type)
        break
      case 'ArrowUp':
        e.preventDefault()
        this._focusOptionAndSync(options[Math.max(currentIdx - 1, 0)], type)
        break
      case 'Home':
        e.preventDefault()
        this._focusOptionAndSync(options[0], type)
        break
      case 'End':
        e.preventDefault()
        this._focusOptionAndSync(options[options.length - 1], type)
        break
      case 'ArrowRight':
        e.preventDefault()
        if (type === 'hour') {
          this._focusOptionAndSync(focused, type)
          this.updateComplete.then(() => {
            this._scrollToSelected()
            this._focusSelectedOrFirst('minute')
          })
        }
        break
      case 'ArrowLeft':
        e.preventDefault()
        if (type === 'minute') {
          this._focusOptionAndSync(focused, type)
          this.updateComplete.then(() => {
            this._scrollToSelected()
            this._focusSelectedOrFirst('hour')
          })
        }
        break
      case 'Enter':
      case ' ':
        e.preventDefault()
        focused.click()
        break
      case 'Escape':
        e.preventDefault()
        this._closePopup()
        this.buttonRef.value?.focus()
        break
    }
  }

  private _stepTime(direction: 1 | -1): void {
    const result = stepTime(this._hours, this._minutes, direction, this._minuteStep)
    this._hours = result.hours
    this._minutes = result.minutes
    this._syncValueFromDisplay()
  }

  private _renderOption(value: number, type: 'hour' | 'minute') {
    const strVal = String(value).padStart(2, '0')
    const currentVal =
      type === 'hour'
        ? this._hours !== ''
          ? parseInt(this._hours, 10)
          : NaN
        : this._minutes !== ''
          ? parseInt(this._minutes, 10)
          : NaN
    const isSelected = value === currentVal
    return html`
      <button
        class=${classMap({
          'pkt-btn': true,
          'pkt-btn--tertiary': true,
          'pkt-btn--small': true,
          'pkt-btn--label-only': true,
          'pkt-timepicker-popup__option': true,
          'pkt-timepicker-popup__option--selected': isSelected,
        })}
        type="button"
        role="option"
        aria-selected=${isSelected ? 'true' : 'false'}
        tabindex=${isSelected ? '0' : '-1'}
        data-type=${type}
        data-value=${value}
        @click=${(e: Event) => {
          e.stopImmediatePropagation()
          this._handleOptionClick(value, type)
        }}
      >
        <span class="pkt-btn__text pkt-txt-14-light">${strVal}</span>
      </button>
    `
  }

  private _renderPopup() {
    return html`
      <div
        class="pkt-timepicker-popup"
        id=${this.id + '-popup'}
        ?hidden=${!this._isOpen}
        role="group"
        aria-label=${this.strings.timepicker?.selectTime ?? 'Velg tidspunkt'}
        @keydown=${this._handlePopupKeydown}
        @focusout=${(e: FocusEvent) => {
          if (!this.querySelector('.pkt-timepicker-popup')?.contains(e.relatedTarget as Node)) {
            this._closePopup()
          }
        }}
      >
        <div
          class="pkt-timepicker-popup__col"
          role="listbox"
          aria-label=${this.strings.timepicker?.hours ?? 'Timer'}
          aria-orientation="vertical"
        >
          ${this._hourOptions.map((h) => this._renderOption(h, 'hour'))}
        </div>
        <div
          class="pkt-timepicker-popup__col"
          role="listbox"
          aria-label=${this.strings.timepicker?.minutes ?? 'Minutter'}
          aria-orientation="vertical"
        >
          ${this._minuteOptions.map((m) => this._renderOption(m, 'minute'))}
        </div>
      </div>
    `
  }

  private _renderContainer() {
    const hoursLabel = this.strings.timepicker?.hours ?? 'Timer'
    const minutesLabel = this.strings.timepicker?.minutes ?? 'Minutter'
    const hoursAriaLabel = this.label ? `${hoursLabel}, ${this.label}` : hoursLabel
    const minutesAriaLabel = this.label ? `${minutesLabel}, ${this.label}` : minutesLabel
    return html`
      <div
        class="pkt-input__container"
        @click=${(e: Event) => {
          const target = e.target as HTMLElement
          if (target.closest('button, input')) return
          this.hoursInputRef.value?.focus()
        }}
      >
        ${this.stepArrows
          ? html`
              <button
                class="pkt-input-icon pkt-btn pkt-btn--icon-only pkt-btn--tertiary pkt-timepicker__button pkt-timepicker__button--prev"
                type="button"
                aria-label=${this.strings.timepicker?.prevTime ?? 'Forrige tidspunkt'}
                ?disabled=${this.disabled}
                @click=${() => this._stepTime(-1)}
              >
                <pkt-icon name="chevron-thin-left"></pkt-icon>
                <span class="pkt-btn__text"
                  >${this.strings.timepicker?.prevTime ?? 'Forrige tidspunkt'}</span
                >
              </button>
            `
          : nothing}
        <input
          ${ref(this.hoursInputRef)}
          type="text"
          inputmode="numeric"
          maxlength="2"
          size="2"
          class="pkt-input pkt-timepicker__input"
          id=${this.id + '-hours'}
          data-min="0"
          data-max="23"
          .value=${this._hours}
          placeholder="––"
          aria-label=${hoursAriaLabel}
          role="spinbutton"
          aria-invalid=${this.hasError ? 'true' : nothing}
          aria-valuemin="0"
          aria-valuemax="23"
          aria-valuenow=${this._hours !== '' ? this._hours : nothing}
          aria-valuetext=${this._hours !== ''
            ? `${this._hours} ${hoursLabel.toLowerCase()}`
            : nothing}
          autocomplete="off"
          ?disabled=${this.disabled}
          @keydown=${this._handleHoursKeydown}
          @blur=${this._handleHoursBlur}
          @focus=${(e: FocusEvent) => {
            ;(e.target as HTMLInputElement).select()
            e.stopImmediatePropagation()
          }}
        />
        <span class="pkt-timepicker__separator">:</span>
        <input
          ${ref(this.minutesInputRef)}
          type="text"
          inputmode="numeric"
          maxlength="2"
          size="2"
          class="pkt-input pkt-timepicker__input"
          id=${this.id + '-minutes'}
          data-min="0"
          data-max="59"
          .value=${this._minutes}
          placeholder="––"
          aria-label=${minutesAriaLabel}
          role="spinbutton"
          aria-invalid=${this.hasError ? 'true' : nothing}
          aria-valuemin="0"
          aria-valuemax="59"
          aria-valuenow=${this._minutes !== '' ? this._minutes : nothing}
          aria-valuetext=${this._minutes !== ''
            ? `${this._minutes} ${minutesLabel.toLowerCase()}`
            : nothing}
          autocomplete="off"
          ?disabled=${this.disabled}
          @keydown=${this._handleMinutesKeydown}
          @blur=${this._handleMinutesBlur}
          @focus=${(e: FocusEvent) => {
            ;(e.target as HTMLInputElement).select()
            e.stopImmediatePropagation()
          }}
        />
        ${this.hidePicker && !this.stepArrows
          ? html`<pkt-icon
              class="pkt-input-icon pkt-timepicker__icon"
              name="clock"
              aria-hidden="true"
            ></pkt-icon>`
          : nothing}
        ${!this.hidePicker && !this.stepArrows
          ? html`
              <button
                ${ref(this.buttonRef)}
                class="pkt-input-icon pkt-btn pkt-btn--icon-only pkt-btn--tertiary pkt-timepicker__button"
                type="button"
                aria-label=${this.strings.timepicker?.openPicker ?? 'Åpne tidspunkt-velger'}
                aria-haspopup="listbox"
                aria-expanded=${this._isOpen ? 'true' : 'false'}
                aria-controls=${this.id + '-popup'}
                ?disabled=${this.disabled}
                @click=${this._togglePopup}
              >
                <pkt-icon name="clock"></pkt-icon>
                <span class="pkt-btn__text"
                  >${this.strings.timepicker?.openPicker ?? 'Åpne tidspunkt-velger'}</span
                >
              </button>
            `
          : nothing}
        ${this.stepArrows
          ? html`
              <button
                class="pkt-input-icon pkt-btn pkt-btn--icon-only pkt-btn--tertiary pkt-timepicker__button pkt-timepicker__button--next"
                type="button"
                aria-label=${this.strings.timepicker?.nextTime ?? 'Neste tidspunkt'}
                ?disabled=${this.disabled}
                @click=${() => this._stepTime(1)}
              >
                <pkt-icon name="chevron-thin-right"></pkt-icon>
                <span class="pkt-btn__text"
                  >${this.strings.timepicker?.nextTime ?? 'Neste tidspunkt'}</span
                >
              </button>
            `
          : nothing}
        <input
          ${ref(this.hiddenInputRef)}
          type="time"
          hidden
          name=${this.name || this.id}
          id=${this.id + '-input'}
          .value=${this.value}
          min=${ifDefined(this.min ?? undefined)}
          max=${ifDefined(this.max ?? undefined)}
          step=${ifDefined(this.step ?? undefined)}
          ?required=${this.required}
          ?disabled=${this.disabled}
          tabindex="-1"
        />
      </div>
    `
  }

  render() {
    return html`
      <pkt-input-wrapper
        label="${this.label}"
        ?disabled=${this.disabled}
        ?fullwidth=${this.fullwidth}
        ?hasError=${this.hasError}
        ?inline=${this.inline}
        ?optionalTag=${this.optionalTag}
        ?required=${this.required}
        ?requiredTag=${this.requiredTag}
        useWrapper=${this.useWrapper}
        .ariaDescribedBy=${this.ariaDescribedBy}
        .errorMessage=${this.errorMessage}
        .forId="${this.id + '-hours'}"
        .helptext=${this.helptext}
        .helptextDropdown=${this.helptextDropdown}
        .helptextDropdownButton=${this.helptextDropdownButton}
        .optionalText=${this.optionalText}
        .requiredText=${this.requiredText}
        .tagText=${this.tagText}
      >
        <div class="pkt-contents" slot="helptext">${slotContent(this, 'helptext')}</div>
        ${!this.hidePicker && !this.stepArrows
          ? html`
              <div class="pkt-timepicker__anchor">
                ${this._renderContainer()} ${this._renderPopup()}
              </div>
            `
          : this._renderContainer()}
      </pkt-input-wrapper>
    `
  }
}

try {
  customElement('pkt-timepicker')(PktTimepicker)
} catch (e) {
  console.warn('Forsøker å definere <pkt-timepicker>, men den er allerede definert')
}
