/**
 * Direction - RTL/LTR direction wrapper utility
 * @countermeasure/web-components/form/direction
 */

import { resolveContainer } from '../../primitives/utils'

export type DirectionValue = 'ltr' | 'rtl' | 'auto'

export interface DirectionConfig {
  container: HTMLElement | string
  direction?: DirectionValue
  onChange?: (direction: string) => void
}

export class Direction {
  private readonly container: HTMLElement
  private readonly config: DirectionConfig
  private observer: MutationObserver | null = null

  constructor(config: DirectionConfig) {
    this.container = resolveContainer(config.container)
    this.config = config

    if (config.direction !== undefined) {
      this.container.setAttribute('dir', config.direction)
    }

    this.observeRootChanges()
  }

  /** Set the direction on the container */
  setDirection(dir: DirectionValue): void {
    this.container.setAttribute('dir', dir)
    this.config.onChange?.(dir)
  }

  /** Get the current computed direction */
  getDirection(): string {
    return this.container.getAttribute('dir') ?? getComputedStyle(this.container).direction
  }

  /** Clean up the mutation observer */
  destroy(): void {
    if (this.observer !== null) {
      this.observer.disconnect()
      this.observer = null
    }
  }

  /** Observe changes to dir attribute on html or body elements */
  private observeRootChanges(): void {
    const htmlEl = document.documentElement
    const bodyEl = document.body

    this.observer = new MutationObserver(() => {
      const resolved = this.getDirection()
      this.config.onChange?.(resolved)
    })

    this.observer.observe(htmlEl, { attributes: true, attributeFilter: ['dir'] })
    this.observer.observe(bodyEl, { attributes: true, attributeFilter: ['dir'] })
  }
}
