/**
 * CopyButton component
 * @countermeasure/web-components/components/copy-button
 */

export interface CopyButtonConfig {
  /** Container element (or selector) the button is mounted into. */
  container: HTMLElement | string
  /** Function that returns the text to copy. Called on each click. */
  getText: () => string
  /**
   * Default button label.
   * @default 'Copy'
   */
  label?: string
  /**
   * Label shown briefly after a successful copy.
   * @default 'Copied!'
   */
  copiedLabel?: string
  /**
   * Duration in milliseconds the `copiedLabel` is displayed.
   * @default 2000
   */
  copiedDuration?: number
}

function resolveContainer(container: HTMLElement | string): HTMLElement {
  if (typeof container === 'string') {
    const el = document.querySelector(container)
    if (!el) {
      throw new Error(`CopyButton: container not found for selector "${container}"`)
    }
    return el as HTMLElement
  }
  return container
}

export class CopyButton {
  private readonly config: CopyButtonConfig
  private readonly containerEl: HTMLElement
  private readonly buttonEl: HTMLButtonElement
  private readonly defaultLabel: string
  private readonly copiedLabel: string
  private readonly copiedDuration: number
  private resetTimer: ReturnType<typeof setTimeout> | null = null
  private destroyed = false

  constructor(config: CopyButtonConfig) {
    this.config = config
    this.containerEl = resolveContainer(config.container)
    this.defaultLabel = config.label ?? 'Copy'
    this.copiedLabel = config.copiedLabel ?? 'Copied!'
    this.copiedDuration = config.copiedDuration ?? 2000

    this.buttonEl = document.createElement('button')
    this.buttonEl.className = 'cmm-copy-button'
    this.buttonEl.textContent = this.defaultLabel
    this.buttonEl.addEventListener('click', this.handleClick)

    this.containerEl.appendChild(this.buttonEl)
  }

  destroy(): void {
    if (this.destroyed) {
      return
    }
    this.destroyed = true

    if (this.resetTimer !== null) {
      clearTimeout(this.resetTimer)
    }

    this.buttonEl.removeEventListener('click', this.handleClick)

    if (this.buttonEl.parentNode) {
      this.buttonEl.parentNode.removeChild(this.buttonEl)
    }
  }

  private readonly handleClick = (): void => {
    const text = this.config.getText()
    void this.copyToClipboard(text)
  }

  private async copyToClipboard(text: string): Promise<void> {
    try {
      await navigator.clipboard.writeText(text)
      this.showCopiedFeedback()
    } catch {
      // Clipboard API not available or permission denied
    }
  }

  private showCopiedFeedback(): void {
    if (this.resetTimer !== null) {
      clearTimeout(this.resetTimer)
    }

    this.buttonEl.textContent = this.copiedLabel
    this.buttonEl.classList.add('cmm-copy-button--copied')

    this.resetTimer = setTimeout(() => {
      if (!this.destroyed) {
        this.buttonEl.textContent = this.defaultLabel
        this.buttonEl.classList.remove('cmm-copy-button--copied')
      }
      this.resetTimer = null
    }, this.copiedDuration)
  }
}
