// Auto-draft generator for رادار آینده / در یک نگاه.
// Scrapes recent Iranian steel news per section → Gemini (via Liara) writes
// Persian analytical items → pushes them to the panel as DRAFTS for review.
//
//   node scripts/generate-drafts.mjs
//
// Config + tone live in ./gen.config.mjs (gitignored). Drafts stay hidden from
// the public site until you press «انتشار» in the CMS.

import CFG from './gen.config.mjs'

// allow pointing at a local panel for testing without editing the config
const PANEL = {
  baseUrl: process.env.PANEL_BASE || CFG.panel.baseUrl,
  username: process.env.PANEL_USER || CFG.panel.username,
  password: process.env.PANEL_PASS || CFG.panel.password,
}

const UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120 Safari/537.36'
const sleep = (ms) => new Promise((r) => setTimeout(r, ms))

// section → { backend category code, scrape query, page label }
const CATEGORIES = [
  { code: 'market', label: 'بازار و زنجیره فولاد', query: 'قیمت بازار فولاد' },
  { code: 'energy', label: 'پایداری و فولاد سبز', query: 'فولاد سبز محیط زیست انرژی' },
  { code: 'geo', label: 'ژئوپلیتیک و اقتصاد جهانی', query: 'تعرفه صادرات فولاد اقتصاد جهانی' },
  { code: 'tech', label: 'فناوری و نوآوری', query: 'فناوری نوآوری فولاد' },
]
const NEWS_SITES = ['https://www.chilanonline.com', 'https://felezatonline.ir', 'https://madanmedia.ir', 'https://www.madannews.ir']

// ---------- helpers ----------
const decode = (s) =>
  s.replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g, '$1')
    .replace(/&#(\d+);/g, (_, n) => String.fromCharCode(+n))
    .replace(/&#xA0;|&#160;|&nbsp;/g, ' ')
    .replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&#39;/g, "'")
    .trim()
const stripTags = (s) => decode(s.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' '))
const tag = (b, n) => { const m = b.match(new RegExp(`<${n}[^>]*>([\\s\\S]*?)<\\/${n}>`, 'i')); return m ? m[1] : '' }

async function get(url, timeout = 18000) {
  const ac = new AbortController()
  const t = setTimeout(() => ac.abort(), timeout)
  try { const r = await fetch(url, { headers: { 'User-Agent': UA }, redirect: 'follow', signal: ac.signal }); return r.ok ? await r.text() : '' }
  catch { return '' } finally { clearTimeout(t) }
}

function parseRss(xml) {
  return [...xml.matchAll(/<item>([\s\S]*?)<\/item>/g)].map((m) => {
    const b = m[1]
    return { title: decode(tag(b, 'title')), url: decode(tag(b, 'link')).trim(), date: tag(b, 'pubDate').trim(), excerpt: stripTags(tag(b, 'description')).slice(0, 260) }
  })
}

async function scrape(query) {
  const all = []
  for (const base of NEWS_SITES) {
    const xml = await get(`${base}/?s=${encodeURIComponent(query)}&feed=rss2`)
    if (xml) all.push(...parseRss(xml))
    await sleep(300)
  }
  const seen = new Set()
  return all
    .filter((it) => it.title && it.url && !seen.has(it.title) && seen.add(it.title))
    .sort((a, b) => (Date.parse(b.date) || 0) - (Date.parse(a.date) || 0))
    .slice(0, 8)
}

async function panelLogin() {
  const res = await fetch(`${PANEL.baseUrl}/api/auth/login`, {
    method: 'POST', headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ username: PANEL.username, password: PANEL.password }),
  })
  if (!res.ok) throw new Error(`panel login failed (${res.status})`)
  const cookies = res.headers.getSetCookie?.() || []
  const session = cookies.map((c) => c.split(';')[0]).find((c) => c.startsWith('session='))
  if (!session) throw new Error('no session cookie returned')
  return session
}

