const http = require('http')
const path = require('path')
const fs = require('fs')
const express = require('express')
const cors = require('cors')
const { WebSocketServer } = require('ws')
const db = require('./db')
const routes = require('./routes')
const { getSituation } = require('./situationData')

const app = express()
const PORT = process.env.API_PORT || 3001

// 爬虫通知用的共享密钥：API_CRAWLER_TOKEN（仅在服务端与爬虫进程间传递）
const CRAWLER_TOKEN = process.env.API_CRAWLER_TOKEN || ''

app.set('trust proxy', 1)
app.use(cors())
app.use(express.json())

app.use('/api', routes)
app.get('/api/health', (_, res) => res.json({ ok: true }))
app.post('/api/crawler/notify', (req, res) => {
  // 若配置了 API_CRAWLER_TOKEN，则要求爬虫携带 X-Crawler-Token 头
  if (CRAWLER_TOKEN) {
    const token = req.headers['x-crawler-token']
    if (typeof token !== 'string' || token !== CRAWLER_TOKEN) {
      return res.status(401).json({ error: 'unauthorized' })
    }
  }
  notifyCrawlerUpdate()
  res.json({ ok: true })
})

// 生产环境：提供前端静态文件（含修订页 /edit，依赖 SPA fallback）
const distPath = path.join(__dirname, '..', 'dist')
if (fs.existsSync(distPath)) {
  app.use(express.static(distPath))
  // 非 API/WS 的请求一律返回 index.html，由前端路由处理 /、/edit、/db 等
  app.get('*', (req, res, next) => {
    if (!req.path.startsWith('/api') && req.path !== '/ws') {
      res.sendFile(path.join(distPath, 'index.html'))
    } else next()
  })
} else {
  console.warn('[server] dist 目录不存在，前端页面（含 /edit 修订页）不可用。请在项目根目录执行 npm run build 后再启动。')
}

const server = http.createServer(app)

const { getStats } = require('./stats')

const wss = new WebSocketServer({ server, path: '/ws' })
wss.on('connection', (ws) => {
  ws.send(JSON.stringify({ type: 'situation', data: getSituation(), stats: getStats() }))
})

// 版本含 situation、situation_update、key_location 基地态势，任一变化都会触发广播，保证爬虫 AI 更新基地后前端实时刷新
function getBroadcastVersion() {
  try {
    const meta = db.prepare('SELECT updated_at FROM situation WHERE id = 1').get()
    const row = db.prepare('SELECT COUNT(*) as c FROM situation_update').get()
    const usAtt = db.prepare("SELECT COUNT(*) as c FROM key_location WHERE side='us' AND status='attacked'").get()
    const irAtt = db.prepare("SELECT COUNT(*) as c FROM key_location WHERE side='iran' AND status='attacked'").get()
    return `${meta?.updated_at || ''}_${row?.c ?? 0}_b${usAtt?.c ?? 0}_${irAtt?.c ?? 0}`
  } catch (_) {
    return ''
  }
}

let lastBroadcastVersion = null

function broadcastSituation(force = false) {
  if (!force && wss.clients.size === 0) return
  const version = getBroadcastVersion()
  if (!force && version === lastBroadcastVersion) return
  try {
    const data = JSON.stringify({ type: 'situation', data: getSituation(), stats: getStats() })
    wss.clients.forEach((c) => {
      if (c.readyState === 1) c.send(data)
    })
    lastBroadcastVersion = version
  } catch (_) {}
}

app.set('broadcastSituation', () => broadcastSituation(true))

if (typeof routes.setBroadcastSituation === 'function') {
  routes.setBroadcastSituation(() => broadcastSituation(true))
}

const BROADCAST_INTERVAL_MS = Math.max(0, parseInt(process.env.BROADCAST_INTERVAL_MS, 10) || 30000)
if (BROADCAST_INTERVAL_MS > 0) {
  setInterval(() => broadcastSituation(false), BROADCAST_INTERVAL_MS)
}

// 供爬虫调用：先从磁盘重载 DB（纳入爬虫写入），再更新 situation.updated_at 并立即广播；前端据此实时更新基地态势等
function notifyCrawlerUpdate() {
  try {
    const db = require('./db')
    db.reloadFromFile()
    db.prepare("INSERT OR REPLACE INTO situation (id, data, updated_at) VALUES (1, '{}', ?)").run(new Date().toISOString())
    broadcastSituation(true) // 强制推送，确保基地数/被袭数等随 AI 清洗实时更新
    const n = db.prepare('SELECT COUNT(*) as c FROM situation_update').get().c
    const usB = db.prepare("SELECT COUNT(*) as c FROM key_location WHERE side='us'").get().c
    const irB = db.prepare("SELECT COUNT(*) as c FROM key_location WHERE side='iran'").get().c
    console.log('[crawler/notify] DB 已重载并广播，situation_update:', n, '基地 us/iran:', usB, irB)
  } catch (e) {
    console.error('[crawler/notify]', e?.message || e)
  }
}

db.initDb().then(() => {
  server.listen(PORT, () => {
    console.log(`API + WebSocket running at http://localhost:${PORT}`)
    console.log(`Swagger docs at http://localhost:${PORT}/api-docs`)
  })
}).catch((err) => {
  console.error('DB init failed:', err)
  process.exit(1)
})
