/**
 * Badge - Small status indicator label
 * @countermeasure/web-components/display/badge
 */

import { type BadgeConfig, type BadgeVariant } from './types'
import { resolveContainer, uniqueId } from '../../primitives/utils'

export type { BadgeConfig, BadgeVariant, BadgeSeverity, BadgeStatus } from './types'
export { severityBadge, statusBadge } from './presets'

export class Badge {
  public readonly el: HTMLSpanElement

  private readonly badgeId: string
  private currentVariant: BadgeVariant
  private labelEl: HTMLSpanElement
  private dotEl: HTMLSpanElement | null = null
  private removeBtn: HTMLButtonElement | null = null
  private readonly removeHandler: (() => void) | undefined
  private readonly removeBtnClickHandler: (() => void) | null = null

  constructor(config: BadgeConfig) {
    this.badgeId = uniqueId('cmm-badge')
    this.currentVariant = config.variant ?? 'default'
    this.removeHandler = config.onRemove

    // Create root element
    this.el = document.createElement('span')
    this.el.id = this.badgeId
    this.el.className = this.buildClassName(config)

    // Create dot indicator
    if (config.dot === true) {
      this.dotEl = document.createElement('span')
      this.dotEl.className = 'cmm-badge__dot'
      this.dotEl.setAttribute('aria-hidden', 'true')
      this.el.appendChild(this.dotEl)
    }

    // Create label
    this.labelEl = document.createElement('span')
    this.labelEl.className = 'cmm-badge__label'
    this.labelEl.textContent = config.label
    this.el.appendChild(this.labelEl)

    // Create remove button
    if (config.removable === true) {
      this.removeBtn = document.createElement('button')
      this.removeBtn.className = 'cmm-badge__remove'
      this.removeBtn.setAttribute('aria-label', 'Remove')
      this.removeBtn.type = 'button'
      this.removeBtn.textContent = '\u00d7'

      const handler = () => {
        if (this.removeHandler !== undefined) {
          this.removeHandler()
        }
      }
      // Store reference for cleanup via reassignment to a non-null local
      const btnRef = this.removeBtn
      btnRef.addEventListener('click', handler)
      // Store in a way we can reference in destroy
      this.removeBtnClickHandler = handler
      this.el.appendChild(this.removeBtn)
    }

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

  /** Update the badge label text */
  setLabel(label: string): void {
    this.labelEl.textContent = label
  }

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

  /** Remove the badge from the DOM and clean up */
  destroy(): void {
    if (this.removeBtn !== null && this.removeBtnClickHandler !== null) {
      this.removeBtn.removeEventListener('click', this.removeBtnClickHandler)
    }
    this.el.remove()
  }

  private buildClassName(config: BadgeConfig): string {
    const classes = ['cmm-badge', `cmm-badge--${this.currentVariant}`]

    if (config.severity !== undefined) {
      classes.push(`cmm-badge--severity-${config.severity}`)
    }
    if (config.status !== undefined) {
      classes.push(`cmm-badge--status-${config.status}`)
    }
    if (config.className) {
      classes.push(config.className)
    }
    return classes.join(' ')
  }
}
