/**
 * Checkbox - Custom checkbox component with accessible native input
 * @countermeasure/web-components/primitives/checkbox
 */

import { type CheckboxConfig } from './types'
import { resolveContainer, uniqueId } from '../utils'

export class Checkbox {
  public readonly el: HTMLElement

  private readonly inputEl: HTMLInputElement
  private readonly boxEl: HTMLSpanElement
  private readonly labelEl: HTMLSpanElement
  private config: CheckboxConfig
  private isDestroyed = false

  private readonly handleChange: () => void

  constructor(config: CheckboxConfig) {
    this.config = config

    this.el = document.createElement('label')
    this.el.className = 'cmm-checkbox'
    if (config.className) {
      this.el.classList.add(config.className)
    }

    if (config.disabled === true) {
      this.el.classList.add('cmm-checkbox--disabled')
    }

    this.inputEl = document.createElement('input')
    this.inputEl.type = 'checkbox'
    this.inputEl.className = 'cmm-checkbox__input'
    this.inputEl.id = uniqueId('cmm-checkbox')

    if (config.name) {
      this.inputEl.name = config.name
    }

    if (config.value) {
      this.inputEl.value = config.value
    }

    if (config.checked === true) {
      this.inputEl.checked = true
    }

    if (config.indeterminate === true) {
      this.inputEl.indeterminate = true
    }

    if (config.disabled === true) {
      this.inputEl.disabled = true
    }

    if (config.ariaLabel) {
      this.inputEl.setAttribute('aria-label', config.ariaLabel)
    }

    this.boxEl = document.createElement('span')
    this.boxEl.className = 'cmm-checkbox__box'
    this.boxEl.setAttribute('aria-hidden', 'true')

    this.labelEl = document.createElement('span')
    this.labelEl.className = 'cmm-checkbox__label'
    if (config.label) {
      this.labelEl.textContent = config.label
    }

    this.el.appendChild(this.inputEl)
    this.el.appendChild(this.boxEl)
    this.el.appendChild(this.labelEl)

    this.handleChange = () => {
      if (this.isDestroyed) {
        return
      }
      this.inputEl.indeterminate = false
      this.config.onChange?.(this.inputEl.checked)
    }

    this.inputEl.addEventListener('change', this.handleChange)

    if (config.container !== undefined) {
      const parent = resolveContainer(config.container)
      parent.appendChild(this.el)
    }
  }

  isChecked(): boolean {
    return this.inputEl.checked
  }

  setChecked(checked: boolean): void {
    this.inputEl.checked = checked
    this.inputEl.indeterminate = false
  }

  setIndeterminate(indeterminate: boolean): void {
    this.inputEl.indeterminate = indeterminate
  }

  setDisabled(disabled: boolean): void {
    this.inputEl.disabled = disabled
    if (disabled) {
      this.el.classList.add('cmm-checkbox--disabled')
    } else {
      this.el.classList.remove('cmm-checkbox--disabled')
    }
  }

  toggle(): void {
    this.inputEl.checked = !this.inputEl.checked
    this.inputEl.indeterminate = false
    this.config.onChange?.(this.inputEl.checked)
  }

  destroy(): void {
    this.isDestroyed = true
    this.inputEl.removeEventListener('change', this.handleChange)
    this.el.remove()
  }
}

export { type CheckboxConfig } from './types'
