import { inferSkillDraftFromMessages } from './chatWorkflow.js'
import { buildSkillPackageEntries } from './skillPackage.js'

const SKILL_SECTION_RE = /(^|\n)#{1,3}\s+.+[\s\S]*(^|\n)##\s*(简介|触发条件|核心指令|使用方式|输出格式)/m
const PACKAGE_LABEL_RE = /(^|\n)[^\n]{0,80}(?:SKILL\.md|examples\.md|rubric\.md|[\w\u4e00-\u9fff./-]+\.(?:json|ya?ml|md|txt|csv))\s*[：:]/i
const GENERIC_SKILL_NAMES = new Set([
  'skill',
  'ai 创建 skill',
  '未命名 skill',
  '简介',
  '触发条件',
  '输入参数',
  '依赖工具',
  '核心指令',
  '输出规范',
  'skill.md',
  'examples.md',
  'rubric.md',
])

export function shouldOfferSkillUpload(text) {
  const raw = String(text || '').trim()
  if (raw.length < 20) return false
  if (PACKAGE_LABEL_RE.test(raw)) return true
  return SKILL_SECTION_RE.test(raw) && /(^|\n)##\s*(触发条件|核心指令)/.test(raw)
}

function compactMissingFields({ name, nodeId, creatorName }) {
  const missing = []
  if (!String(name || '').trim()) missing.push('name')
  if (nodeId == null || nodeId === '') missing.push('nodeId')
  if (!String(creatorName || '').trim()) missing.push('creatorName')
  return missing
}

function conversationPackageSource(messages, fallback) {
  const text = (messages || [])
    .filter(m => (m?.role === 'user' || m?.role === 'assistant') && m?.content && !m?.isStreaming)
    .map(m => m.content)
    .join('\n\n')
  return shouldOfferSkillUpload(text) ? text : fallback
}

