/**
 * VulnerabilityCard - CVE / vulnerability display card
 * @countermeasure/web-components/security/vulnerability-card
 */

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

export type { VulnerabilityCardConfig, VulnerabilityData, VulnerabilityReference } from './types'

/** Severity display labels */
const SEVERITY_LABELS: Record<VulnerabilityData['severity'], string> = {
  critical: 'Critical',
  high: 'High',
  medium: 'Medium',
  low: 'Low',
  info: 'Info',
}

/** Status display labels */
const STATUS_LABELS: Record<string, string> = {
  open: 'Open',
  in_progress: 'In Progress',
  resolved: 'Resolved',
  accepted: 'Accepted',
  false_positive: 'False Positive',
}

/** Escape HTML special characters */
function esc(text: string): string {
  const div = document.createElement('div')
  div.textContent = text
  return div.innerHTML
}

/** Format a date to a locale string */
function formatDate(value: Date | string): string {
  const d = value instanceof Date ? value : new Date(value)
  return d.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' })
}

export class VulnerabilityCard {
  public readonly el: HTMLDivElement

  private readonly cardId: string
  private readonly compact: boolean
  private readonly showReferences: boolean
  private readonly clickHandler: ((data: VulnerabilityData) => void) | undefined
  private currentData: VulnerabilityData
  private refsExpanded = false
  private readonly boundCardClick: (() => void) | null

