// ── Role-agnostic self-service ("me") under /auth/me ───────────────────────
//
// The canonical self surface for EVERY authenticated role (player and staff
// alike). It reuses the exact same account.controller handlers as
// /player/account/* and /admin/account/* — no logic duplication — but gates on
// requireAuth ONLY (any authenticated, active account), never on a specific role.
//
// Why it exists: the Android app wants one self surface it can call regardless of
// role, and it must never touch /admin (docs/android/PLAN.md §6.4). The older
// /player/account/* and /admin/account/* routes stay for web back-compat; these
// /auth/me/* routes are the additive, role-agnostic canonical form.
//
// requireAuth sets req.user to the fresh DB row and enforces the status + session
// cutoff/revocation checks on every request, exactly as the account handlers
// expect. Mounted at /me by auth/index.js, so paths below are /auth/me/account*.

const express = require('express')
const { body, param } = require('express-validator')

const account = require('../admin/account.controller')
const { requireAuth } = require('../../../auth/session.middleware')
const noindex = require('../../../middleware/noindex')
const validate = require('../../../middleware/validate')
const { accountChangeLimiter } = require('../../../middleware/rateLimit')
const { slowLogin, backoffGuard } = require('../../../middleware/loginProtection')

const meRouter = express.Router()

// Group gate: authenticated + active (any role), and keep it out of search
// indexes. No requireRole — this surface is deliberately role-agnostic.
meRouter.use(noindex, requireAuth)

