import { describe, expect, it } from 'vitest'
import {
  canAccessSurface, canManageAccess, delegatableSurfaces, grantState, hasAnySurface, isDelegatable,
  SURFACES, surfaceByKey, surfaceForPath, surfacesFor, validateModeratorEmail,
} from '@/lib/domain/moderator-access'
import { DEFAULT_TEMPLATES } from '@/lib/email-templates'
import { resolveTemplateMeta } from '@/lib/domain/email-policy'

/**
 * Per-page moderator access (Nash, 2026-09-23): "the main admin can invite a
 * specific user with his email to a specific page… He cannot invite anyone
 * else, only the admin can." Security-relevant, so the rules are pinned here.
 */
const admin = { role: 'admin' as const }
const leadsMod = { role: 'dispatcher', surfaces: ['broker_leads'] }
const customer = { role: 'broker', surfaces: [] as string[] }

describe('who can open what', () => {
  it('the admin opens every page', () => {
    for (const s of SURFACES) expect(canAccessSurface(admin, s.key)).toBe(true)
  })
  it('a moderator opens only the pages granted', () => {
    expect(canAccessSurface(leadsMod, 'broker_leads')).toBe(true)
    expect(canAccessSurface(leadsMod, 'email_templates')).toBe(false)
    expect(canAccessSurface(leadsMod, 'moderation')).toBe(false)
    expect(surfacesFor(leadsMod).map((s) => s.key)).toEqual(['broker_leads'])
    expect(hasAnySurface(leadsMod)).toBe(true)
  })
  it('a customer opens nothing, and neither does a missing user', () => {
    expect(canAccessSurface(customer, 'broker_leads')).toBe(false)
    expect(surfacesFor(customer)).toEqual([])
    expect(hasAnySurface(customer)).toBe(false)
    expect(canAccessSurface(null, 'broker_leads')).toBe(false)
    expect(canAccessSurface(undefined, 'moderation')).toBe(false)
    expect(surfacesFor(null)).toEqual([])
  })
  it('an unknown page is never open', () => {
    expect(canAccessSurface(leadsMod, 'nope')).toBe(false)
    expect(canAccessSurface({ role: 'dispatcher', surfaces: ['nope'] }, 'nope')).toBe(false)
  })
  it('user management and operational logs can never be delegated', () => {
    expect(surfaceByKey('users')?.adminOnly).toBe(true)
    expect(surfaceByKey('operations')?.adminOnly).toBe(true)
    expect(isDelegatable('users')).toBe(false)
    expect(isDelegatable('operations')).toBe(false)
    expect(canAccessSurface({ role: 'dispatcher', surfaces: ['users'] }, 'users')).toBe(false)
    expect(canAccessSurface({ role: 'dispatcher', surfaces: ['operations'] }, 'operations')).toBe(false)
    expect(delegatableSurfaces().some((s) => s.key === 'users')).toBe(false)
    expect(delegatableSurfaces()).toHaveLength(SURFACES.filter((s) => !s.adminOnly).length)
  })
})

describe('only the admin grants access', () => {
  it('a moderator can never invite anyone', () => {
    expect(canManageAccess(admin)).toBe(true)
    expect(canManageAccess(leadsMod)).toBe(false)
    expect(canManageAccess({ role: 'dispatcher', surfaces: SURFACES.map((s) => s.key) })).toBe(false)
    expect(canManageAccess(null)).toBe(false)
  })
})

describe('surfaces', () => {
  it('every page has a unique key and path, and the API prefixes map back', () => {
    expect(new Set(SURFACES.map((s) => s.key)).size).toBe(SURFACES.length)
    expect(new Set(SURFACES.map((s) => s.path)).size).toBe(SURFACES.length)
    expect(surfaceForPath('/api/admin/broker-leads/leads')?.key).toBe('broker_leads')
    expect(surfaceForPath('/api/admin/moderation')?.key).toBe('moderation')
    expect(surfaceForPath('/api/trips/x')).toBeNull()
    // a prefix must not match a longer sibling by accident
    expect(surfaceForPath('/api/admin/broker-leads-other')).toBeNull()
  })
  it('the invitation template exists and is account security, never marketing', () => {
    expect(DEFAULT_TEMPLATES.some((t) => t.key === 'moderator_access_invitation')).toBe(true)
    const meta = resolveTemplateMeta('moderator_access_invitation')
    expect(meta.stream).toBe('transactional')
    expect(meta.category).toBe('account_security')
  })
})

describe('grant state and email checks', () => {
  it('invited → active → revoked', () => {
    expect(grantState({})).toBe('invited')
    expect(grantState({ accepted_at: '2026-09-23' })).toBe('active')
    expect(grantState({ accepted_at: '2026-09-23', revoked_at: '2026-09-24' })).toBe('revoked')
    expect(grantState({ revoked_at: '2026-09-24' })).toBe('revoked')
  })
  it('a real address is required', () => {
    expect(validateModeratorEmail('  Alex@Company.COM ')).toEqual({ ok: true, email: 'alex@company.com' })
    expect(validateModeratorEmail('nope').ok).toBe(false)
    expect(validateModeratorEmail('x@users.local').ok).toBe(false)
    expect(validateModeratorEmail('x@thing.example').ok).toBe(false)
  })
})