function cleanSkillName(value) {
  return String(value || '')
    .replace(/^#+\s*/, '')
    .replace(/^["'“”‘’]+|["'“”‘’]+$/g, '')
    .replace(/^Skill\s*名称\s*[：:]\s*/i, '')
    .replace(/^名称\s*[：:]\s*/i, '')
    .replace(/\s*(评测标准|评分标准|质量标准|示例|案例)\s*$/i, '')
    .trim()
}

function isGenericSkillName(value) {
  const normalized = cleanSkillName(value).replace(/\s+/g, ' ').toLowerCase()
  return !normalized || GENERIC_SKILL_NAMES.has(normalized)
}

function inferSkillNameFromEntries(entries = []) {
  const skillEntry = (entries || []).find(entry => entry?.path?.toLowerCase() === 'skill.md')
  const content = String(skillEntry?.content || '')
  const explicit = content.match(/(?:^|\n)\s*(?:#{1,4}\s*)?(?:Skill\s*)?名称\s*[：:]\s*([^\n]+)/i)
  if (explicit?.[1]) return cleanSkillName(explicit[1])
  const heading = content.match(/(?:^|\n)\s*#\s+([^\n]+)/)
  return heading?.[1] ? cleanSkillName(heading[1]) : ''
}

function stripFrontmatter(text) {
  return String(text || '').replace(/^---\s*\n[\s\S]*?\n---\s*\n?/, '')
}

function extractFrontmatterDescription(text) {
  const match = String(text || '').match(/^---\s*\n([\s\S]*?)\n---\s*\n?/)
  if (!match) return ''
  for (const line of match[1].split(/\r?\n/)) {
    const row = line.trim().match(/^(description|desc|summary)\s*:\s*(.+)$/i)
    if (row?.[2]) return row[2].trim().replace(/^["']|["']$/g, '')
  }
  return ''
}

function extractNamedDescriptionSection(text) {
  const body = stripFrontmatter(text).replace(/\r/g, '')
  const headingRe = /^#{1,6}\s+(.+?)\s*$/gm
  const headings = []
  let match
  while ((match = headingRe.exec(body)) !== null) {
    headings.push({
      title: cleanSkillName(match[1]),
      start: match.index,
      contentStart: headingRe.lastIndex,
    })
  }
  const target = headings.find(h => /^(简介|描述|说明|能力说明|功能简介|适用场景|用途)$/.test(h.title))
  if (!target) return ''
  const next = headings.find(h => h.start > target.start)
  return body.slice(target.contentStart, next?.start ?? body.length)
}

function firstPlainParagraph(text) {
  return stripFrontmatter(text)
    .replace(/```[\s\S]*?```/g, '\n')
    .split(/\n{2,}/)
    .map(part => part.trim())
    .find(part => part && !/^#{1,6}\s+/.test(part) && !/^\|?\s*[-:| ]{3,}\s*\|?$/.test(part)) || ''
}

export function markdownToPlainDescription(markdown, { maxLength = 180 } = {}) {
  const lines = String(markdown || '')
    .replace(/\r/g, '')
    .replace(/```[\s\S]*?```/g, '\n')
    .split('\n')
    .map(line => line
      .replace(/^\s{0,3}#{1,6}\s+/, '')
      .replace(/^\s{0,3}>\s?/, '')
      .replace(/^\s*(?:[-*+]|\d+[.)、])\s+/, '')
      .trim()
    )
    .filter(line => line && !/^\|?\s*[-:| ]{3,}\s*\|?$/.test(line))

  const text = lines.join(' ')
    .replace(/!\[([^\]]*)\]\([^)]+\)/g, '$1')
    .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
    .replace(/`([^`]+)`/g, '$1')
    .replace(/<\/?[^>]+>/g, '')
    .replace(/(\*\*|__)(.*?)\1/g, '$2')
    .replace(/(\*|_)(.*?)\1/g, '$2')
    .replace(/~~(.*?)~~/g, '$1')
    .replace(/\|/g, ' ')
    .replace(/\\([\\`*_[\]{}()#+\-.!>])/g, '$1')
    .replace(/^(简介|描述|说明|能力说明|功能简介|适用场景|用途)\s*[：:]\s*/, '')
    .replace(/\s+/g, ' ')
    .replace(/([。！？!?；;，,、])\s+(?=[\u4e00-\u9fffA-Za-z0-9])/g, '$1')
    .trim()

  return maxLength && text.length > maxLength ? `${text.slice(0, maxLength).trim()}...` : text
}

export function deriveSkillDescriptionFromEntries(entries = [], fallback = '') {
  const skillEntry = (entries || []).find(entry => entry?.path?.toLowerCase() === 'skill.md')
  const skillMd = String(skillEntry?.content || '')
  const source = skillMd
    ? (extractFrontmatterDescription(skillMd) || extractNamedDescriptionSection(skillMd) || firstPlainParagraph(skillMd))
    : fallback
  return markdownToPlainDescription(source)
}

export function buildSkillUploadPlan(options = {}) {
  const draft = options.draft || inferSkillDraftFromMessages(options.messages || [], {
    sourceFile: options.sourceFile,
    sourceFilePath: options.sourceFilePath || options.nodePath,
  })
  const packageSource = options.description || conversationPackageSource(options.messages || [], draft.description)
  const explicitEntries = Array.isArray(options.entries) && options.entries.length > 0
    ? options.entries
    : undefined
  const entries = buildSkillPackageEntries({
    name: options.name || draft.name,
    description: packageSource,
    entries: explicitEntries,
  })
  const requestedName = String(options.name || draft.name || '').trim()
  const entryName = inferSkillNameFromEntries(entries)
  const name = explicitEntries && entryName
    ? entryName
    : (isGenericSkillName(requestedName) && entryName ? entryName : requestedName)
  const creatorName = String(options.creatorName || '').trim()
  const nodeId = options.nodeId ?? null
  const nodePath = options.nodePath || ''
  const description = deriveSkillDescriptionFromEntries(entries, options.description || draft.description || '')
  const missingFields = compactMissingFields({ name, nodeId, creatorName })

  return {
    name,
    description,
    nodeId,
    nodePath,
    creatorName,
    entries,
    missingFields,
    canUpload: missingFields.length === 0,
  }
}
