// Field Change Plugin System
// Supports both global plugins and pagetype-specific plugins
// Also supports RecordInitPlugin for initializing new records

export interface FieldChangeContext {
  fieldname: string
  value: any
  oldValue: any
  record: Record<string, any>
  parentDoc?: Record<string, any>
  entity: string
  pagetype: string
}

export interface FieldChangePlugin {
  fieldname: string | string[] | RegExp
  handler: (ctx: FieldChangeContext) => void | Promise<void>
}

// Record Init Plugin - called when creating a new record
export interface RecordInitPlugin {
  pagetype: string | string[]
  handler: (record: Record<string, any>, pagetype: string) => void | Promise<void>
}

type PluginEntry = {
  plugin: FieldChangePlugin
  source: string // 'global' | pagetype name
}

// Global plugins registry
const globalPlugins: PluginEntry[] = []

// Pagetype-specific plugins registry: pagetype -> plugins
const pagetypePlugins: Map<string, PluginEntry[]> = new Map()

// Record init plugins registry
const recordInitPlugins: RecordInitPlugin[] = []

// Register a global plugin
export function registerGlobalPlugin(plugin: FieldChangePlugin): void {
  globalPlugins.push({ plugin, source: 'global' })
}

// Register a pagetype-specific plugin
export function registerPagetypePlugin(pagetype: string, plugin: FieldChangePlugin): void {
  const key = pagetype.toLowerCase().replace(/[-\s]+/g, '_')
  if (!pagetypePlugins.has(key)) {
    pagetypePlugins.set(key, [])
  }
  pagetypePlugins.get(key)!.push({ plugin, source: pagetype })
}

// Register a record init plugin
export function registerRecordInitPlugin(plugin: RecordInitPlugin): void {
  recordInitPlugins.push(plugin)
}

// Match pagetype against plugin pattern
function matchesPagetype(pattern: string | string[], pagetype: string): boolean {
  const key = pagetype.toLowerCase().replace(/[-\s]+/g, '_')
  if (typeof pattern === 'string') {
    return pattern.toLowerCase().replace(/[-\s]+/g, '_') === key
  }
  if (Array.isArray(pattern)) {
    return pattern.some(p => p.toLowerCase().replace(/[-\s]+/g, '_') === key)
  }
  return false
}

// Trigger record init plugins
export async function triggerRecordInit(
  pagetype: string,
  record: Record<string, any>
): Promise<void> {
  for (const plugin of recordInitPlugins) {
    if (matchesPagetype(plugin.pagetype, pagetype)) {
      try {
        await plugin.handler(record, pagetype)
      } catch (err) {
        console.error(`[RecordInitPlugin] Error in plugin for "${pagetype}":`, err)
      }
    }
  }
}

// Match fieldname against plugin pattern
function matchesFieldname(pattern: string | string[] | RegExp, fieldname: string): boolean {
  if (typeof pattern === 'string') {
    return pattern === fieldname
  }
  if (Array.isArray(pattern)) {
    return pattern.includes(fieldname)
  }
  if (pattern instanceof RegExp) {
    return pattern.test(fieldname)
  }
  return false
}

// Trigger field change plugins
export async function triggerFieldChange(
  pagetype: string,
  context: FieldChangeContext
): Promise<void> {
  const key = pagetype.toLowerCase().replace(/[-\s]+/g, '_')
  const plugins: PluginEntry[] = [
    ...globalPlugins,
    ...(pagetypePlugins.get(key) || [])
  ]

  for (const entry of plugins) {
    if (matchesFieldname(entry.plugin.fieldname, context.fieldname)) {
      try {
        await entry.plugin.handler(context)
      } catch (err) {
        console.error(`[FieldPlugin] Error in plugin for "${context.fieldname}":`, err)
      }
    }
  }
}

// Safely extract plain object from Vue reactive proxy
function toPlainObject(obj: any, depth = 0): Record<string, any> {
  if (!obj || depth > 3) return {}
  if (typeof obj !== 'object') return obj
  
  const result: Record<string, any> = Array.isArray(obj) ? [] : {}
  
  try {
    const keys = Object.keys(obj)
    for (const key of keys) {
      // Skip Vue internal properties
      if (key.startsWith('__') || key.startsWith('_')) continue
      
      const val = obj[key]
      if (val === null || val === undefined) {
        result[key] = val
      } else if (typeof val === 'object') {
        result[key] = toPlainObject(val, depth + 1)
      } else {
        result[key] = val
      }
    }
  } catch {
    // Ignore errors
  }
  
  return result
}

// Create a bound trigger function for a specific pagetype
export function createFieldChangeTrigger(pagetype: string, parentDoc?: any) {
  return async (
    fieldname: string,
    value: any,
    oldValue: any,
    record: Record<string, any>
  ) => {
    await triggerFieldChange(pagetype, {
      fieldname,
      value,
      oldValue,
      record, // Keep original reference for UI reactivity
      parentDoc: toPlainObject(parentDoc?.value || parentDoc),
      entity: pagetype,
      pagetype
    })
  }
}

// Composable for Vue components
export function useFieldPlugins(pagetype: string, parentDoc?: Record<string, any>) {
  const onFieldChange = createFieldChangeTrigger(pagetype, parentDoc)
  return { onFieldChange }
}
