/**
 * Breadcrumb - Navigation trail with overflow truncation
 * @countermeasure/web-components/navigation/breadcrumb
 */

import { resolveContainer, uniqueId } from '../../primitives/utils'
import { escapeHtml, sanitizeHtml } from '../../utils/sanitize'
import { type BreadcrumbConfig, type BreadcrumbItem } from './types'

export type { BreadcrumbConfig, BreadcrumbItem } from './types'

export class Breadcrumb {
  private readonly container: HTMLElement
  private readonly separator: string
  private readonly maxVisible: number | undefined
  private readonly className: string | undefined
  private readonly onNavigate: ((item: BreadcrumbItem, index: number) => void) | undefined
  private readonly navId: string

  private items: BreadcrumbItem[]
  private destroyed = false

  constructor(config: BreadcrumbConfig) {
    this.container = resolveContainer(config.container)
    this.items = [...config.items]
    this.separator = config.separator ?? '/'
    this.maxVisible = config.maxVisible
    this.className = config.className
    this.onNavigate = config.onNavigate
    this.navId = uniqueId('cmm-breadcrumb')

    this.render()
  }

  /** Update the breadcrumb items and re-render */
  update(items: BreadcrumbItem[]): void {
    if (this.destroyed) {
      return
    }
    this.items = [...items]
    this.render()
  }

  /** Remove all DOM elements and clean up */
  destroy(): void {
    if (this.destroyed) {
      return
    }
    this.destroyed = true
    this.container.innerHTML = ''
  }

  /** Build the visible item list, applying overflow truncation if needed */
  private getVisibleItems(): (BreadcrumbItem | 'ellipsis')[] {
    if (this.maxVisible === undefined || this.items.length <= this.maxVisible) {
      return [...this.items]
    }

    // Show first item, ellipsis, then last (maxVisible - 1) items
    const tailCount = this.maxVisible - 1
    const first = this.items[0]
    const tail = this.items.slice(this.items.length - tailCount)

    if (first === undefined) {
      return []
    }

    return [first, 'ellipsis' as const, ...tail]
  }

  /** Render the breadcrumb navigation */
  private render(): void {
    this.container.innerHTML = ''

    const nav = document.createElement('nav')
    nav.id = this.navId
    nav.className = 'cmm-breadcrumb'
    nav.setAttribute('aria-label', 'Breadcrumb')

    if (this.className) {
      nav.classList.add(this.className)
    }

    const ol = document.createElement('ol')
    ol.className = 'cmm-breadcrumb__list'

    const visibleItems = this.getVisibleItems()

    for (let i = 0; i < visibleItems.length; i++) {
      const entry = visibleItems[i]

      // Add separator before every item except the first
      if (i > 0) {
        const sepLi = document.createElement('li')
        sepLi.className = 'cmm-breadcrumb__separator'
        sepLi.setAttribute('aria-hidden', 'true')
        sepLi.innerHTML = escapeHtml(this.separator)
        ol.appendChild(sepLi)
      }

      if (entry === 'ellipsis') {
        const ellipsisLi = document.createElement('li')
        ellipsisLi.className = 'cmm-breadcrumb__item cmm-breadcrumb__item--ellipsis'
        ellipsisLi.setAttribute('aria-hidden', 'true')

        const ellipsisSpan = document.createElement('span')
        ellipsisSpan.className = 'cmm-breadcrumb__ellipsis'
        ellipsisSpan.textContent = '\u2026'
        ellipsisLi.appendChild(ellipsisSpan)
        ol.appendChild(ellipsisLi)
        continue
      }

      if (entry === undefined) {
        continue
      }

      // Find the real index in the original items array
      const realIndex = this.items.indexOf(entry)

      const li = document.createElement('li')
      li.className = 'cmm-breadcrumb__item'

      if (entry.current === true) {
        li.classList.add('cmm-breadcrumb__item--current')
      }

      const el =
        entry.href && entry.current !== true
          ? document.createElement('a')
          : document.createElement('span')

      el.className = 'cmm-breadcrumb__link'

      if (el instanceof HTMLAnchorElement && entry.href) {
        el.href = entry.href
      }

      if (entry.current === true) {
        el.setAttribute('aria-current', 'page')
      }

      // Icon
      if (entry.icon) {
        const iconSpan = document.createElement('span')
        iconSpan.className = 'cmm-breadcrumb__icon'
        iconSpan.setAttribute('aria-hidden', 'true')
        iconSpan.innerHTML = sanitizeHtml(entry.icon, { allowSvg: true })
        el.appendChild(iconSpan)
      }

      // Label
      const labelSpan = document.createElement('span')
      labelSpan.textContent = entry.label
      el.appendChild(labelSpan)

      // Click handler
      if (entry.href && entry.current !== true) {
        const item = entry
        el.addEventListener('click', (e: MouseEvent) => {
          if (this.onNavigate) {
            e.preventDefault()
            this.onNavigate(item, realIndex)
          }
        })
      }

      li.appendChild(el)
      ol.appendChild(li)
    }

    nav.appendChild(ol)
    this.container.appendChild(nav)
  }
}
