/**
 * Textarea - Multi-line text input component
 * @countermeasure/web-components/primitives/input
 */

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

export class Textarea {
  public readonly el: HTMLDivElement
  public readonly textareaEl: HTMLTextAreaElement

  private readonly textareaId: string
  private countEl: HTMLSpanElement | null = null
  private readonly maxLength: number | undefined
  private readonly autoResize: boolean
  private readonly handlers: {
    input: () => void
    change: () => void
    focus: () => void
    blur: () => void
  }

  constructor(config: TextareaConfig) {
    this.textareaId = uniqueId('cmm-textarea')
    this.maxLength = config.maxLength
    this.autoResize = config.autoResize === true

    // Create wrapper
    this.el = document.createElement('div')
    this.el.className = 'cmm-textarea-wrapper'

    if (config.className) {
      this.el.classList.add(config.className)
    }

    // Create textarea
    this.textareaEl = document.createElement('textarea')
    this.textareaEl.id = this.textareaId
    this.textareaEl.className = 'cmm-textarea'

    if (config.placeholder !== undefined) {
      this.textareaEl.placeholder = config.placeholder
    }

    if (config.value !== undefined) {
      this.textareaEl.value = config.value
    }

    if (config.disabled === true) {
      this.textareaEl.disabled = true
    }

    if (config.readOnly === true) {
      this.textareaEl.readOnly = true
    }

    if (config.required === true) {
      this.textareaEl.required = true
      this.textareaEl.setAttribute('aria-required', 'true')
    }

    if (config.rows !== undefined) {
      this.textareaEl.rows = config.rows
    }

    if (this.maxLength !== undefined) {
      this.textareaEl.maxLength = this.maxLength
    }

    if (config.name !== undefined) {
      this.textareaEl.name = config.name
    }

    if (config.ariaLabel !== undefined) {
      this.textareaEl.setAttribute('aria-label', config.ariaLabel)
    }

    this.el.appendChild(this.textareaEl)

    // Character count display
    if (this.maxLength !== undefined) {
      this.countEl = document.createElement('span')
      this.countEl.className = 'cmm-textarea__count'
      this.updateCharCount()
      this.el.appendChild(this.countEl)
    }

    // Event handlers
    this.handlers = {
      input: () => {
        if (this.autoResize) {
          this.adjustHeight()
        }
        if (this.countEl !== null) {
          this.updateCharCount()
        }
        config.onInput?.(this.textareaEl.value)
      },
      change: () => {
        config.onChange?.(this.textareaEl.value)
      },
      focus: () => {
        config.onFocus?.()
      },
      blur: () => {
        config.onBlur?.()
      },
    }

    this.textareaEl.addEventListener('input', this.handlers.input)
    this.textareaEl.addEventListener('change', this.handlers.change)
    this.textareaEl.addEventListener('focus', this.handlers.focus)
    this.textareaEl.addEventListener('blur', this.handlers.blur)

    // Apply initial auto-resize
    if (this.autoResize && config.value !== undefined) {
      this.adjustHeight()
    }

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

  /** Get the current textarea value */
  getValue(): string {
    return this.textareaEl.value
  }

  /** Set the textarea value */
  setValue(value: string): void {
    this.textareaEl.value = value
    if (this.autoResize) {
      this.adjustHeight()
    }
    if (this.countEl !== null) {
      this.updateCharCount()
    }
  }

  /** Toggle the disabled state */
  setDisabled(disabled: boolean): void {
    this.textareaEl.disabled = disabled
  }

  /** Toggle the error state */
  setError(error: boolean): void {
    if (error) {
      this.textareaEl.classList.add('cmm-textarea--error')
      this.textareaEl.setAttribute('aria-invalid', 'true')
    } else {
      this.textareaEl.classList.remove('cmm-textarea--error')
      this.textareaEl.removeAttribute('aria-invalid')
    }
  }

  /** Remove from the DOM and clean up event listeners */
  destroy(): void {
    this.textareaEl.removeEventListener('input', this.handlers.input)
    this.textareaEl.removeEventListener('change', this.handlers.change)
    this.textareaEl.removeEventListener('focus', this.handlers.focus)
    this.textareaEl.removeEventListener('blur', this.handlers.blur)
    this.el.remove()
  }

  private adjustHeight(): void {
    this.textareaEl.style.height = 'auto'
    this.textareaEl.style.height = `${String(this.textareaEl.scrollHeight)}px`
  }

  private updateCharCount(): void {
    if (this.countEl !== null && this.maxLength !== undefined) {
      this.countEl.textContent = `${String(this.textareaEl.value.length)}/${String(this.maxLength)}`
    }
  }
}
