import type { ComponentType } from 'react'
import type { FieldPath, ResolvedAnyFieldDefinition } from '@platform-modules/fields'
import type { FieldValidationIssue } from './complete-editor.js'

export interface ReactFieldSurfaceProps {
  readonly definition: ResolvedAnyFieldDefinition
  readonly value: unknown
  readonly onChange: (value: unknown) => void
  readonly path: FieldPath
  readonly inputId: string
  readonly describedBy?: string
  readonly invalid: boolean
  readonly disabled: boolean
  readonly readOnly: boolean
}
export interface ReactFieldReadOnlyProps {
  readonly definition: ResolvedAnyFieldDefinition
  readonly value: unknown
  readonly path: FieldPath
}
export interface ReactFieldSurfaceAdapter {
  readonly type: string
  readonly contractVersion: string
  readonly editor: ComponentType<ReactFieldSurfaceProps>
  readonly readOnlyDisplay: ComponentType<ReactFieldReadOnlyProps>
  readonly focusTarget: (container: HTMLElement) => HTMLElement | null
  readonly responsive: Readonly<{ fullWidth: boolean; minimumInlineSize?: number }>
  readonly a11y: Readonly<{ labelStrategy: 'field' | 'adapter'; description: string }>
}
export type ReactFieldSurfaceResolution =
  | { readonly kind: 'supported'; readonly adapter: ReactFieldSurfaceAdapter }
  | { readonly kind: 'unsupported'; readonly code: 'unsupported-surface'; readonly type: string }
export interface ReactFieldSurfaceRegistry {
  readonly version: string
  readonly types: readonly string[]
  resolve(type: string): ReactFieldSurfaceResolution
}

const CUSTOM_TYPE_RE=/^[a-z][a-z0-9-]*:[a-z][a-z0-9._-]*$/
function registryVersion(adapters:readonly ReactFieldSurfaceAdapter[]):string{return `fields-react-v1:${adapters.map((adapter)=>`${adapter.type}@${adapter.contractVersion}`).join('|')}`}

export function createReactFieldSurfaceRegistry(input:{extensions?:readonly ReactFieldSurfaceAdapter[]}={}):ReactFieldSurfaceRegistry{
  const extensions=[...(input.extensions??[])].sort((a,b)=>a.type.localeCompare(b.type)),seen=new Set<string>()
  for(const adapter of extensions){
    if(!CUSTOM_TYPE_RE.test(adapter.type))throw new TypeError(`React field surface type must be adopter-namespaced: ${adapter.type}`)
    if(!adapter.contractVersion.trim())throw new TypeError(`React field surface ${adapter.type} requires contractVersion`)
    if(seen.has(adapter.type))throw new TypeError(`Duplicate React field surface ${adapter.type}`)
    if(typeof adapter.editor!=='function'||typeof adapter.readOnlyDisplay!=='function'||typeof adapter.focusTarget!=='function')throw new TypeError(`React field surface ${adapter.type} is incomplete`)
    if(!adapter.a11y.description.trim())throw new TypeError(`React field surface ${adapter.type} requires a11y description`)
    seen.add(adapter.type)
    Object.freeze(adapter.responsive);Object.freeze(adapter.a11y);Object.freeze(adapter)
  }
  const map=new Map(extensions.map((adapter)=>[adapter.type,adapter]))
  return Object.freeze({version:registryVersion(extensions),types:Object.freeze(extensions.map((adapter)=>adapter.type)),resolve(type:string):ReactFieldSurfaceResolution{const adapter=map.get(type);return adapter?Object.freeze({kind:'supported' as const,adapter}):Object.freeze({kind:'unsupported' as const,code:'unsupported-surface' as const,type})}})
}

export interface CustomFieldSurfaceProps {
  readonly definition: ResolvedAnyFieldDefinition
  readonly value: unknown
  readonly onChange: (value: unknown) => void
  readonly path: FieldPath
  readonly errors: readonly FieldValidationIssue[]
  readonly registry?: ReactFieldSurfaceRegistry
  readonly inputId: string
  readonly disabled: boolean
  readonly readOnly: boolean
}
export function CustomFieldSurface({definition,value,onChange,path,errors,registry,inputId,disabled,readOnly}:CustomFieldSurfaceProps){
  const resolution=registry?.resolve(definition.type)??{kind:'unsupported' as const,code:'unsupported-surface' as const,type:definition.type}
  if(resolution.kind==='unsupported')return <div role="alert" tabIndex={0} data-field-surface-error={resolution.code}>Unsupported React surface for {resolution.type}</div>
  const adapter=resolution.adapter,fieldErrors=errors.filter((issue)=>JSON.stringify(issue.path)===JSON.stringify(path)),errorId=fieldErrors.length?`${inputId}-error`:undefined,Editor=adapter.editor,ReadOnly=adapter.readOnlyDisplay
  return <div data-custom-field-type={definition.type} data-responsive-width={adapter.responsive.fullWidth?'full':'auto'} style={{containerType:'inline-size'}}>
    {adapter.a11y.labelStrategy==='field'?<label htmlFor={inputId}>{definition.label}{definition.required?' *':''}</label>:null}
    {readOnly?<ReadOnly definition={definition} value={value} path={path}/>:<Editor definition={definition} value={value} onChange={onChange} path={path} inputId={inputId} describedBy={errorId} invalid={fieldErrors.length>0} disabled={disabled} readOnly={readOnly}/>}
    {fieldErrors.length?<div id={errorId} role="alert" tabIndex={0}>{fieldErrors.map((issue)=><div key={`${issue.code??'validation'}:${issue.message}`}>{issue.message}</div>)}</div>:null}
  </div>
}
