/**
 * 将各种形式的 Markdown “文档源”统一提取/读取为字符串
 *
 * 支持：
 * - 直接传 markdown 字符串
 * - `import md from './a.md'`（可能是 string，也可能是 { default: string }）
 * - Blob/File（浏览器端读取）
 * - URL/相对路径（以 .md 结尾且不包含换行时，走 fetch 读取）
 */

function isObject (v) {
  return v != null && typeof v === 'object'
}

function looksLikeUrlOrPath (s) {
  if (typeof s !== 'string') return false
  // http(s)://, //cdn, /xxx, ./xxx, ../xxx
  return /^(https?:)?\/\//.test(s) || s.startsWith('/') || s.startsWith('./') || s.startsWith('../')
}

function looksLikeBundledAssetPath (s) {
  if (typeof s !== 'string') return false
  // 打包产物里常见：assets/xxx.md、static/xxx.md、xxx.hash.md 等
  // 这些通常不以 ./ ../ / 开头，但依然应当被当作可 fetch 的资源路径
  if (s.includes('\n')) return false
  if (/\s/.test(s)) return false
  // 排除 data: / blob:（这些一般不需要我们 fetch 或无法 fetch）
  if (/^(data:|blob:)/i.test(s)) return false
  return /[\\/]/.test(s) || /^\w[\w.-]*\.md(\?.*)?$/.test(s)
}

function isMdPath (s) {
  if (typeof s !== 'string') return false
  return /\.md(\?.*)?$/.test(s)
}

/**
 * 同步“提取” markdown 字符串（不做 IO）
 * @param {*} input
 * @returns {string}
 */
export function extractMarkdownText (input) {
  if (input == null) return ''
  if (typeof input === 'string') return input

  // `import xxx from '*.md'` 可能是模块对象 { default: '...' }
  if (isObject(input)) {
    if (typeof input.default === 'string') return input.default
    if (typeof input.content === 'string') return input.content
    // 一些 loader 可能返回 { default: { ... } }，尝试递归解包
    if (input.default != null) {
      const unwrapped = extractMarkdownText(input.default)
      if (unwrapped) return unwrapped
    }
  }

  // 避免把 “空对象” 渲染成 [object Object]
  const s = String(input)
  return s === '[object Object]' ? '' : s
}

function readBlobAsText (blob) {
  // 现代浏览器 Blob#text
  if (blob && typeof blob.text === 'function') return blob.text()

  // 兼容：FileReader
  return new Promise((resolve, reject) => {
    try {
      const reader = new FileReader()
      reader.onload = () => resolve(reader.result == null ? '' : String(reader.result))
      reader.onerror = () => reject(reader.error || new Error('FileReader error'))
      reader.readAsText(blob)
    } catch (e) {
      reject(e)
    }
  })
}

/**
 * 异步“读取”为 markdown 字符串（可做 IO）
 *
 * @param {*} source - string | module | Blob/File | URL/path
 * @param {Object} [options]
 * @param {(input: RequestInfo, init?: RequestInit) => Promise<Response>} [options.fetcher] - 可注入自定义 fetch（默认 window.fetch）
 * @returns {Promise<string>}
 */
export async function readMarkdownAsText (source, options = {}) {
  // 1) Blob/File
  if (typeof Blob !== 'undefined' && source instanceof Blob) {
    return await readBlobAsText(source)
  }

  // 2) URL/path（只在“是单行 .md 字符串”时触发；兼容打包后导出为资源 URL 的场景）
  if (
    typeof source === 'string' &&
    !source.includes('\n') &&
    isMdPath(source) &&
    (looksLikeUrlOrPath(source) || looksLikeBundledAssetPath(source))
  ) {
    const fetcher = options.fetcher || (typeof fetch !== 'undefined' ? fetch : null)
    if (!fetcher) throw new Error('[readMarkdownAsText] fetch is not available')
    try {
      const res = await fetcher(source)
      if (!res || !res.ok) throw new Error(`[readMarkdownAsText] failed to fetch: ${source}`)
      return await res.text()
    } catch (e) {
      // fetch 失败时回退为普通字符串提取（避免误判导致直接抛错影响业务）
      return extractMarkdownText(source)
    }
  }

  // 3) 其他：同步提取
  return extractMarkdownText(source)
}

