// Point the DB at a closed port BEFORE requiring anything that builds the pool,
// so any stray query fails fast instead of holding the process open. The session
// service, users model, and appeals model are all stubbed, so no query runs.
process.env.DB_HOST = '127.0.0.1'
process.env.DB_PORT = '59999'

const { test, after, afterEach } = require('node:test')
const assert = require('node:assert/strict')

const { startApp } = require('./_helper')
const playerRouter = require('../src/router/v1/player')
const sessionService = require('../src/auth/session.service')
const users = require('../src/model/users/users.model')
const appeals = require('../src/model/appeals/appeals.model')
const db = require('../src/utils/db')

after(() => db.close())

const originals = {
  validateSession: sessionService.validateSession,
  isSessionRevoked: sessionService.isSessionRevoked,
  sessionMeta: sessionService.sessionMeta,
  getById: users.getById,
  listMine: appeals.listMine,
}
afterEach(() => {
  sessionService.validateSession = originals.validateSession
  sessionService.isSessionRevoked = originals.isSessionRevoked
  sessionService.sessionMeta = originals.sessionMeta
  users.getById = originals.getById
  appeals.listMine = originals.listMine
})

// Sign every request in as the given DB user (role decides the gate outcome).
function signInAs(user) {
  sessionService.validateSession = () => ({ userId: user.id, sessionId: 's1', createdAt: Date.now(), authMethod: 'jwt' })
  sessionService.isSessionRevoked = async () => false
  sessionService.sessionMeta = () => ({})
  users.getById = async () => user
}

// The player self-service group is intentionally role-agnostic (staff are a
// superset of players): any authenticated, active account reaches the self-scoped
// handlers. Regression guard for the fix that dropped requireRole('player') so a
// staff/admin account is no longer 403'd out of its own characters.
for (const role of ['player', 'admin', 'editor', 'moderator']) {
  test(`GET /player/appeals is reachable by an authenticated ${role}`, async () => {
    signInAs({ id: 7, username: 'u', role, status: 'active' })
    appeals.listMine = async (id) => {
      assert.equal(id, 7) // self-scoped to the caller regardless of role
      return [{ id: 1 }]
    }
    const app = await startApp((a) => a.use('/api/v1/player', playerRouter))
    try {
      const res = await fetch(app.url + '/api/v1/player/appeals')
      assert.equal(res.status, 200, `${role} should reach the handler, got ${res.status}`)
      assert.deepEqual(await res.json(), [{ id: 1 }])
    } finally {
      await app.close()
    }
  })
}

test('GET /player/appeals still rejects an unauthenticated caller with 401', async () => {
  sessionService.validateSession = () => null
  const app = await startApp((a) => a.use('/api/v1/player', playerRouter))
  try {
    const res = await fetch(app.url + '/api/v1/player/appeals')
    assert.equal(res.status, 401)
  } finally {
    await app.close()
  }
})

test('a disabled account is still rejected with 403 (status gate, not role)', async () => {
  signInAs({ id: 8, username: 'banned', role: 'player', status: 'disabled' })
  const app = await startApp((a) => a.use('/api/v1/player', playerRouter))
  try {
    const res = await fetch(app.url + '/api/v1/player/appeals')
    assert.equal(res.status, 403)
  } finally {
    await app.close()
  }
})
