const discordManager = require('../discord/discordManager')
const newsAnnounce = require('../discord/newsAnnounce')
const modLog = require('../discord/modLog')
const createLogger = require('../utils/logger')

const log = createLogger('internal')

const REVERSIBLE = new Set(['ban', 'mute'])
// discord.js REST error code for removing a ban that no longer exists.
const UNKNOWN_BAN = 10026

// POST /internal/config — called by the main server right after an admin
// saves the Discord Bot panel, and by the bot's own bootstrap on startup
// (via a GET to the server for the current config, then this same start/stop
// logic locally). Body: { token, guildId, enabled }.
async function setConfig(req, res) {
  const { token, guildId, enabled } = req.body || {}
  try {
    if (enabled) {
      if (!token || !guildId) {
        return res.status(400).json({ message: 'token and guildId are required when enabled' })
      }
      await discordManager.start({ token, guildId })
    } else {
      await discordManager.stop()
    }
    return res.json(discordManager.getStatus())
  } catch (err) {
    log.error('setConfig failed', { message: err.message })
    // Still 200 with an error status — the caller (admin panel) should surface
    // discordManager's status/statusDetail rather than treat this as a 5xx.
    return res.json(discordManager.getStatus())
  }
}

// GET /internal/status — live connection state, polled by the admin panel.
function getStatusHandler(req, res) {
  return res.json(discordManager.getStatus())
}

// POST /internal/announce — called by the main server right after a news
// post is published. Body: { title, excerpt, url, imageUrl }.
async function announce(req, res) {
  const connection = discordManager.getConnection()
  if (!connection) return res.status(503).json({ message: 'Bot is not connected' })
  try {
    await newsAnnounce.postAnnounce(connection.client, connection.guildId, req.body || {})
    return res.json({ posted: true })
  } catch (err) {
    log.warn('announce failed', { message: err.message })
    return res.status(400).json({ message: err.message })
  }
}

// POST /internal/mod-reverse — called by the main server when a staffer APPROVES
// a moderation appeal (Phase 6d). Body: { discord_user_id, action_type, appeal_id }.
// Reverses the Discord action: 'ban' → lift the ban, 'mute' → clear the timeout.
// Idempotent-friendly: an already-lifted ban ("Unknown Ban") or a member who has
// left the guild is treated as success (the desired end state already holds).
async function reverseModAction(req, res) {
  const { discord_user_id: discordUserId, action_type: actionType, appeal_id: appealId } = req.body || {}

  if (!REVERSIBLE.has(actionType)) {
    return res.status(400).json({ message: 'action_type must be ban or mute' })
  }

  const connection = discordManager.getConnection()
  if (!connection) return res.status(503).json({ message: 'Bot is not connected' })

  const reason = `Appeal #${appealId} approved`
  try {
    const guild = await connection.client.guilds.fetch(connection.guildId)

    if (actionType === 'ban') {
      try {
        await guild.bans.remove(discordUserId, reason)
      } catch (err) {
        // Unknown Ban → already unbanned; anything else is a real failure.
        if (err.code !== UNKNOWN_BAN) throw err
      }
    } else {
      // mute: clear the timeout. If the member has left, there's nothing to clear.
      const member = await guild.members.fetch(discordUserId).catch(() => null)
      if (member) await member.timeout(null, reason)
    }

    await modLog.postReversal({
      client: connection.client,
      guildId: connection.guildId,
      actionType,
      discordUserId,
      appealId,
    })

    return res.json({ reversed: true })
  } catch (err) {
    log.error('mod-reverse failed', { message: err.message, actionType, discordUserId })
    return res.status(500).json({ message: err.message })
  }
}

module.exports = { setConfig, getStatus: getStatusHandler, announce, reverseModAction }
