/**
 * StatusDot - Semantic status indicator dot
 * @countermeasure/web-components/display/status-dot
 */

import { type StatusDotConfig, type StatusDotSize, type StatusDotStatus } from './types'
import { resolveContainer, uniqueId } from '../../primitives/utils'

export type { StatusDotConfig, StatusDotSize, StatusDotStatus } from './types'

export class StatusDot {
  public readonly el: HTMLSpanElement

  private readonly statusDotId: string
  private currentStatus: StatusDotStatus
  private currentSize: 'sm' | 'md'

  constructor(config: StatusDotConfig = {}) {
    this.statusDotId = uniqueId('cmm-status-dot')
    this.currentStatus = config.status ?? 'neutral'
    this.currentSize = normalizeStatusDotSize(config.size)

    this.el = document.createElement('span')
    this.el.id = this.statusDotId
    this.el.className = this.buildClassName(config)

    if (config.decorative === false) {
      this.el.setAttribute('role', 'img')
      this.el.setAttribute('aria-label', config.label ?? this.currentStatus)
    } else if (config.label !== undefined) {
      this.el.setAttribute('role', 'img')
      this.el.setAttribute('aria-label', config.label)
    } else {
      this.el.setAttribute('aria-hidden', 'true')
    }

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

  setStatus(status: StatusDotStatus): void {
    this.el.classList.remove(`cmm-status-dot--${this.currentStatus}`)
    this.currentStatus = status
    this.el.classList.add(`cmm-status-dot--${this.currentStatus}`)
  }

  setSize(size: StatusDotSize): void {
    this.el.classList.remove(`cmm-status-dot--${this.currentSize}`)
    this.currentSize = normalizeStatusDotSize(size)
    this.el.classList.add(`cmm-status-dot--${this.currentSize}`)
  }

  setLabel(label: string | null): void {
    if (label === null) {
      this.el.removeAttribute('role')
      this.el.removeAttribute('aria-label')
      this.el.setAttribute('aria-hidden', 'true')
      return
    }

    this.el.removeAttribute('aria-hidden')
    this.el.setAttribute('role', 'img')
    this.el.setAttribute('aria-label', label)
  }

  destroy(): void {
    this.el.remove()
  }

  private buildClassName(config: StatusDotConfig): string {
    const classes = [
      'cmm-status-dot',
      `cmm-status-dot--${this.currentStatus}`,
      `cmm-status-dot--${this.currentSize}`,
    ]

    if (config.pulse === true) {
      classes.push('cmm-status-dot--pulse')
    }

    if (config.className) {
      classes.push(config.className)
    }

    return classes.join(' ')
  }
}

export function normalizeStatusDotSize(size: StatusDotSize = 'sm'): 'sm' | 'md' {
  if (size === 8 || size === 'md') {
    return 'md'
  }

  return 'sm'
}
