const { getToken, validateToken } = require('./auth')
const { getUserProfile } = require('./api')

function normalizeRole(value) {
  if (value == null) return ''
  return String(value).trim().toLowerCase()
}

/** Roles that may update Templates (Developer, or elevated roles that include that capability). */
function isAllowedRoleForTemplateLibraryUpdate(value) {
  const n = normalizeRole(value)
  return (
    n === 'developer' ||
    n === 'admin' ||
    n === 'administrator' ||
    n === 'superadmin' ||
    n === 'owner'
  )
}

function isDeveloperRole(value) {
  return normalizeRole(value) === 'developer'
}

function decodeJwtPayload(token) {
  if (!validateToken(token)) return null
  const parts = token.split('.')
  if (parts.length !== 3) return null
  try {
    const json = Buffer.from(parts[1], 'base64url').toString('utf8')
    return JSON.parse(json)
  } catch {
    return null
  }
}

/**
 * Per-app or global role from CMS user objects (GET /api/user).
 */
function extractRoleFromUserProfile(user, appId) {
  if (!user || typeof user !== 'object') return null

  if (Array.isArray(user.memberships)) {
    const m = user.memberships.find(
      (x) => x && (x.appId === appId || x.app === appId || x.id === appId),
    )
    if (m && m.role != null) return m.role
  }

  const nested = user.appRoles && typeof user.appRoles === 'object' ? user.appRoles[appId] : null
  if (nested != null) return typeof nested === 'string' ? nested : nested.role

  const lists = [user.apps, user.webs, user.appMemberships].filter(Boolean)
  for (const list of lists) {
    if (!Array.isArray(list)) continue
    const match = list.find((entry) => entry && (entry.id === appId || entry.appId === appId))
    if (match && match.role != null) return match.role
  }

  if (user.role != null) {
    if (typeof user.role === 'string') return user.role
    if (typeof user.role === 'number' || typeof user.role === 'boolean') return String(user.role)
  }
  if (user.admin === true) return 'admin'

  return null
}

function extractRoleFromJwtPayload(payload, appId) {
  if (!payload || typeof payload !== 'object') return null

  if (payload.admin === true) return 'admin'
  if (payload.isAdmin === true) return 'admin'
  if (payload.claims && typeof payload.claims === 'object' && typeof payload.claims.role === 'string') {
    return payload.claims.role
  }
  if (payload.firebase && typeof payload.firebase === 'object' && typeof payload.firebase.role === 'string') {
    return payload.firebase.role
  }

  if (typeof payload.role === 'string') return payload.role

  if (Array.isArray(payload.roles)) {
    const hit = payload.roles.find((r) => isAllowedRoleForTemplateLibraryUpdate(r))
    if (hit != null) return String(hit)
  }
  if (typeof payload.roles === 'string') return payload.roles

  const appNested =
    (payload.apps && typeof payload.apps === 'object' && payload.apps[appId]) ||
    (payload.appRoles && typeof payload.appRoles === 'object' && payload.appRoles[appId])
  if (appNested != null) {
    if (typeof appNested === 'string') return appNested
    if (typeof appNested === 'object' && appNested.role != null) return appNested.role
  }

  return null
}

/**
 * Resolves role using only the auth token (claims) and existing GET /api/user — no extra CMS routes.
 */
async function resolveRoleForApp(appId) {
  const token = await getToken()
  if (!validateToken(token)) {
    return null
  }

  const payload = decodeJwtPayload(token)

  if (payload) {
    const fromJwt = extractRoleFromJwtPayload(payload, appId)
    if (fromJwt) return fromJwt
  }

  const profile = await getUserProfile()
  if (profile) {
    const fromProfile = extractRoleFromUserProfile(profile, appId)
    if (fromProfile) return fromProfile
  }

  return null
}

async function requireDeveloperRoleForApp(appId) {
  const token = await getToken()
  if (!validateToken(token)) {
    throw new Error('Not authenticated or token is invalid; cannot verify Developer role.')
  }
  const payload = decodeJwtPayload(token)
  if (!payload) {
    throw new Error('Could not read your session; cannot verify Developer role.')
  }

  const role = await resolveRoleForApp(appId)
  if (role == null) {
    throw new Error(
      'Could not verify your role. Ensure GET /api/user returns your role (e.g. developer or admin) and you are logged in.',
    )
  }
  if (!isAllowedRoleForTemplateLibraryUpdate(role)) {
    throw new Error(
      'Updating Templates requires the Developer or Admin role (or equivalent) for this app.',
    )
  }
}

module.exports = {
  normalizeRole,
  isDeveloperRole,
  isAllowedRoleForTemplateLibraryUpdate,
  requireDeveloperRoleForApp,
  resolveRoleForApp,
}
