/**
 * 步骤描述解析工具函数
 *
 * 提供步骤描述到自动化动作的推断转换功能。
 * 根据自然语言步骤描述（如"输入用户名""点击登录按钮"），
 * 自动推断动作类型（action）和动作参数（params）。
 *
 * @module utils/stepParser
 * @author czj
 * @date 2026-07-29
 */

/** 意图步骤数据结构（前端编辑器使用） */
export interface IntentStep {
  order: number
  description: string
  expected: string
  actual: string
  waitAfter: number
  locatorType: string
  locatorValue: string
  /** 阶段 6：round-trip 保留的语义字段（编辑回显不丢） */
  semantic?: Record<string, any>
  verify?: Record<string, any>
  run_on?: string
}

/** 意图步骤编辑器 emit 事件 */
export interface IntentStepEditorEmits {
  (e: 'update:modelValue', value: IntentStep[]): void
  (e: 'locate', index: number): void
}

/**
 * 根据步骤描述自动推断动作类型
 *
 * @param description - 步骤描述文本，如"输入用户名"
 * @returns 动作类型，如 fill / click / navigate 等
 *
 * @example
 * inferAction('输入用户名')   // => 'fill'
 * inferAction('点击登录')     // => 'click'
 * inferAction('打开首页')     // => 'navigate'
 */
export function inferAction(description: string): string {
  const desc = description.toLowerCase()

  if (/打开|导航|访问|进入|跳转|前往/.test(desc)) return 'navigate'
  if (/点击|按下|选择|单击|双击/.test(desc)) return 'click'
  if (/输入|填写|填入|键入|写入/.test(desc)) return 'fill'
  if (/选择|下拉|选取/.test(desc)) return 'select'
  if (/悬停|鼠标移入|hover/.test(desc)) return 'hover'
  if (/等待|延时|等待元素/.test(desc)) return 'wait'
  if (/滚动|滑动|滚到/.test(desc)) return 'scroll'
  if (/按键盘|按|按键|按下.*键/.test(desc)) return 'press'
  if (/勾选|选中|勾上/.test(desc)) return 'check'
  if (/取消勾选|取消选中|取消勾/.test(desc)) return 'uncheck'
  if (/断言|验证|检查|确认|判断|检测/.test(desc)) return 'assert'
  if (/截图|截屏|屏幕截图/.test(desc)) return 'screenshot'

  return 'click' // 默认动作
}

/**
 * 推断动作参数
 *
 * 根据步骤描述和定位值，推断出动作所需的参数。
 * 如 fill 动作需要 selector + value，navigate 需要 url 等。
 *
 * @param description - 步骤描述文本
 * @param locatorValue - 定位值（如 #username）
 * @returns 动作参数字典
 *
 * @example
 * inferParams('输入 admin', '#username')
 * // => { selector: '#username', value: 'admin' }
 */
export function inferParams(description: string, locatorValue: string): Record<string, any> {
  const action = inferAction(description)
  const params: Record<string, any> = {}

  // 需要选择器的动作
  if (['click', 'fill', 'select', 'hover', 'wait', 'check', 'uncheck', 'press'].includes(action)) {
    if (locatorValue) params.selector = locatorValue
  }

  // fill 需要值：从描述提取如"输入 admin" → value="admin"
  if (action === 'fill') {
    const match = description.match(/输入["「『""]?(.+?)["」』""]?$/)
    if (match) params.value = match[1]
  }

  // navigate 需要 URL
  if (action === 'navigate') {
    const match = description.match(/https?:\/\/[^\s]+/)
    if (match) params.url = match[0]
  }

  // assert 需要推断断言类型
  if (action === 'assert') {
    if (/可见|显示|出现/.test(description)) {
      params.type = 'visible'
      params.expected = description.replace(/断言|验证|检查/gi, '').trim()
    } else if (/隐藏|消失|不可见/.test(description)) {
      params.type = 'hidden'
    } else if (/包含|含有/.test(description)) {
      params.type = 'contains'
    } else if (/相等|等于|是/.test(description)) {
      params.type = 'text'
    } else {
      params.type = 'visible' // 默认断言可见
      params.expected = description.replace(/断言|验证|检查/gi, '').trim()
    }
  }

  // scroll 需要方向
  if (action === 'scroll') {
    params.direction = /向上|上滑/.test(description) ? 'up' : 'down'
    params.distance = 300
  }

  return params
}

/**
 * 从自然语言描述推断语义目标（semantic）
 *
 * 阶段 6：意图模式步骤转换时，若未显式指定定位器，则附带语义目标，
 * 让执行期走 deterministic 的语义解析（映射表 v2 / 模式选择器），
 * 替代不稳定的人工/AI 定位。有显式 locator 的步骤不推断（避免覆盖）。
 *
 * @param description - 步骤描述，如「点击【登录】按钮」「输入 用户名」
 * @returns SemanticTarget 或 null
 */
export function inferSemantic(description: string): Record<string, any> | null {
  const desc = description.trim()
  if (!desc) return null

  // 提取带引号的业务文本：点击「X」/ 输入【X】/ 勾选"X" 等
  const quoted = desc.match(/["「『"](.+?)["」』"]/)
  const targetText = quoted ? quoted[1] : desc.replace(/^(请|帮我|点击|单击|输入|填写|键入|填入|勾选|选中|切换|选择|打开|进入|访问)\s*/, '')

  if (/输入|填写|填入|键入|写入/.test(desc)) {
    return { type: 'input', text: targetText || '' }
  }
  if (/勾选|选中|勾上/.test(desc)) {
    return { type: 'checkbox', text: targetText || '' }
  }
  if (/切换|切换到/.test(desc)) {
    return { type: 'tab', text: targetText || '' }
  }
  if (/点击|单击|按下|选择/.test(desc)) {
    return { type: 'button', text: targetText || '' }
  }
  return null
}

