// ── Public: the spawn atlas ────────────────────────────────────────────────
//
// A browsable catalogue of what the shard CONTAINS — which creatures spawn,
// where, how many, and which champion altars are configured. Everything here is
// a plain indexed read of the tables the boot-time import fills from the shard's
// own ServUO tree (docs/website/SPAWN_ATLAS.md).
//
// Two properties separate this from /public/shard/*:
//
//   • **Nothing touches the sidecar.** The atlas is static shard content, not
//     live shard state, so these pages stay fully populated while the shard is
//     down. That is why the routes are mounted at /public/atlas and are
//     siteMode-gated like /posts and /wiki, rather than under /shard.
//   • **The live champion feed is a different thing.** `/atlas/champions` is the
//     configured roster ("there is an Unholy Terror altar in Deceit");
//     `/shard/champs` is the running state ("it is on level 3 right now").
//
// Every response is still passed through `projectFeature` for the `atlas`
// feature. It declares no sensitive fields today, so the projection is a
// no-op — but v3.md §3.6.1's rule is that a read path returning shard data and
// not projecting is a bug, and the cost of honouring it is one call per handler
// rather than a retrofit the first time a field needs gating.

const atlas = require('../../../model/shardAtlas/shardAtlas.model')
const visibility = require('../../../utils/shardVisibility')

const log = require('../../../utils/logger')('public-atlas')

const FEATURE = 'atlas'

// Query params arrive as strings; express-validator has already bounded them.
const int = (value, fallback) => {
  const n = Number.parseInt(value, 10)
  return Number.isFinite(n) ? n : fallback
}

const str = (value) => (typeof value === 'string' ? value.trim() : '')

// GET /public/atlas/creatures?q=&facet=&limit=&offset=
async function getCreatures(req, res) {
  try {
    const page = await atlas.searchCreatures({
      q: str(req.query.q),
      facet: str(req.query.facet),
      limit: int(req.query.limit, 50),
      offset: int(req.query.offset, 0),
    })
    return res.json(await visibility.project(FEATURE, page, req))
  } catch (err) {
    log.error('atlas.getCreatures', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

// GET /public/atlas/creatures/:slug — one creature, with the places it spawns.
//
// 404 means "no such creature in this atlas", which also covers "the atlas has
// never been imported" — an empty atlas has no slugs, and there is nothing more
// specific to say to an anonymous caller.
async function getCreature(req, res) {
  try {
    const creature = await atlas.getCreature(req.params.slug, {
      facet: str(req.query.facet),
      points: int(req.query.points, 200),
    })
    if (!creature) return res.status(404).json({ message: 'Not Found' })
    return res.json(await visibility.project(FEATURE, creature, req))
  } catch (err) {
    log.error('atlas.getCreature', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

// GET /public/atlas/regions?facet=&q=
async function getRegions(req, res) {
  try {
    const regions = await atlas.listRegions({
      facet: str(req.query.facet),
      q: str(req.query.q),
    })
    return res.json(await visibility.project(FEATURE, regions, req))
  } catch (err) {
    log.error('atlas.getRegions', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

// GET /public/atlas/landmarks?facet=&q=
async function getLandmarks(req, res) {
  try {
    const landmarks = await atlas.listLandmarks({
      facet: str(req.query.facet),
      q: str(req.query.q),
    })
    return res.json(await visibility.project(FEATURE, landmarks, req))
  } catch (err) {
    log.error('atlas.getLandmarks', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

// GET /public/atlas/champions?facet= — the CONFIGURED altar roster.
async function getChampions(req, res) {
  try {
    const champions = await atlas.listChampions({ facet: str(req.query.facet) })
    return res.json(await visibility.project(FEATURE, champions, req))
  } catch (err) {
    log.error('atlas.getChampions', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

// GET /public/atlas/meta — what is loaded: facets, counts, when it was imported.
//
// Public-safe by construction: the model omits the ServUO path, the per-file
// hashes and the pending-refresh state, all of which describe the operator's
// filesystem rather than the game world. The admin status route carries those.
async function getMeta(req, res) {
  try {
    return res.json(await visibility.project(FEATURE, await atlas.publicMeta(), req))
  } catch (err) {
    log.error('atlas.getMeta', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

module.exports = {
  getCreatures,
  getCreature,
  getRegions,
  getLandmarks,
  getChampions,
  getMeta,
}
