const READABLE_EXT_RE = /\.(md|markdown|txt|json|ya?ml|csv)$/i
const DEFAULT_API_BASE = import.meta.env?.VITE_API_BASE || '/api'

function safeGeneratedPath(value) {
  const path = String(value || '')
    .trim()
    .replace(/\\/g, '/')
    .replace(/^\/+/, '')
  if (!path || path.length > 240 || /[\0-\x1f]/.test(path)) return ''
  if (/^[A-Za-z]:\//.test(path) || /^[a-z][a-z0-9+.-]*:\/\//i.test(path)) return ''
  const parts = path.split('/').filter(Boolean)
  if (!parts.length) return ''
  if (parts.some(part => part === '.' || part === '..' || part.startsWith('.') || part.length > 120)) return ''
  return parts.join('/')
}

export function isReadableGeneratedPackageFile(path) {
  const safe = safeGeneratedPath(path)
  return !!safe && READABLE_EXT_RE.test(safe)
}

function generatedOutputUrl(apiBase, sessionId, path) {
  return `${apiBase}/skill-run/outputs/${encodeURIComponent(sessionId)}/${encodeURIComponent(path)}`
}

export async function fetchGeneratedPackageEntries({
  sessionId,
  files,
  apiBase = DEFAULT_API_BASE,
  fetcher = globalThis.fetch,
} = {}) {
  const sid = String(sessionId || '').trim()
  if (!sid || !Array.isArray(files) || typeof fetcher !== 'function') return []

  const entries = []
  const seen = new Set()
  for (const file of files) {
    const path = safeGeneratedPath(file)
    if (!path || seen.has(path) || !isReadableGeneratedPackageFile(path)) continue
    seen.add(path)
    try {
      const res = await fetcher(generatedOutputUrl(apiBase, sid, path))
      if (!res?.ok || typeof res.text !== 'function') continue
      const content = await res.text()
      if (!String(content || '').trim()) continue
      entries.push({ path, content })
    } catch {
      // A generated asset or stale file should not block the rest of the package.
    }
  }
  return entries
}
