/**
 * CodeEditor React wrapper — Lane A imperative wrap over src/editors/code-editor.ts
 *
 * Import from the dedicated subpath to keep CodeMirror out of the main bundle:
 *   import { CodeEditor } from '@countermeasure-platform/web-components/react/editors/code-editor'
 *
 * API is hybrid controlled/uncontrolled:
 *   - `defaultValue` seeds the editor on mount (uncontrolled, common case)
 *   - `value` + `onChange` enable controlled mode
 *
 * Programmatic `setValue` calls are guarded with `isUpdatingFromProps` so they
 * do not echo back through `onChange` and trigger infinite update loops.
 */

import * as React from 'react'
import { cn } from '../primitives/utils'
import { CodeEditor as CodeEditorImpl } from '../../editors/code-editor'
import type { CodeEditorConfig, AutocompleteSchema, ValidationConfig } from '../../editors/types'

export interface CodeEditorProps extends Omit<
  CodeEditorConfig,
  'container' | 'value' | 'onChange'
> {
  /** Uncontrolled initial value. Ignored once `value` is provided. */
  defaultValue?: string
  /** Controlled value. When provided the editor reflects this string. */
  value?: string
  /** Fires on every user-initiated change. Required for controlled mode. */
  onChange?: (value: string) => void
  className?: string
}

export type { AutocompleteSchema, ValidationConfig }

function CodeEditor({ defaultValue, value, onChange, className, ...config }: CodeEditorProps) {
  const containerRef = React.useRef<HTMLDivElement>(null)
  const editorRef = React.useRef<CodeEditorImpl | null>(null)
  /** Guards against re-firing onChange when we programmatically call setValue */
  const isUpdatingFromProps = React.useRef(false)
  /** Always-current onChange reference so the mount closure never goes stale */
  const onChangeRef = React.useRef(onChange)
  onChangeRef.current = onChange

  // Construct once on mount — SSR-safe
  React.useEffect(() => {
    if (typeof document === 'undefined' || !containerRef.current) return
    const initial = value ?? defaultValue ?? ''
    editorRef.current = new CodeEditorImpl({
      ...config,
      container: containerRef.current,
      value: initial,
      onChange: (next: string) => {
        if (isUpdatingFromProps.current) return
        onChangeRef.current?.(next)
      },
    })
    return () => {
      editorRef.current?.destroy()
      editorRef.current = null
    }
  }, [])

  // Sync controlled value into the editor without re-firing onChange
  React.useEffect(() => {
    const editor = editorRef.current
    if (!editor || value === undefined) return
    if (editor.getValue() === value) return
    isUpdatingFromProps.current = true
    editor.setValue(value)
    isUpdatingFromProps.current = false
  }, [value])

  return <div ref={containerRef} data-slot="code-editor" className={cn('w-full', className)} />
}

CodeEditor.displayName = 'CodeEditor'

export { CodeEditor }
