/**
 * Card - Generic card container with header, body, and footer sections
 * @countermeasure/web-components/display/card
 */

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

export type { CardConfig } from './types'

export class Card {
  public readonly el: HTMLDivElement

  private readonly cardId: string
  private headerEl: HTMLDivElement | null = null
  private bodyEl: HTMLDivElement | null = null
  private footerEl: HTMLDivElement | null = null
  private readonly clickHandler: (() => void) | undefined
  private readonly keydownHandler: ((e: KeyboardEvent) => void) | null = null

  constructor(config: CardConfig) {
    this.cardId = uniqueId('cmm-card')
    this.clickHandler = config.onClick

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

    // Create header if provided
    if (config.header !== undefined) {
      this.headerEl = this.createSection('cmm-card__header', config.header)
      this.el.appendChild(this.headerEl)
    }

    // Create body if provided
    if (config.body !== undefined) {
      this.bodyEl = this.createSection('cmm-card__body', config.body)
      this.el.appendChild(this.bodyEl)
    }

    // Create footer if provided
    if (config.footer !== undefined) {
      this.footerEl = this.createSection('cmm-card__footer', config.footer)
      this.el.appendChild(this.footerEl)
    }

    // Set up click handling
    if (this.clickHandler !== undefined) {
      this.el.setAttribute('role', 'button')
      this.el.setAttribute('tabindex', '0')
      this.el.classList.add('cmm-card--clickable')
      this.el.addEventListener('click', this.clickHandler)

      const keyHandler = (e: KeyboardEvent) => {
        if (e.key === 'Enter' || e.key === ' ') {
          e.preventDefault()
          if (this.clickHandler !== undefined) {
            this.clickHandler()
          }
        }
      }
      this.keydownHandler = keyHandler
      this.el.addEventListener('keydown', keyHandler)
    }

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

  /** Update the card header content */
  setHeader(content: string | HTMLElement): void {
    if (this.headerEl !== null) {
      this.setSectionContent(this.headerEl, content)
    } else {
      this.headerEl = this.createSection('cmm-card__header', content)
      this.el.insertBefore(this.headerEl, this.el.firstChild)
    }
  }

  /** Update the card body content */
  setBody(content: string | HTMLElement): void {
    if (this.bodyEl !== null) {
      this.setSectionContent(this.bodyEl, content)
    } else {
      this.bodyEl = this.createSection('cmm-card__body', content)
      if (this.footerEl !== null) {
        this.el.insertBefore(this.bodyEl, this.footerEl)
      } else {
        this.el.appendChild(this.bodyEl)
      }
    }
  }

  /** Update the card footer content */
  setFooter(content: string | HTMLElement): void {
    if (this.footerEl !== null) {
      this.setSectionContent(this.footerEl, content)
    } else {
      this.footerEl = this.createSection('cmm-card__footer', content)
      this.el.appendChild(this.footerEl)
    }
  }

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

  private buildClassName(config: CardConfig): string {
    const classes = ['cmm-card']

    if (config.hoverable === true) {
      classes.push('cmm-card--hoverable')
    }

    if (config.bordered === false) {
      classes.push('cmm-card--no-border')
    }

    if (config.padding === false) {
      classes.push('cmm-card--no-padding')
    }

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

    return classes.join(' ')
  }

  private createSection(className: string, content: string | HTMLElement): HTMLDivElement {
    const section = document.createElement('div')
    section.className = className
    this.setSectionContent(section, content)
    return section
  }

  private setSectionContent(section: HTMLDivElement, content: string | HTMLElement): void {
    // Clear existing content safely
    section.textContent = ''

    if (typeof content === 'string') {
      // Use textContent for string content to prevent XSS
      section.textContent = content
    } else {
      section.appendChild(content)
    }
  }
}
