/**
 * CvssBadge - CVSS score display with severity color coding
 * @countermeasure/web-components/security/cvss-badge
 */

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

export type { CvssBadgeConfig } from './types'

type SeverityLabel = 'None' | 'Low' | 'Medium' | 'High' | 'Critical'

/** Determine CVSS severity label from a numeric score */
function getSeverity(score: number): SeverityLabel {
  if (score <= 0) {
    return 'None'
  }
  if (score <= 3.9) {
    return 'Low'
  }
  if (score <= 6.9) {
    return 'Medium'
  }
  if (score <= 8.9) {
    return 'High'
  }
  return 'Critical'
}

/** Map severity label to a CSS modifier */
function getSeverityModifier(label: SeverityLabel): string {
  switch (label) {
    case 'None':
      return 'none'
    case 'Low':
      return 'low'
    case 'Medium':
      return 'medium'
    case 'High':
      return 'high'
    case 'Critical':
      return 'critical'
  }
}

export class CvssBadge {
  public readonly el: HTMLDivElement

  private readonly badgeId: string
  private readonly size: 'sm' | 'md' | 'lg'
  private scoreEl: HTMLSpanElement
  private severityEl: HTMLSpanElement
  private vectorEl: HTMLSpanElement | null = null
  private versionEl: HTMLSpanElement | null = null
  private currentScore: number
  private readonly showVector: boolean

  constructor(config: CvssBadgeConfig) {
    this.badgeId = uniqueId('cmm-cvss-badge')
    this.size = config.size ?? 'md'
    this.currentScore = Math.max(0, Math.min(10, config.score))
    this.showVector = config.showVector === true

    const severity = getSeverity(this.currentScore)
    const modifier = getSeverityModifier(severity)

    // Create root element
    this.el = document.createElement('div')
    this.el.id = this.badgeId
    this.el.className = this.buildClassName(modifier, config.className)
    this.el.setAttribute('role', 'status')
    this.el.setAttribute('aria-label', `CVSS Score: ${String(this.currentScore)} - ${severity}`)

    // Score display
    this.scoreEl = document.createElement('span')
    this.scoreEl.className = 'cmm-cvss-badge__score'
    this.scoreEl.textContent = this.currentScore.toFixed(1)
    this.el.appendChild(this.scoreEl)

    // Severity label
    this.severityEl = document.createElement('span')
    this.severityEl.className = 'cmm-cvss-badge__severity'
    this.severityEl.textContent = severity
    this.el.appendChild(this.severityEl)

    // Version label
    if (config.version !== undefined) {
      this.versionEl = document.createElement('span')
      this.versionEl.className = 'cmm-cvss-badge__version'
      this.versionEl.textContent = `CVSS v${config.version}`
      this.el.appendChild(this.versionEl)
    }

    // Vector string
    if (this.showVector && config.vector !== undefined) {
      this.vectorEl = document.createElement('span')
      this.vectorEl.className = 'cmm-cvss-badge__vector'
      this.vectorEl.textContent = config.vector
      this.vectorEl.title = config.vector
      this.el.appendChild(this.vectorEl)
    }

    // Mount
    const parent = resolveContainer(config.container)
    parent.appendChild(this.el)
  }

  /** Update the displayed CVSS score and optional vector */
  update(score: number, vector?: string): void {
    this.currentScore = Math.max(0, Math.min(10, score))
    const severity = getSeverity(this.currentScore)
    const modifier = getSeverityModifier(severity)

    // Update score text
    this.scoreEl.textContent = this.currentScore.toFixed(1)
    this.severityEl.textContent = severity

    // Update severity class
    this.el.className = this.buildClassName(modifier)
    this.el.setAttribute('aria-label', `CVSS Score: ${String(this.currentScore)} - ${severity}`)

    // Update vector
    if (this.vectorEl !== null && vector !== undefined) {
      this.vectorEl.textContent = vector
      this.vectorEl.title = vector
    }
  }

  /** Remove the element from the DOM and clean up */
  destroy(): void {
    this.el.remove()
  }

  private buildClassName(modifier: string, extra?: string): string {
    const classes = [
      'cmm-cvss-badge',
      `cmm-cvss-badge--${modifier}`,
      `cmm-cvss-badge--${this.size}`,
    ]
    if (extra) {
      classes.push(extra)
    }
    return classes.join(' ')
  }
}