function parseItems(text) {
  let t = text.replace(/```json|```/g, '').trim()
  const s = t.indexOf('{'), e = t.lastIndexOf('}')
  if (s === -1 || e === -1) return []
  try { return JSON.parse(t.slice(s, e + 1)).items || [] } catch { return [] }
}

async function generate(cat, news) {
  const newsText = news.map((n, i) => `${i + 1}. ${n.title}\n   منبع: ${n.url}\n   ${n.excerpt}`).join('\n\n')
  const user = `دسته: «${cat.label}»

از میان خبرهای زیر، ${CFG.perCategory} آیتم تحلیلیِ مستقل و متفاوت برای این دسته بنویس. هر آیتم باید یک رویداد/موضوع واقعی از خبرها را پوشش دهد.

خروجی را «فقط» به‌صورت JSON و دقیقاً با این ساختار بده (بدون هیچ توضیح اضافه):
{"items":[{"titleFa":"تیتر کوتاه","excerptFa":"خلاصهٔ یک تا دو جمله‌ای","bodyFa":"متن اصلی ۳ تا ۵ پاراگراف","analysisFa":"تحلیل راهبردی یک پاراگراف","tags":["برچسب","برچسب"],"sourceUrl":"نشانی منبع مرتبط"}]}

خبرها:
${newsText}`

  const res = await fetch(`${CFG.ai.baseUrl}/chat/completions`, {
    method: 'POST',
    headers: { Authorization: `Bearer ${CFG.ai.apiKey}`, 'Content-Type': 'application/json' },
    body: JSON.stringify({ model: CFG.ai.model, messages: [{ role: 'system', content: CFG.systemPrompt }, { role: 'user', content: user }], max_tokens: 8000, temperature: 0.7 }),
  })
  if (!res.ok) throw new Error(`gemini ${res.status}: ${(await res.text()).slice(0, 200)}`)
  const j = await res.json()
  return parseItems(j.choices?.[0]?.message?.content || '')
}

async function createDraft(session, cat, item, dateFa) {
  const body = {
    category: cat.code,
    titleFa: String(item.titleFa || '').trim(),
    excerptFa: item.excerptFa || null,
    bodyFa: item.bodyFa || null,
    analysisFa: item.analysisFa || null,
    tags: Array.isArray(item.tags) ? item.tags : [],
    source: item.sourceUrl || null,
    dateFa,
    status: 'draft',
  }
  if (!body.titleFa) return null
  const res = await fetch(`${PANEL.baseUrl}/api/radar`, {
    method: 'POST', headers: { 'Content-Type': 'application/json', Cookie: session },
    body: JSON.stringify(body),
  })
  if (!res.ok) { console.log(`    ✗ POST failed ${res.status}: ${(await res.text()).slice(0, 120)}`); return null }
  return (await res.json()).id
}

async function main() {
  const dateFa = new Intl.DateTimeFormat('fa-IR-u-ca-persian', { year: 'numeric', month: 'long', day: 'numeric' }).format(new Date())
  console.log(`Login to panel…`)
  const session = await panelLogin()
  let total = 0
  for (const cat of CATEGORIES) {
    console.log(`\n■ ${cat.label} (${cat.code})`)
    const news = await scrape(cat.query)
    console.log(`  scraped ${news.length} articles`)
    if (!news.length) { console.log('  (no news, skipping)'); continue }
    const items = await generate(cat, news)
    console.log(`  gemini returned ${items.length} items`)
    for (const it of items) {
      const id = await createDraft(session, cat, it, dateFa)
      if (id) { total++; console.log(`  ✓ draft ${id} — ${String(it.titleFa).slice(0, 50)}`) }
    }
  }
  console.log(`\nDone. ${total} drafts created. Review & publish them in the panel → «در یک نگاه».`)
}

main().catch((e) => { console.error('FATAL:', e.message); process.exit(1) })
