/**
 * LogToolbar component - search, follow, wrap, copy, download controls for log viewers
 * @countermeasure/web-components/components/log-toolbar
 */

export interface LogToolbarConfig {
  container: HTMLElement | string
  /** Callback when search query changes (debounced) */
  onSearch?: (query: string) => void
  /** Callback when follow mode toggles */
  onFollowChange?: (enabled: boolean) => void
  /** Callback when word-wrap toggles */
  onWrapChange?: (enabled: boolean) => void
  /** Callback to get text for copy/download */
  getText?: () => string
  /** File name stem for downloads (without extension) */
  downloadName?: string
  /** Initial follow state */
  follow?: boolean
  /** Initial wrap state */
  wrap?: boolean
  /** Search debounce in ms */
  debounceMs?: number
}

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

export class LogToolbar {
  private readonly containerEl: HTMLElement
  private readonly rootEl: HTMLElement
  private readonly searchEl: HTMLInputElement
  private readonly followBtn: HTMLButtonElement
  private readonly wrapBtn: HTMLButtonElement
  private readonly copyBtn: HTMLButtonElement
  private readonly downloadBtn: HTMLButtonElement
  private follow: boolean
  private wrap: boolean
  private debounceTimer: ReturnType<typeof setTimeout> | null = null
  private destroyed = false
  private config: LogToolbarConfig

  constructor(config: LogToolbarConfig) {
    this.config = config
    this.containerEl = resolveContainer(config.container)
    this.follow = config.follow ?? true
    this.wrap = config.wrap ?? true

    this.rootEl = document.createElement('div')
    this.rootEl.className = 'cmm-log-toolbar'

    // Search
    this.searchEl = document.createElement('input')
    this.searchEl.type = 'text'
    this.searchEl.className = 'cmm-log-toolbar__search'
    this.searchEl.placeholder = 'Search logs...'
    this.searchEl.addEventListener('input', this.handleSearch)
    this.rootEl.appendChild(this.searchEl)

    // Follow
    this.followBtn = this.createToggle('Follow', this.follow, this.handleFollow)
    this.rootEl.appendChild(this.followBtn)

    // Wrap
    this.wrapBtn = this.createToggle('Wrap', this.wrap, this.handleWrap)
    this.rootEl.appendChild(this.wrapBtn)

    // Copy
    this.copyBtn = document.createElement('button')
    this.copyBtn.className = 'cmm-log-toolbar__btn'
    this.copyBtn.textContent = 'Copy'
    this.copyBtn.addEventListener('click', this.handleCopy)
    this.rootEl.appendChild(this.copyBtn)

    // Download
    this.downloadBtn = document.createElement('button')
    this.downloadBtn.className = 'cmm-log-toolbar__btn'
    this.downloadBtn.textContent = 'Download'
    this.downloadBtn.addEventListener('click', this.handleDownload)
    this.rootEl.appendChild(this.downloadBtn)

    this.containerEl.appendChild(this.rootEl)
  }

  getSearchQuery(): string {
    return this.searchEl.value
  }

  getFollowEnabled(): boolean {
    return this.follow
  }

  setFollow(enabled: boolean): void {
    this.follow = enabled
    this.followBtn.classList.toggle('cmm-log-toolbar__btn--active', enabled)
    this.followBtn.setAttribute('aria-pressed', String(enabled))
  }

  setWrap(enabled: boolean): void {
    this.wrap = enabled
    this.wrapBtn.classList.toggle('cmm-log-toolbar__btn--active', enabled)
  }

  destroy(): void {
    if (this.destroyed) return
    this.destroyed = true
    if (this.debounceTimer !== null) clearTimeout(this.debounceTimer)
    this.searchEl.removeEventListener('input', this.handleSearch)
    this.followBtn.removeEventListener('click', this.handleFollow)
    this.wrapBtn.removeEventListener('click', this.handleWrap)
    this.copyBtn.removeEventListener('click', this.handleCopy)
    this.downloadBtn.removeEventListener('click', this.handleDownload)
    if (this.rootEl.parentNode) this.rootEl.parentNode.removeChild(this.rootEl)
  }

  private createToggle(label: string, initial: boolean, handler: () => void): HTMLButtonElement {
    const btn = document.createElement('button')
    btn.className = 'cmm-log-toolbar__btn'
    if (initial) btn.classList.add('cmm-log-toolbar__btn--active')
    btn.textContent = label
    btn.setAttribute('aria-pressed', String(initial))
    btn.addEventListener('click', handler)
    return btn
  }

  private readonly handleSearch = (): void => {
    if (this.debounceTimer !== null) clearTimeout(this.debounceTimer)
    this.debounceTimer = setTimeout(() => {
      this.config.onSearch?.(this.searchEl.value)
    }, this.config.debounceMs ?? 150)
  }

  private readonly handleFollow = (): void => {
    this.follow = !this.follow
    this.followBtn.classList.toggle('cmm-log-toolbar__btn--active', this.follow)
    this.followBtn.setAttribute('aria-pressed', String(this.follow))
    this.config.onFollowChange?.(this.follow)
  }

  private readonly handleWrap = (): void => {
    this.wrap = !this.wrap
    this.wrapBtn.classList.toggle('cmm-log-toolbar__btn--active', this.wrap)
    this.config.onWrapChange?.(this.wrap)
  }

  private readonly handleCopy = (): void => {
    const text = this.config.getText?.() ?? ''
    void navigator.clipboard
      .writeText(text)
      .then(() => {
        this.copyBtn.textContent = 'Copied!'
        this.copyBtn.classList.add('cmm-log-toolbar__btn--copied')
        setTimeout(() => {
          if (!this.destroyed) {
            this.copyBtn.textContent = 'Copy'
            this.copyBtn.classList.remove('cmm-log-toolbar__btn--copied')
          }
        }, 2000)
      })
      .catch(() => {})
  }

  private readonly handleDownload = (): void => {
    const text = this.config.getText?.() ?? ''
    const blob = new Blob([text], { type: 'text/plain' })
    const url = URL.createObjectURL(blob)
    const a = document.createElement('a')
    a.href = url
    a.download = `${this.config.downloadName ?? 'logs'}.log`
    a.style.display = 'none'
    document.body.appendChild(a)
    a.click()
    a.remove()
    setTimeout(() => {
      URL.revokeObjectURL(url)
    }, 0)
  }
}