  constructor(config: VulnerabilityCardConfig) {
    this.cardId = uniqueId('cmm-vuln-card')
    this.compact = config.compact === true
    this.showReferences = config.showReferences !== false
    this.clickHandler = config.onClick
    this.currentData = config.data

    // Create root element
    this.el = document.createElement('div')
    this.el.id = this.cardId
    this.el.className = this.buildRootClassName(config.className)

    // Click handler on the card
    if (this.clickHandler !== undefined) {
      this.el.style.cursor = 'pointer'
      const handler = () => {
        if (this.clickHandler !== undefined) {
          this.clickHandler(this.currentData)
        }
      }
      this.boundCardClick = handler
      this.el.addEventListener('click', handler)
    } else {
      this.boundCardClick = null
    }

    this.renderContent()

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

  /** Update the card with new vulnerability data */
  update(data: VulnerabilityData): void {
    this.currentData = data
    this.el.innerHTML = ''
    this.renderContent()
  }

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

  private renderContent(): void {
    const data = this.currentData

    // Header
    const header = document.createElement('div')
    header.className = 'cmm-vuln-card__header'

    // Severity badge
    const severityBadge = document.createElement('span')
    severityBadge.className = `cmm-vuln-card__severity cmm-vuln-card__severity--${data.severity}`
    const label = SEVERITY_LABELS[data.severity]
    severityBadge.textContent = label
    header.appendChild(severityBadge)

    // CVE ID
    const cveId = document.createElement('span')
    cveId.className = 'cmm-vuln-card__id'
    cveId.textContent = data.id
    header.appendChild(cveId)

    // Title
    const title = document.createElement('span')
    title.className = 'cmm-vuln-card__title'
    title.textContent = data.title
    header.appendChild(title)

    // Status badge
    if (data.status !== undefined) {
      const statusLabel = STATUS_LABELS[data.status]
      if (statusLabel !== undefined) {
        const statusEl = document.createElement('span')
        statusEl.className = `cmm-vuln-card__status cmm-vuln-card__status--${data.status}`
        statusEl.textContent = statusLabel
        header.appendChild(statusEl)
      }
    }

    this.el.appendChild(header)

    // Body
    const body = document.createElement('div')
    body.className = 'cmm-vuln-card__body'

    // Description
    const desc = document.createElement('p')
    desc.className = 'cmm-vuln-card__description'
    if (this.compact && data.description.length > 150) {
      desc.textContent = data.description.slice(0, 150) + '...'
      desc.title = data.description
    } else {
      desc.textContent = data.description
    }
    body.appendChild(desc)

    // CVSS score
    if (data.cvss !== undefined) {
      const cvssRow = document.createElement('div')
      cvssRow.className = 'cmm-vuln-card__cvss'

      const cvssLabel = document.createElement('span')
      cvssLabel.className = 'cmm-vuln-card__cvss-label'
      cvssLabel.textContent = 'CVSS:'
      cvssRow.appendChild(cvssLabel)

      const cvssValue = document.createElement('span')
      cvssValue.className = 'cmm-vuln-card__cvss-value'
      cvssValue.textContent = data.cvss.toFixed(1)
      cvssRow.appendChild(cvssValue)

      if (data.cvssVector !== undefined) {
        const vectorEl = document.createElement('span')
        vectorEl.className = 'cmm-vuln-card__cvss-vector'
        vectorEl.textContent = data.cvssVector
        vectorEl.title = data.cvssVector
        cvssRow.appendChild(vectorEl)
      }

      body.appendChild(cvssRow)
    }

    // CWE
    if (data.cwe !== undefined) {
      const cweEl = document.createElement('div')
      cweEl.className = 'cmm-vuln-card__cwe'

      const cweLink = document.createElement('a')
      cweLink.className = 'cmm-vuln-card__cwe-link'
      cweLink.href = `https://cwe.mitre.org/data/definitions/${data.cwe.replace('CWE-', '')}.html`
      cweLink.target = '_blank'
      cweLink.rel = 'noopener noreferrer'
      cweLink.textContent = data.cwe
      cweEl.appendChild(cweLink)
      body.appendChild(cweEl)
    }

    this.el.appendChild(body)

    // Metadata section
    const meta = document.createElement('div')
    meta.className = 'cmm-vuln-card__meta'

    // Dates
    if (data.published !== undefined) {
      const pubEl = document.createElement('span')
      pubEl.className = 'cmm-vuln-card__date'
      pubEl.textContent = `Published: ${formatDate(data.published)}`
      meta.appendChild(pubEl)
    }

    if (data.modified !== undefined) {
      const modEl = document.createElement('span')
      modEl.className = 'cmm-vuln-card__date'
      modEl.textContent = `Modified: ${formatDate(data.modified)}`
      meta.appendChild(modEl)
    }

    // Affected components
    if (data.affected !== undefined && data.affected.length > 0) {
      const affectedEl = document.createElement('div')
      affectedEl.className = 'cmm-vuln-card__affected'

      const affectedLabel = document.createElement('span')
      affectedLabel.className = 'cmm-vuln-card__affected-label'
      affectedLabel.textContent = 'Affected:'
      affectedEl.appendChild(affectedLabel)

      for (const comp of data.affected) {
        const chip = document.createElement('span')
        chip.className = 'cmm-vuln-card__affected-chip'
        chip.textContent = comp
        affectedEl.appendChild(chip)
      }
      meta.appendChild(affectedEl)
    }

    if (meta.childNodes.length > 0) {
      this.el.appendChild(meta)
    }

    // Tags
    if (data.tags !== undefined && data.tags.length > 0) {
      const tagsEl = document.createElement('div')
      tagsEl.className = 'cmm-vuln-card__tags'

      for (const tag of data.tags) {
        const pill = document.createElement('span')
        pill.className = 'cmm-vuln-card__tag'
        pill.textContent = tag
        tagsEl.appendChild(pill)
      }
      this.el.appendChild(tagsEl)
    }

    // References
    if (this.showReferences && data.references !== undefined && data.references.length > 0) {
      const refsSection = document.createElement('div')
      refsSection.className = 'cmm-vuln-card__references'

      if (this.compact) {
        const toggleBtn = document.createElement('button')
        toggleBtn.className = 'cmm-vuln-card__refs-toggle'
        toggleBtn.type = 'button'
        toggleBtn.textContent = this.refsExpanded
          ? `Hide References (${String(data.references.length)})`
          : `Show References (${String(data.references.length)})`
        toggleBtn.addEventListener('click', (e: MouseEvent) => {
          e.stopPropagation()
          this.refsExpanded = !this.refsExpanded
          this.el.innerHTML = ''
          this.renderContent()
        })
        refsSection.appendChild(toggleBtn)

        if (this.refsExpanded) {
          this.appendRefList(refsSection, data.references)
        }
      } else {
        const refsTitle = document.createElement('div')
        refsTitle.className = 'cmm-vuln-card__refs-title'
        refsTitle.textContent = `References (${String(data.references.length)})`
        refsSection.appendChild(refsTitle)
        this.appendRefList(refsSection, data.references)
      }

      this.el.appendChild(refsSection)
    }
  }

  private appendRefList(
    parent: HTMLElement,
    refs: readonly { title: string; url: string }[]
  ): void {
    const list = document.createElement('ul')
    list.className = 'cmm-vuln-card__refs-list'
    for (const ref of refs) {
      const li = document.createElement('li')
      li.className = 'cmm-vuln-card__refs-item'
      const a = document.createElement('a')
      a.className = 'cmm-vuln-card__refs-link'
      a.href = ref.url
      a.target = '_blank'
      a.rel = 'noopener noreferrer'
      a.innerHTML = esc(ref.title)
      li.appendChild(a)
      list.appendChild(li)
    }
    parent.appendChild(list)
  }

  private buildRootClassName(extra?: string): string {
    const classes = ['cmm-vuln-card']
    if (this.compact) {
      classes.push('cmm-vuln-card--compact')
    }
    if (extra) {
      classes.push(extra)
    }
    return classes.join(' ')
  }
}
