/**
 * Toggle - Pressable toggle button component
 * @countermeasure/web-components/primitives/toggle
 */

import { type ToggleConfig, type ToggleVariant } from './types'
import { resolveContainer, uniqueId } from '../utils'
import { setSafeIconHtml } from '../../utils/sanitize'

export type {
  ToggleConfig,
  ToggleVariant,
  ToggleGroupType,
  ToggleGroupConfig,
  ToggleGroupItem,
} from './types'
export { ToggleGroup } from './toggle-group'

export class Toggle {
  public readonly el: HTMLButtonElement

  private readonly toggleId: string
  private currentVariant: ToggleVariant
  private pressed: boolean
  private readonly clickHandler: () => void
  private readonly onChangeCallback: ((pressed: boolean) => void) | undefined

  constructor(config: ToggleConfig) {
    this.toggleId = uniqueId('cmm-toggle')
    this.currentVariant = config.variant ?? 'default'
    this.pressed = config.pressed === true
    this.onChangeCallback = config.onChange

    // Create the button element
    this.el = document.createElement('button')
    this.el.type = 'button'
    this.el.id = this.toggleId
    this.el.className = this.buildClassName(config.className)
    this.el.setAttribute('aria-pressed', String(this.pressed))

    if (config.ariaLabel !== undefined) {
      this.el.setAttribute('aria-label', config.ariaLabel)
    }

    // Build inner content
    if (config.icon !== undefined) {
      const iconEl = document.createElement('span')
      iconEl.className = 'cmm-toggle__icon'
      setSafeIconHtml(iconEl, config.icon)
      this.el.appendChild(iconEl)
    }

    if (config.label !== undefined) {
      const labelEl = document.createElement('span')
      labelEl.className = 'cmm-toggle__label'
      labelEl.textContent = config.label
      this.el.appendChild(labelEl)
    }

    // Disabled state
    if (config.disabled === true) {
      this.el.disabled = true
    }

    // Click handler
    this.clickHandler = () => {
      this.pressed = !this.pressed
      this.updatePressedState()
      this.onChangeCallback?.(this.pressed)
    }
    this.el.addEventListener('click', this.clickHandler)

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

  /** Returns whether the toggle is pressed */
  isPressed(): boolean {
    return this.pressed
  }

  /** Programmatically set the pressed state */
  setPressed(pressed: boolean): void {
    if (pressed !== this.pressed) {
      this.pressed = pressed
      this.updatePressedState()
    }
  }

  /** Set the disabled state */
  setDisabled(disabled: boolean): void {
    this.el.disabled = disabled
  }

  /** Change the variant */
  setVariant(variant: ToggleVariant): void {
    this.el.classList.remove(`cmm-toggle--${this.currentVariant}`)
    this.currentVariant = variant
    this.el.classList.add(`cmm-toggle--${this.currentVariant}`)
  }

  /** Remove from DOM and clean up */
  destroy(): void {
    this.el.removeEventListener('click', this.clickHandler)
    this.el.remove()
  }

  private updatePressedState(): void {
    this.el.setAttribute('aria-pressed', String(this.pressed))
    if (this.pressed) {
      this.el.classList.add('cmm-toggle--pressed')
    } else {
      this.el.classList.remove('cmm-toggle--pressed')
    }
  }

  private buildClassName(extra?: string): string {
    const classes = ['cmm-toggle', `cmm-toggle--${this.currentVariant}`]
    if (this.pressed) {
      classes.push('cmm-toggle--pressed')
    }
    if (extra) {
      classes.push(extra)
    }
    return classes.join(' ')
  }
}
