// ── Admin: auth provider configuration ─────────────────────────────────────
//
// CRUD for SSO providers. Built-ins (google, discord) are configured here too but
// can only be enabled/disabled and given a client id/secret — their kind, name,
// and endpoints are fixed in code and cannot be edited or deleted. Custom
// (oidc/oauth2) providers are fully editable.
//
// SECURITY: the client secret is write-only over this API. It is stored encrypted
// and NEVER returned — responses expose only `hasSecret`. A blank `secret` on
// update means "leave the existing secret unchanged".

const authProviders = require('../../../model/authProviders/authProviders.model')
const registry = require('../../../auth/providers/registry')
const activity = require('../../../model/activity/activity.model')

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

// Shape a provider row for the admin UI — no secret material, ever.
function toSafe(p) {
  return {
    id: p.id,
    kind: p.kind,
    name: p.name,
    enabled: Boolean(p.enabled),
    clientId: p.client_id || '',
    hasSecret: Boolean(p.client_secret_enc),
    authorizeUrl: p.authorize_url || '',
    tokenUrl: p.token_url || '',
    userinfoUrl: p.userinfo_url || '',
    scopes: p.scopes || '',
    priority: p.priority ?? 100,
    builtin: registry.isBuiltin(p.id),
    health: p.health || registry.validateConfig(p),
  }
}

// GET /admin/auth/providers — all providers (built-ins always present) + health.
async function list(req, res) {
  try {
    const rows = await registry.listConfigured()
    return res.json(rows.map(toSafe))
  } catch (err) {
    log.error('authProviders.list', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

// POST /admin/auth/providers — create a custom (oidc/oauth2) provider.
async function create(req, res) {
  const { id, kind, name, enabled, clientId, secret, authorizeUrl, tokenUrl, userinfoUrl, scopes, priority } = req.body
  try {
    if (registry.isBuiltin(id)) {
      return res.status(400).json({ message: 'Built-in provider — configure it via PUT, not create.' })
    }
    if (!['oidc', 'oauth2'].includes(kind)) {
      return res.status(400).json({ message: 'Custom providers must be of kind oidc or oauth2.' })
    }
    if (await authProviders.get(id)) {
      return res.status(409).json({ message: 'A provider with that id already exists.' })
    }
    const saved = await authProviders.save(id, {
      kind, name, enabled, clientId, secret, authorizeUrl, tokenUrl, userinfoUrl, scopes, priority,
    })
    await activity.log({ req, action: 'auth.provider.create', detail: { id } })
    log.info('auth provider created', { id, kind, by: req.user.username })
    return res.status(201).json(toSafe(saved))
  } catch (err) {
    log.error('authProviders.create', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

// PUT /admin/auth/providers/:id — update a built-in or custom provider.
async function update(req, res) {
  const { id } = req.params
  const b = req.body
  try {
    let fields
    if (registry.isBuiltin(id)) {
      // Built-ins: kind/name/priority are fixed; only enable + credentials change.
      const meta = registry.BUILTINS.find((x) => x.id === id)
      fields = { kind: meta.kind, name: meta.name, priority: meta.priority, enabled: b.enabled, clientId: b.clientId, secret: b.secret }
    } else {
      if (!(await authProviders.get(id))) {
        return res.status(404).json({ message: 'Provider not found.' })
      }
      fields = {
        name: b.name, enabled: b.enabled, clientId: b.clientId, secret: b.secret,
        authorizeUrl: b.authorizeUrl, tokenUrl: b.tokenUrl, userinfoUrl: b.userinfoUrl,
        scopes: b.scopes, priority: b.priority,
      }
    }
    const saved = await authProviders.save(id, fields)
    await activity.log({ req, action: 'auth.provider.update', detail: { id } })
    log.info('auth provider updated', { id, by: req.user.username })
    return res.json(toSafe(saved))
  } catch (err) {
    log.error('authProviders.update', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

// DELETE /admin/auth/providers/:id — custom providers only.
async function remove(req, res) {
  const { id } = req.params
  try {
    if (registry.isBuiltin(id)) {
      return res.status(400).json({ message: 'Built-in providers cannot be deleted — disable them instead.' })
    }
    const n = await authProviders.remove(id)
    if (!n) return res.status(404).json({ message: 'Provider not found.' })
    await activity.log({ req, action: 'auth.provider.delete', detail: { id } })
    log.info('auth provider deleted', { id, by: req.user.username })
    return res.json({ deleted: true })
  } catch (err) {
    log.error('authProviders.remove', err)
    return res.status(500).json({ message: 'Internal Server Error' })
  }
}

module.exports = { list, create, update, remove, toSafe }
