/**
 * Avatar - User avatar with image, initials fallback, and status indicator
 * @countermeasure/web-components/display/avatar
 */

import { type AvatarConfig, type AvatarSize, type AvatarShape, type AvatarStatus } from './types'
import { resolveContainer, uniqueId } from '../../primitives/utils'

export type {
  AvatarConfig,
  AvatarSize,
  AvatarShape,
  AvatarStatus,
  AvatarGroupConfig,
} from './types'
export { AvatarGroup } from './avatar-group'

/** Default user icon SVG for when no image or name is provided */
const DEFAULT_USER_ICON =
  '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>'

/** Extract initials from a name string (first letter of first two words) */
function extractInitials(name: string): string {
  const words = name.trim().split(/\s+/)
  const first = words[0]
  const second = words[1]
  if (first === undefined) {
    return ''
  }
  const firstChar = first[0] ?? ''
  if (second !== undefined) {
    const secondChar = second[0] ?? ''
    return `${firstChar}${secondChar}`.toUpperCase()
  }
  return firstChar.toUpperCase()
}

export class Avatar {
  public readonly el: HTMLDivElement

  private readonly avatarId: string
  private currentSize: AvatarSize
  private currentShape: AvatarShape
  private currentSrc: string | undefined
  private currentName: string | undefined
  private contentEl: HTMLImageElement | HTMLSpanElement
  private statusEl: HTMLSpanElement | null = null

  constructor(config: AvatarConfig) {
    this.avatarId = uniqueId('cmm-avatar')
    this.currentSize = config.size ?? 'md'
    this.currentShape = config.shape ?? 'circle'
    this.currentSrc = config.src
    this.currentName = config.name

    // Create root element
    this.el = document.createElement('div')
    this.el.id = this.avatarId
    this.el.className = this.buildClassName(config.className)
    if (config.decorative === true) {
      this.el.setAttribute('role', 'presentation')
    } else {
      this.el.setAttribute('role', 'img')
      this.el.setAttribute('aria-label', config.alt ?? config.name ?? 'User avatar')
    }

    // Create content (image, initials, or default icon)
    this.contentEl = this.createContent()
    this.el.appendChild(this.contentEl)

    // Create status indicator
    if (config.status !== undefined) {
      this.statusEl = this.createStatusEl(config.status)
      this.el.appendChild(this.statusEl)
    }

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

  /** Update the avatar image source */
  setSrc(src: string): void {
    this.currentSrc = src
    this.rebuildContent()
  }

  /** Update the avatar name (used for initials) */
  setName(name: string): void {
    this.currentName = name
    // Only rebuild if we're not showing an image
    if (this.currentSrc === undefined) {
      this.rebuildContent()
    }
    this.el.setAttribute('aria-label', name)
  }

  /** Update or clear the status indicator */
  setStatus(status: AvatarStatus | null): void {
    // Remove existing status indicator
    if (this.statusEl !== null) {
      this.statusEl.remove()
      this.statusEl = null
    }

    if (status !== null) {
      this.statusEl = this.createStatusEl(status)
      this.el.appendChild(this.statusEl)
    }
  }

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

  private buildClassName(extra?: string): string {
    const classes = [
      'cmm-avatar',
      `cmm-avatar--${this.currentSize}`,
      `cmm-avatar--${this.currentShape}`,
    ]
    if (extra) {
      classes.push(extra)
    }
    return classes.join(' ')
  }

  private createContent(): HTMLImageElement | HTMLSpanElement {
    if (this.currentSrc !== undefined) {
      return this.createImageEl(this.currentSrc)
    }
    if (this.currentName) {
      return this.createInitialsEl(this.currentName)
    }
    return this.createDefaultIconEl()
  }

  private createImageEl(src: string): HTMLImageElement {
    const img = document.createElement('img')
    img.className = 'cmm-avatar__image'
    img.src = src
    img.alt = ''
    img.setAttribute('aria-hidden', 'true')
    img.addEventListener('error', () => {
      this.currentSrc = undefined
      this.rebuildContent()
    })
    return img
  }

  private createInitialsEl(name: string): HTMLSpanElement {
    const span = document.createElement('span')
    span.className = 'cmm-avatar__initials'
    span.setAttribute('aria-hidden', 'true')
    span.textContent = extractInitials(name)
    return span
  }

  private createDefaultIconEl(): HTMLSpanElement {
    const span = document.createElement('span')
    span.className = 'cmm-avatar__icon'
    span.setAttribute('aria-hidden', 'true')
    span.innerHTML = DEFAULT_USER_ICON
    return span
  }

  private createStatusEl(status: AvatarStatus): HTMLSpanElement {
    const span = document.createElement('span')
    span.className = `cmm-avatar__status cmm-avatar__status--${status}`
    span.setAttribute('aria-hidden', 'true')
    return span
  }

  private rebuildContent(): void {
    this.contentEl.remove()
    this.contentEl = this.createContent()
    // Insert content before status if status exists
    if (this.statusEl !== null) {
      this.el.insertBefore(this.contentEl, this.statusEl)
    } else {
      this.el.appendChild(this.contentEl)
    }
  }
}
