// ── Admin · Spawn atlas ────────────────────────────────────────────────────
//
// Operating the atlas import: where the ServUO tree is, whether it has drifted
// from what is loaded, and the approve/reject decision for a refresh that would
// remove a facet (docs/website/SPAWN_ATLAS.md).
//
// The policy lives in the model. This controller does three things and no more:
// it validates input, it maps a refresh RESULT onto an HTTP status, and it
// records the action in the admin activity log.
//
// **A refresh result is not an exception.** `shardAtlas.refresh()` reports
// `unavailable` / `failed` / `needsReview` rather than throwing, because the boot
// path must never be stopped by a bad tree. That contract is preserved here: an
// unreadable mount is a 200 carrying `status: 'unavailable'`, not a 500. The
// admin needs to be told what is wrong with their path, and a 500 says only
// "something broke".

const atlas = require('../../../model/shardAtlas/shardAtlas.model')
const activity = require('../../../model/activity/activity.model')

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

// GET /admin/shard/atlas — what is loaded, what the tree looks like, what is
// staged. Unlike the public /atlas/meta route this DOES carry the filesystem
// path and the drift flag: that is the whole point of the panel.
async function getStatus(req, res) {
  try {
    return res.json(await atlas.status())
  } catch (err) {
    log.error('getStatus', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

// POST /admin/shard/atlas/import — apply a map change without a restart.
//
// `force` reimports even when the source hashes match what is loaded (the escape
// hatch for "the database is wrong but the tree is not"). Facet loss is still
// staged rather than applied — approving is a separate, explicit act.
async function importAtlas(req, res) {
  try {
    const force = !!req.body?.force
    const result = await atlas.refresh({ force })
    await activity.log({
      req,
      action: 'shard.atlas.import',
      detail: { force, status: result.status, counts: result.counts ?? null },
    })
    return res.json(result)
  } catch (err) {
    log.error('importAtlas', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

// POST /admin/shard/atlas/approve — apply a staged refresh, facet loss and all.
//
// Re-parses the tree rather than applying something captured at boot: only the
// DECISION was stored, so what lands matches the tree as it is now. If the
// operator has since fixed a half-copied mount, the approved import is simply
// the corrected one — which is the desired outcome, not a surprise.
async function approve(req, res) {
  try {
    const result = await atlas.approvePending()
    await activity.log({
      req,
      action: 'shard.atlas.approve',
      detail: { status: result.status, removed: result.removedFacets ?? null },
    })
    return res.json(result)
  } catch (err) {
    log.error('approveAtlas', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

// POST /admin/shard/atlas/reject — keep the current atlas and remember the
// decision against those exact source hashes, so a declined refresh does not
// re-prompt on every restart. Changing the tree asks again.
async function reject(req, res) {
  try {
    const result = await atlas.rejectPending()
    if (result.status === 'none') {
      return res.status(404).json({ message: 'No refresh is awaiting review.' })
    }
    await activity.log({ req, action: 'shard.atlas.reject', detail: {} })
    return res.json(result)
  } catch (err) {
    log.error('rejectAtlas', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

// PUT /admin/shard/atlas/path — point the atlas at a different ServUO tree.
//
// Persisted as a setting, which wins over the SERVUO_PATH env default so an
// operator can move the mount without a redeploy. Blank clears it, which turns
// the atlas off (boot skips, the loaded atlas keeps serving) — that is a
// legitimate thing to want, so it is allowed rather than validated away.
//
// Deliberately does NOT import as a side effect: changing where the atlas reads
// from and reloading it are separate decisions, and an operator fixing a typo
// should not have a multi-thousand-row replace happen under them. The response
// carries the refreshed status so the panel can offer the import immediately.
async function setPath(req, res) {
  try {
    const value = String(req.body?.path ?? '').trim()
    await atlas.setServuoPath(value, req.user?.id ?? null)
    await activity.log({ req, action: 'shard.atlas.path', detail: { path: value } })
    return res.json(await atlas.status())
  } catch (err) {
    log.error('setAtlasPath', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

module.exports = { getStatus, importAtlas, approve, reject, setPath }