meRouter.get(
  '/account',
  // #swagger.tags = ['Auth · Me']
  // #swagger.summary = 'Get the current account (self, any role)'
  // #swagger.security = [{ "cookieAuth": [] }, { "bearerAuth": [] }]
  /* #swagger.responses[200] = { description: 'The current account', content: { "application/json": { schema: { $ref: "#/components/schemas/PlayerAccount" } } } } */
  /* #swagger.responses[401] = { description: 'Not authenticated', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  /* #swagger.responses[403] = { description: 'Account not active', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  account.getAccount,
)

meRouter.patch(
  '/account/username',
  // #swagger.tags = ['Auth · Me']
  // #swagger.summary = 'Change the current account’s username (self, any role)'
  // #swagger.security = [{ "cookieAuth": [] }, { "bearerAuth": [] }]
  /* #swagger.requestBody = { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/ChangeUsernameRequest" } } } } */
  /* #swagger.responses[200] = { description: 'Updated username (session re-issued)', content: { "application/json": { schema: { type: "object", properties: { username: { type: "string" } } } } } } */
  /* #swagger.responses[400] = { description: 'Validation error or unavailable username', content: { "application/json": { schema: { $ref: "#/components/schemas/ValidationError" } } } } */
  /* #swagger.responses[401] = { description: 'Not authenticated', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  /* #swagger.responses[409] = { description: 'Username already taken', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  /* #swagger.responses[429] = { description: 'Too many changes (rate limited)', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  accountChangeLimiter,
  body('username').isString().trim().isLength({ min: 3, max: 32 }),
  validate,
  account.changeUsername,
)

meRouter.patch(
  '/account/password',
  // #swagger.tags = ['Auth · Me']
  // #swagger.summary = 'Change or set the current account’s password (self, any role)'
  // #swagger.description = 'If the account already has a password, currentPassword is required and verified. SSO-provisioned accounts with no password may set an initial one without a current password. On success the caller’s own session is re-issued (they stay logged in) while older web sessions are revoked.'
  // #swagger.security = [{ "cookieAuth": [] }, { "bearerAuth": [] }]
  /* #swagger.requestBody = { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/ChangePasswordRequest" } } } } */
  /* #swagger.responses[200] = { description: 'Password changed', content: { "application/json": { schema: { $ref: "#/components/schemas/OkFlag" } } } } */
  /* #swagger.responses[400] = { description: 'Validation error or wrong current password', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  /* #swagger.responses[401] = { description: 'Not authenticated', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  /* #swagger.responses[429] = { description: 'Too many changes (rate limited)', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  accountChangeLimiter,
  body('newPassword').isString().isLength({ min: 8, max: 64 }),
  body('currentPassword').optional({ values: 'falsy' }).isString(),
  validate,
  account.changePassword,
)

// TOTP self-enrollment — identical to the player/admin account flow (disable
// requires a valid current code; it does not take a password).
meRouter.post(
  '/account/totp/setup',
  // #swagger.tags = ['Auth · Me']
  // #swagger.summary = 'Begin 2FA enrollment (returns secret + QR)'
  // #swagger.security = [{ "cookieAuth": [] }, { "bearerAuth": [] }]
  /* #swagger.responses[200] = { description: 'otpauth URL and QR data to scan', content: { "application/json": { schema: { $ref: "#/components/schemas/TotpSetup" } } } } */
  /* #swagger.responses[401] = { description: 'Not authenticated', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  /* #swagger.responses[409] = { description: 'Two-factor already enabled', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  account.totpSetup,
)
meRouter.post(
  '/account/totp/enable',
  // #swagger.tags = ['Auth · Me']
  // #swagger.summary = 'Enable 2FA by confirming a code'
  // #swagger.security = [{ "cookieAuth": [] }, { "bearerAuth": [] }]
  /* #swagger.requestBody = { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/TotpCodeRequest" } } } } */
  /* #swagger.responses[200] = { description: '2FA enabled', content: { "application/json": { schema: { $ref: "#/components/schemas/TotpState" } } } } */
  /* #swagger.responses[400] = { description: 'Setup not started, or invalid code', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  /* #swagger.responses[409] = { description: 'Two-factor already enabled', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  body('code').isString().trim().isLength({ min: 6, max: 8 }),
  validate,
  account.totpEnable,
)
meRouter.post(
  '/account/totp/disable',
  // #swagger.tags = ['Auth · Me']
  // #swagger.summary = 'Disable 2FA by confirming a code'
  // #swagger.description = 'Requires a valid current authenticator code (proves control of the authenticator); it does not take a password.'
  // #swagger.security = [{ "cookieAuth": [] }, { "bearerAuth": [] }]
  /* #swagger.requestBody = { required: true, content: { "application/json": { schema: { $ref: "#/components/schemas/TotpCodeRequest" } } } } */
  /* #swagger.responses[200] = { description: '2FA disabled', content: { "application/json": { schema: { $ref: "#/components/schemas/TotpState" } } } } */
  /* #swagger.responses[400] = { description: 'Not enabled, or invalid code', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  body('code').isString().trim().isLength({ min: 6, max: 8 }),
  validate,
  account.totpDisable,
)

// Linked SSO identities (self-service). Linking itself starts at
// GET /auth/sso/:provider/link (already behind requireAuth; works for any role).
meRouter.get(
  '/account/identities',
  // #swagger.tags = ['Auth · Me']
  // #swagger.summary = 'List linked SSO identities (self)'
  // #swagger.security = [{ "cookieAuth": [] }, { "bearerAuth": [] }]
  /* #swagger.responses[200] = { description: 'Linked identities', content: { "application/json": { schema: { type: "array", items: { $ref: "#/components/schemas/LinkedIdentity" } } } } } */
  account.listIdentities,
)
meRouter.delete(
  '/account/identities/:provider',
  // #swagger.tags = ['Auth · Me']
  // #swagger.summary = 'Unlink an SSO identity (self)'
  // #swagger.security = [{ "cookieAuth": [] }, { "bearerAuth": [] }]
  // #swagger.parameters['provider'] = { in: 'path', required: true, schema: { type: 'string' }, description: 'Provider id.' }
  /* #swagger.responses[200] = { description: 'Unlinked', content: { "application/json": { schema: { $ref: "#/components/schemas/UnlinkedFlag" } } } } */
  /* #swagger.responses[404] = { description: 'No linked account for that provider', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  param('provider').matches(/^[a-z0-9-]+$/),
  validate,
  account.unlinkIdentity,
)

// Active mobile device sessions (self-service). Distinct from /auth/me/devices,
// which is push-notification endpoints — these are login sessions (M9). List the
// active ones and revoke a single device without "log out everywhere".
meRouter.get(
  '/sessions',
  // #swagger.tags = ['Auth · Me']
  // #swagger.summary = 'List active mobile device sessions (self)'
  // #swagger.description = 'Active (unrevoked, unexpired) mobile bearer sessions — one per live device — for the Active Devices screen. Never returns tokens.'
  // #swagger.security = [{ "cookieAuth": [] }, { "bearerAuth": [] }]
  /* #swagger.responses[200] = { description: 'Active device sessions', content: { "application/json": { schema: { type: "array", items: { $ref: "#/components/schemas/DeviceSession" } } } } } */
  /* #swagger.responses[401] = { description: 'Not authenticated', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  account.listSessions,
)
meRouter.delete(
  '/sessions/:id',
  // #swagger.tags = ['Auth · Me']
  // #swagger.summary = 'Revoke one mobile device session (self)'
  // #swagger.description = 'Revokes a single device by its session id (ownership-scoped). Revoking stops future token renewals; an already-issued access token remains valid until it expires (see the documented revocation-latency window).'
  // #swagger.security = [{ "cookieAuth": [] }, { "bearerAuth": [] }]
  // #swagger.parameters['id'] = { in: 'path', required: true, schema: { type: 'integer' }, description: 'The session row id from GET /auth/me/sessions.' }
  /* #swagger.responses[200] = { description: 'Revoked (idempotent)', content: { "application/json": { schema: { type: "object", properties: { revoked: { type: "boolean" } } } } } } */
  /* #swagger.responses[401] = { description: 'Not authenticated', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  param('id').isInt({ min: 1 }),
  validate,
  account.revokeSession,
)

// ── Trusted devices (self-service, MFA "Trust this device") ────────────────
// Distinct from /sessions (mobile login sessions): these are the devices allowed
// to SKIP the TOTP step at login. List, trust-current, revoke one, untrust all.
meRouter.get(
  '/trusted-devices',
  // #swagger.tags = ['Auth · Me']
  // #swagger.summary = 'List trusted devices (self)'
  // #swagger.description = 'Active (unrevoked, unexpired) trusted devices — the browsers/apps allowed to skip the TOTP step at login. Never returns tokens.'
  // #swagger.security = [{ "cookieAuth": [] }, { "bearerAuth": [] }]
  /* #swagger.responses[200] = { description: 'Active trusted devices', content: { "application/json": { schema: { type: "array", items: { $ref: "#/components/schemas/TrustedDevice" } } } } } */
  /* #swagger.responses[401] = { description: 'Not authenticated', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  account.listTrustedDevices,
)
meRouter.post(
  '/trusted-devices',
  // #swagger.tags = ['Auth · Me']
  // #swagger.summary = 'Trust the current device (self)'
  // #swagger.description = 'Marks the current browser/app as trusted so future logins skip the TOTP step (30 days). Web receives an httpOnly trust cookie; native (bearer) sessions receive { trustToken } to store. Returns 409 { error: "trusted_device_limit", devices } when the per-user cap is reached — revoke one first, then retry.'
  // #swagger.security = [{ "cookieAuth": [] }, { "bearerAuth": [] }]
  /* #swagger.requestBody = { content: { "application/json": { schema: { type: "object", properties: { deviceName: { type: "string" } } } } } } */
  /* #swagger.responses[200] = { description: 'Device trusted', content: { "application/json": { schema: { $ref: "#/components/schemas/TrustDeviceResult" } } } } */
  /* #swagger.responses[401] = { description: 'Not authenticated', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  /* #swagger.responses[409] = { description: 'Trusted-device limit reached', content: { "application/json": { schema: { $ref: "#/components/schemas/TrustedDeviceLimit" } } } } */
  accountChangeLimiter,
  body('deviceName').optional({ values: 'falsy' }).isString().trim().isLength({ max: 100 }),
  validate,
  account.trustThisDevice,
)
meRouter.delete(
  '/trusted-devices',
  // #swagger.tags = ['Auth · Me']
  // #swagger.summary = 'Revoke all trusted devices (self)'
  // #swagger.description = 'Untrust every device; future logins on all of them require the full TOTP step again. Also clears this browser’s trust cookie.'
  // #swagger.security = [{ "cookieAuth": [] }, { "bearerAuth": [] }]
  /* #swagger.responses[200] = { description: 'Revoked count', content: { "application/json": { schema: { type: "object", properties: { revoked: { type: "integer" } } } } } } */
  /* #swagger.responses[401] = { description: 'Not authenticated', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  account.revokeAllTrustedDevices,
)
meRouter.delete(
  '/trusted-devices/:id',
  // #swagger.tags = ['Auth · Me']
  // #swagger.summary = 'Revoke one trusted device (self)'
  // #swagger.security = [{ "cookieAuth": [] }, { "bearerAuth": [] }]
  // #swagger.parameters['id'] = { in: 'path', required: true, schema: { type: 'integer' }, description: 'Trusted-device id from GET /auth/me/trusted-devices.' }
  /* #swagger.responses[200] = { description: 'Revoked (idempotent)', content: { "application/json": { schema: { type: "object", properties: { revoked: { type: "boolean" } } } } } } */
  /* #swagger.responses[401] = { description: 'Not authenticated', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  param('id').isInt({ min: 1 }),
  validate,
  account.revokeTrustedDevice,
)

// ── Recovery (backup) codes (self-service) ─────────────────────────────────
meRouter.get(
  '/account/recovery-codes/status',
  // #swagger.tags = ['Auth · Me']
  // #swagger.summary = 'Remaining recovery-code count (self)'
  // #swagger.security = [{ "cookieAuth": [] }, { "bearerAuth": [] }]
  /* #swagger.responses[200] = { description: 'Remaining unused codes', content: { "application/json": { schema: { type: "object", properties: { remaining: { type: "integer" } } } } } } */
  /* #swagger.responses[401] = { description: 'Not authenticated', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  account.recoveryCodesStatus,
)
meRouter.post(
  '/account/recovery-codes/generate',
  // #swagger.tags = ['Auth · Me']
  // #swagger.summary = 'Regenerate recovery codes (self, password step-up)'
  // #swagger.description = 'Generates a fresh set of single-use recovery codes, invalidating any prior set, and returns them ONCE. Requires the current password (accounts that have one); refuses when two-factor is off. Behind the login backoff/bot guards since a wrong password is credential-guessing.'
  // #swagger.security = [{ "cookieAuth": [] }, { "bearerAuth": [] }]
  /* #swagger.requestBody = { content: { "application/json": { schema: { type: "object", properties: { currentPassword: { type: "string" } } } } } } */
  /* #swagger.responses[200] = { description: 'New recovery codes (shown once)', content: { "application/json": { schema: { $ref: "#/components/schemas/RecoveryCodes" } } } } */
  /* #swagger.responses[400] = { description: 'Wrong password, or two-factor not enabled', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  /* #swagger.responses[401] = { description: 'Not authenticated', content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } } } */
  backoffGuard,
  slowLogin,
  accountChangeLimiter,
  body('currentPassword').optional({ values: 'falsy' }).isString(),
  validate,
  account.generateRecoveryCodes,
)

module.exports = meRouter
