// ── Admin: a single user's shard (uo-link) footprint ──────────────────────────
//
// Backs the /admin/users/:id detail page. Every read is scoped to the target
// user's linked game accounts (from the local shard_account_links mirror): their
// vendor sales, houses, and currently-online characters. The live character
// rosters are fetched separately by the client through the existing admin-bypass
// /admin/shard/* endpoints, so nothing here round-trips the sidecar — these are
// fast, DB-backed reads. Admin-only (registered under adminOnly in the router).

const users = require('../../../model/users/users.model')
const shardLinks = require('../../../model/shardLinks/shardLinks.model')
const shardState = require('../../../model/shardState/shardState.model')
const uoLinkClient = require('../../../utils/uoLinkClient')
const activity = require('../../../model/activity/activity.model')
const { salesForAccounts } = require('../../../utils/shardSales')

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

// Resolve the target user's linked game accounts, or null if the user id is
// unknown (so the handler can 404 rather than silently returning an empty set).
async function accountsForUser(id) {
  const user = await users.getById(id)
  if (!user) return null
  const links = await shardLinks.listForUser(id)
  return { user, links, accounts: links.map((l) => l.account) }
}

// GET /admin/users/:id — the sanitized user (so the detail page is refresh-safe).
async function getUser(req, res) {
  try {
    const user = await users.getById(Number(req.params.id))
    if (!user) return res.status(404).json({ message: 'Not found' })
    return res.json(user)
  } catch (err) {
    log.error('getUser', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

// GET /admin/users/:id/shard/accounts — the user's linked game accounts.
async function listAccounts(req, res) {
  try {
    const ctx = await accountsForUser(Number(req.params.id))
    if (!ctx) return res.status(404).json({ message: 'Not found' })
    return res.json(ctx.links)
  } catch (err) {
    log.error('listAccounts', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

// GET /admin/users/:id/shard/sales — recent vendor sales on the user's accounts.
async function getSales(req, res) {
  try {
    const ctx = await accountsForUser(Number(req.params.id))
    if (!ctx) return res.status(404).json({ message: 'Not found' })
    return res.json(await salesForAccounts(ctx.accounts))
  } catch (err) {
    log.error('getSales', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

// GET /admin/users/:id/shard/houses — houses owned by the user's accounts.
async function getHouses(req, res) {
  try {
    const ctx = await accountsForUser(Number(req.params.id))
    if (!ctx) return res.status(404).json({ message: 'Not found' })
    return res.json(await shardState.listHousesForAccounts(ctx.accounts))
  } catch (err) {
    log.error('getHouses', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

// GET /admin/users/:id/shard/online — the user's characters currently online.
async function getOnline(req, res) {
  try {
    const ctx = await accountsForUser(Number(req.params.id))
    if (!ctx) return res.status(404).json({ message: 'Not found' })
    return res.json(await shardState.listOnlineForAccounts(ctx.accounts))
  } catch (err) {
    log.error('getOnline', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

// GET /admin/users/:id/shard/standing — the user's shard "standing" cross-links:
// city governorships they currently hold and guilds they lead. Both are reliable
// current-state lookups on the user's linked accounts.
async function getStanding(req, res) {
  try {
    const ctx = await accountsForUser(Number(req.params.id))
    if (!ctx) return res.status(404).json({ message: 'Not found' })
    const [governorOf, guildsLed] = await Promise.all([
      shardState.listGovernorshipsForAccounts(ctx.accounts),
      shardState.listGuildsLedForAccounts(ctx.accounts),
    ])
    return res.json({ governorOf, guildsLed })
  } catch (err) {
    log.error('getStanding', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

// DELETE /admin/users/:id/shard/link/:account — unlink a game account from this
// user, site-side. `actor` is stamped from the session (never the browser). On
// success the sidecar clears the WebsiteUserId tag on the shard and we drop the
// local mirror so attribution stops immediately.
async function unlinkAccount(req, res) {
  const { account } = req.params
  try {
    const ctx = await accountsForUser(Number(req.params.id))
    if (!ctx) return res.status(404).json({ message: 'Not found' })
    // Only unlink an account actually linked to THIS user (avoid cross-user unlink).
    if (!ctx.accounts.includes(account)) {
      return res.status(404).json({ message: 'That account is not linked to this user.' })
    }
    const result = await uoLinkClient.unlinkAccount({ actor: req.user.username, account })
    if (result.ok) {
      await shardLinks.removeByAccount(account)
      await activity.log({ req, userId: ctx.user.id, action: 'shard.account.unlink', detail: { account } })
      log.info('game account unlinked', { account, userId: ctx.user.id, actor: req.user.username })
      return res.json({ account, unlinked: true })
    }
    if (result.status === 403) return res.status(403).json({ message: 'That account is protected and cannot be unlinked.' })
    if (result.status === 404) {
      // Not linked on the shard — reconcile our mirror anyway so the two agree.
      await shardLinks.removeByAccount(account)
      return res.status(404).json({ message: 'That account is not linked.' })
    }
    if (result.status === 503 || result.status === 0) {
      return res.status(503).json({ message: 'The game server is unavailable — try again shortly.' })
    }
    return res.status(502).json({ message: 'Could not reach the shard to unlink the account.' })
  } catch (err) {
    log.error('unlinkAccount', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

module.exports = { getUser, listAccounts, getSales, getHouses, getOnline, getStanding, unlinkAccount }