/**
 * 将意图步骤转换为 StepDefinition 格式
 *
 * 根据步骤描述自动推断 action 和 params，
 * 并将 locator_type / locator_value 同步到 params.selector。
 *
 * 阶段 6 增强：步骤无显式定位器时附带 semantic 语义目标；
 * 保留步骤自带 semantic / verify / run_on（round-trip 安全）。
 *
 * @param step - 意图步骤数据
 * @returns 标准 StepDefinition 格式
 *
 * @example
 * toStepDefinition({
 *   order: 1, description: '输入用户名',
 *   expected: '', actual: '', waitAfter: 0,
 *   locatorType: 'css', locatorValue: '#username'
 * })
 * // => { order: 1, name: '输入用户名', action: 'fill', params: { selector: '#username' }, ... }
 */
export function toStepDefinition(step: IntentStep & {
  semantic?: Record<string, any>
  verify?: Record<string, any>
  run_on?: string
}): Record<string, any> {
  const action = inferAction(step.description)
  const params = inferParams(step.description, step.locatorValue)

  // 如果有 locator_value，自动同步到 params.selector
  if (step.locatorValue && !params.selector) {
    params.selector = step.locatorValue
  }

  const result: Record<string, any> = {
    order: step.order,
    name: step.description,
    action,
    params,
    expected: step.expected || '',
    actual: step.actual || '',
    waitAfter: step.waitAfter || 0,
    locator_type: step.locatorType || '',
    locator_value: step.locatorValue || '',
  }

  // 阶段 6：无显式定位器时推断语义目标；否则保留步骤自带字段
  if (step.semantic && typeof step.semantic === 'object' && step.semantic.text) {
    result.semantic = step.semantic
  } else if (!step.locatorValue) {
    const semantic = inferSemantic(step.description)
    if (semantic) result.semantic = semantic
  }
  if (step.verify && typeof step.verify === 'object' && step.verify.type) {
    result.verify = step.verify
  }
  if (step.run_on) {
    result.run_on = step.run_on
  }

  // P1：verify_method 兼容转换（智能定位旧产出 → verify 顶层字段）
  if (!result.verify && params.verify_method) {
    const v = verifyMethodToVerify(params.verify_method, params)
    if (v) result.verify = v
  }

  return result
}

/**
 * 将智能定位旧字段 verify_method 转换为 verify 顶层字段
 *
 * P1 兼容转换：只读模式下已支持 verify_method → verify 映射，
 * 保存时同样转换，避免「仅编辑不保存丢失」。
 *
 * @param vm - verify_method 值（message / search / text_visible）
 * @param params - 动作参数（可能含 selector / expected_text / expected）
 * @returns verify 对象或 null
 */
export function verifyMethodToVerify(
  vm: string,
  params: Record<string, any>
): Record<string, any> | null {
  if (!vm) return null
  if (vm === 'message') return { type: 'dialog' }
  if (vm === 'search') return { type: 'element_visible', selector: params?.selector || '' }
  if (vm === 'text_visible') {
    return {
      type: 'text_visible',
      text: params?.expected_text || params?.expected || '',
    }
  }
  return null
}

/**
 * 将后端 StepDefinition 转换为意图步骤格式
 *
 * 用于编辑回显时，将后端存储的步骤数据转换为前端编辑器可用的格式。
 * 如果 locator_type / locator_value 为空，会尝试从 params.selector 自动推断补齐。
 *
 * @param step - 后端返回的 StepDefinition 数据
 * @returns 意图步骤格式
 *
 * @example
 * toIntentStep({ name: '输入用户名', params: { selector: '#username' } })
 * // => { description: '输入用户名', locatorType: 'css', locatorValue: '#username', ... }
 */
export function toIntentStep(step: any): IntentStep {
  const intentStep: IntentStep = {
    order: step.order || 1,
    description: step.name || '',
    expected: step.expected || '',
    actual: step.actual || '',
    waitAfter: step.waitAfter || 0,
    locatorType: step.locator_type || '',
    locatorValue: step.locator_value || '',
  }

  // 自动补齐：如果 locator 为空但 params.selector 有值，从中提取
  if (!intentStep.locatorType && !intentStep.locatorValue && step.params?.selector) {
    const selector = step.params.selector
    if (selector.startsWith('//') || selector.startsWith('(')) {
      intentStep.locatorType = 'xpath'
    } else if (selector.startsWith('#') && !selector.includes(' ')) {
      intentStep.locatorType = 'id'
      intentStep.locatorValue = selector.substring(1)
    } else {
      intentStep.locatorType = 'css'
    }
    intentStep.locatorValue = selector
  }

  // 阶段 6：保留语义字段（编辑回显不丢）
  if (step.semantic && typeof step.semantic === 'object' && step.semantic.text) {
    intentStep.semantic = step.semantic
  }
  if (step.verify && typeof step.verify === 'object' && step.verify.type) {
    intentStep.verify = step.verify
  }
  if (step.run_on) {
    intentStep.run_on = step.run_on
  }

  // P1：verify_method 兼容转换（智能定位旧产出，回显时可编辑）
  if (!intentStep.verify && step.params?.verify_method) {
    const v = verifyMethodToVerify(step.params.verify_method, step.params)
    if (v) intentStep.verify = v
  }

  return intentStep
}