export const UPLOAD_BLOCK_NODE_TYPE = 'upload_block'

export const DEFAULT_UPLOAD_BLOCK_TYPES = [
  'docx',
  'pptx',
  'pdf',
  'txt',
  'json',
  'toml',
  'yaml',
  'images',
  'mp4',
  'webm',
  'mov',
  'avi',
  'mkv',
]

const TYPE_ALIAS = {
  doc: 'docx',
  docx: 'docx',
  word: 'docx',
  ppt: 'pptx',
  pptx: 'pptx',
  powerpoint: 'pptx',
  pdf: 'pdf',
  txt: 'txt',
  text: 'txt',
  plain: 'txt',
  json: 'json',
  toml: 'toml',
  yaml: 'yaml',
  yml: 'yaml',
  '[images]': 'images',
  image: 'images',
  images: 'images',
  mp4: 'mp4',
  webm: 'webm',
  mov: 'mov',
  avi: 'avi',
  mkv: 'mkv',
}

const TYPE_LABELS = {
  docx: 'DOCX',
  pptx: 'PPTX',
  pdf: 'PDF',
  txt: 'TXT',
  json: 'JSON',
  toml: 'TOML',
  yaml: 'YAML',
  images: '图片',
  mp4: 'MP4',
  webm: 'WebM',
  mov: 'MOV',
  avi: 'AVI',
  mkv: 'MKV',
}

const TYPE_ACCEPT_MAP = {
  docx: [
    '.docx',
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  ],
  pptx: [
    '.pptx',
    'application/vnd.openxmlformats-officedocument.presentationml.presentation',
  ],
  pdf: [
    '.pdf',
    'application/pdf',
  ],
  txt: [
    '.txt',
    'text/plain',
  ],
  json: [
    '.json',
    'application/json',
  ],
  toml: [
    '.toml',
    'application/toml',
    'text/toml',
  ],
  yaml: [
    '.yaml',
    '.yml',
    'text/yaml',
    'text/x-yaml',
    'application/x-yaml',
  ],
  images: ['image/*'],
  mp4: ['.mp4', 'video/mp4'],
  webm: ['.webm', 'video/webm'],
  mov: ['.mov', 'video/quicktime'],
  avi: ['.avi', 'video/x-msvideo'],
  mkv: ['.mkv', 'video/x-matroska'],
}

const IMAGE_EXT_RE = /\.(png|jpe?g|gif|webp|bmp|svg|heic|heif|avif)$/i
const SYNTAX_RE = /^\{\{\{([\s\S]*?)\}\}\}$/
const UPLOAD_TYPE_PREFIX_RE = /^upload\s+file\s+type\s*:\s*(.+)$/i

function parseStrictUploadBlockTypes(values = []) {
  const normalized = []

  for (const value of values) {
    const next = normalizeUploadBlockType(value)
    if (!next) return null
    if (!normalized.includes(next)) {
      normalized.push(next)
    }
  }

  return normalized.length > 0 ? normalized : null
}

export function normalizeUploadBlockType(value = '') {
  const key = String(value || '').trim().toLowerCase()
  return TYPE_ALIAS[key] || ''
}

export function normalizeUploadBlockTypes(value) {
  const source = Array.isArray(value) ? value : []
  const normalized = []

  for (const item of source) {
    const next = normalizeUploadBlockType(item)
    if (!next || normalized.includes(next)) continue
    normalized.push(next)
  }

  return normalized.length > 0 ? normalized : [...DEFAULT_UPLOAD_BLOCK_TYPES]
}

export function getUploadBlockMenuOptions(allowedTypes = DEFAULT_UPLOAD_BLOCK_TYPES) {
  return normalizeUploadBlockTypes(allowedTypes).map((type) => ({
    value: type,
    label: TYPE_LABELS[type] || type.toUpperCase(),
  }))
}

export function getUploadBlockAccept(allowedTypes = DEFAULT_UPLOAD_BLOCK_TYPES) {
  const entries = new Set()

  normalizeUploadBlockTypes(allowedTypes).forEach((type) => {
    const values = TYPE_ACCEPT_MAP[type] || []
    values.forEach((entry) => entries.add(entry))
  })

  return Array.from(entries).join(',')
}

export function getUploadBlockAcceptForType(type = '') {
  const normalized = normalizeUploadBlockType(type)
  if (!normalized) return ''
  return (TYPE_ACCEPT_MAP[normalized] || []).join(',')
}

function parseUploadBlockInner(raw = '') {
  const inner = String(raw || '').trim()
  if (!inner) {
    return { allowedTypes: [...DEFAULT_UPLOAD_BLOCK_TYPES] }
  }

  const matched = inner.match(UPLOAD_TYPE_PREFIX_RE)
  if (!matched) return null

  const segments = matched[1]
    .split(',')
    .map((item) => item.trim())
    .filter(Boolean)

  if (segments.length === 0) return null

  const allowedTypes = parseStrictUploadBlockTypes(segments)
  if (!allowedTypes) return null

  return allowedTypes.length > 0 ? { allowedTypes } : null
}

export function parseUploadBlockSyntax(value = '') {
  const matched = String(value || '').trim().match(SYNTAX_RE)
  if (!matched) return null
  return parseUploadBlockInner(matched[1])
}

export function serializeUploadBlockSyntax(allowedTypes = DEFAULT_UPLOAD_BLOCK_TYPES) {
  const normalized = normalizeUploadBlockTypes(allowedTypes)
  const isDefault =
    normalized.length === DEFAULT_UPLOAD_BLOCK_TYPES.length &&
    normalized.every((type, index) => type === DEFAULT_UPLOAD_BLOCK_TYPES[index])

  if (isDefault) return '{{{}}}'

  const serialized = normalized
    .map((type) => (type === 'images' ? '[images]' : type))
    .join(',')

  return `{{{upload file type:${serialized}}}}`
}

export function isUploadBlockImageFile(file) {
  if (!file) return false
  const name = String(file.name || '').toLowerCase()
  const type = String(file.type || '').toLowerCase()
  return type.startsWith('image/') || IMAGE_EXT_RE.test(name)
}

export function getUploadBlockFileType(file) {
  if (!file) return ''
  if (isUploadBlockImageFile(file)) return 'images'

  const name = String(file.name || '').toLowerCase()
  if (name.endsWith('.docx')) return 'docx'
  if (name.endsWith('.pptx')) return 'pptx'
  if (name.endsWith('.pdf')) return 'pdf'
  if (name.endsWith('.json')) return 'json'
  if (name.endsWith('.toml')) return 'toml'
  if (name.endsWith('.yaml') || name.endsWith('.yml')) return 'yaml'
  if (name.endsWith('.txt')) return 'txt'

  const mime = String(file.type || '').toLowerCase()
  if (mime === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document') return 'docx'
  if (mime === 'application/vnd.openxmlformats-officedocument.presentationml.presentation') return 'pptx'
  if (mime === 'application/pdf') return 'pdf'
  if (mime === 'application/json') return 'json'
  if (mime === 'application/toml' || mime === 'text/toml') return 'toml'
  if (mime === 'text/yaml' || mime === 'text/x-yaml' || mime === 'application/x-yaml') return 'yaml'
  if (mime === 'text/plain') return 'txt'

  return ''
}

export function isUploadBlockTypeAllowed(file, allowedTypes = DEFAULT_UPLOAD_BLOCK_TYPES) {
  const fileType = getUploadBlockFileType(file)
  if (!fileType) return false
  return normalizeUploadBlockTypes(allowedTypes).includes(fileType)
}