// Field Plugin System
// - RecordInitPlugin: 记录初始化
// - FieldWatchPlugin: 字段值变化监听
// - FieldConfigPlugin: 字段配置

// ============================================
// FieldWatchPlugin - 字段值变化监听
// ============================================
export interface FieldWatchContext {
  fieldname: string
  value: any
  oldValue: any
  record: Record<string, any>
  parentDoc?: Record<string, any>
  entity: string
  pagetype: string
}

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

// ============================================
// FieldConfigPlugin - 字段配置
// ============================================
export interface FieldDefinition {
  fieldname: string
  fieldtype: string
  label?: string
  options?: string
  hidden?: boolean
  read_only?: boolean
  reqd?: boolean
  default?: any
  description?: string
  [key: string]: any
}

export interface FieldConfigContext {
  field: FieldDefinition
  record: Record<string, any>
  pagetype: string
  setOptions: (options: string[]) => void
  setProperty: (key: string, value: any) => void
  setDefaultValue: (value: any) => void
}

export interface FieldConfigPlugin {
  pagetype: string | string[]
  fieldname: string | string[]
  config: (ctx: FieldConfigContext) => void | Promise<void>
  defaultValue?: any | ((ctx: Omit<FieldConfigContext, 'setDefaultValue'>) => any)
}

// ============================================
// RecordInitPlugin - 记录初始化
// ============================================
export interface RecordInitPlugin {
  pagetype: string | string[]
  handler: (record: Record<string, any>, pagetype: string) => void | Promise<void>
}

type PluginEntry = {
  plugin: FieldWatchPlugin
  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[] = []

// Field config plugins registry
const fieldConfigPlugins: FieldConfigPlugin[] = []

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

// Register a pagetype-specific plugin
export function registerPagetypePlugin(pagetype: string, plugin: FieldWatchPlugin): 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)
}

// Register a field config plugin
export function registerFieldConfigPlugin(plugin: FieldConfigPlugin): void {
  fieldConfigPlugins.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 watch plugins
export async function triggerFieldWatch(
  pagetype: string,
  context: FieldWatchContext
): 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(`[FieldWatchPlugin] Error in plugin for "${context.fieldname}":`, err)
      }
    }
  }
}

// Trigger field config plugins - 返回配置后的字段选项
export async function triggerFieldConfig(
  pagetype: string,
  field: FieldDefinition,
  record: Record<string, any>
): Promise<FieldDefinition> {
  const result = { ...field }
  
  for (const plugin of fieldConfigPlugins) {
    if (!matchesPagetype(plugin.pagetype, pagetype)) continue
    
    const fieldnames = typeof plugin.fieldname === 'string' ? [plugin.fieldname] : plugin.fieldname
    if (!fieldnames.includes(field.fieldname)) continue
    
    try {
      await plugin.config({
        field: result,
        record,
        pagetype,
        setOptions: (options: string[]) => { result.options = options.join('\n') },
        setProperty: (key: string, value: any) => { result[key] = value },
        setDefaultValue: (value: any) => { if (record[field.fieldname] === undefined) record[field.fieldname] = value }
      })
      
      // 处理 defaultValue 配置
      if (plugin.defaultValue !== undefined && record[field.fieldname] === undefined) {
        record[field.fieldname] = typeof plugin.defaultValue === 'function' 
          ? await plugin.defaultValue({ field: result, record, pagetype })
          : plugin.defaultValue
      }
    } catch (err) {
      console.error(`[FieldConfigPlugin] Error in plugin for "${pagetype}.${field.fieldname}":`, err)
    }
  }
  
  return result
}

// 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 triggerFieldWatch(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 }
}
