/**
 * Tenant admin session management auth — A12c regression tests.
 */
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { Hono } from 'hono'
import { TenantTier } from '@zync/types'
import type { AppEnv } from '../src/types'

const mockListTenantUserSessionSummaries = vi.fn()
const mockRevokeAllSessionsForUser = vi.fn()
const mockRevokeAllTenantSessions = vi.fn()
const mockBlocklistRevokedTokens = vi.fn()
const mockLogAuditEvent = vi.fn()

let mockSession: {
  type: 'user'
  sub: string
  tid: string
  permissions: string[]
  tier: TenantTier
  v: number
}

vi.mock('../src/middleware/auth', () => ({
  authMiddleware: async (c: { set: (key: string, value: unknown) => void }, next: () => Promise<void>) => {
    c.set('db', {})
    c.set('session', mockSession)
    await next()
  },
}))

vi.mock('@zync/db/queries', async (importOriginal) => {
  const actual = await importOriginal<typeof import('@zync/db/queries')>()
  return {
    ...actual,
    listTenantUserSessionSummaries: (...args: unknown[]) =>
      mockListTenantUserSessionSummaries(...args),
    revokeAllSessionsForUser: (...args: unknown[]) => mockRevokeAllSessionsForUser(...args),
    revokeAllTenantSessions: (...args: unknown[]) => mockRevokeAllTenantSessions(...args),
    logAuditEvent: (...args: unknown[]) => mockLogAuditEvent(...args),
  }
})

vi.mock('@zync/auth', async (importOriginal) => {
  const actual = await importOriginal<typeof import('@zync/auth')>()
  return {
    ...actual,
    blocklistRevokedTokens: (...args: unknown[]) => mockBlocklistRevokedTokens(...args),
  }
})

import { adminSessionsRoute } from '../src/routes/admin-sessions'

const mockEnv = {
  DB: { connectionString: 'postgresql://test:test@localhost/test' },
  JWT_SECRET: 'test-jwt-secret',
  RATELIMIT_KV: {},
} as AppEnv['Bindings']

function appWithAdminSessionsRoute() {
  const app = new Hono<AppEnv>()
  app.route('/api/admin/sessions', adminSessionsRoute)
  return app
}

describe('GET /api/admin/sessions tenant auth (A12c-001)', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    mockSession = {
      type: 'user',
      sub: 'admin-user-id',
      tid: 'tenant-id',
      permissions: ['settings:security:read'],
      tier: TenantTier.BUSINESS,
      v: 1,
    }
    mockListTenantUserSessionSummaries.mockResolvedValue([
      { userId: 'user-1', activeSessionCount: 2, lastActiveAt: '2026-06-10T10:00:00Z' },
    ])
  })

  it('returns 200 for tenant admin with settings:security:read on Business tier', async () => {
    const res = await appWithAdminSessionsRoute().request('/api/admin/sessions', {
      method: 'GET',
      headers: { Origin: 'https://app.zync.is' },
    }, { Bindings: mockEnv })

    expect(res.status).toBe(200)
    const body = (await res.json()) as { sessions: unknown[] }
    expect(body.sessions).toHaveLength(1)
    expect(mockListTenantUserSessionSummaries).toHaveBeenCalledWith({}, 'tenant-id')
  })

  it('returns 403 without settings:security:read', async () => {
    mockSession.permissions = ['settings:read']

    const res = await appWithAdminSessionsRoute().request('/api/admin/sessions', {
      method: 'GET',
      headers: { Origin: 'https://app.zync.is' },
    }, { Bindings: mockEnv })

    expect(res.status).toBe(403)
    expect(mockListTenantUserSessionSummaries).not.toHaveBeenCalled()
  })

  it('returns 402 below Business tier', async () => {
    mockSession.tier = TenantTier.FREELANCER

    const res = await appWithAdminSessionsRoute().request('/api/admin/sessions', {
      method: 'GET',
      headers: { Origin: 'https://app.zync.is' },
    }, { Bindings: mockEnv })

    expect(res.status).toBe(402)
    expect(mockListTenantUserSessionSummaries).not.toHaveBeenCalled()
  })
})

describe('DELETE /api/admin/sessions/user/:userId tenant auth (A12c-001)', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    mockSession = {
      type: 'user',
      sub: 'admin-user-id',
      tid: 'tenant-id',
      permissions: ['settings:security:write'],
      tier: TenantTier.BUSINESS,
      v: 1,
    }
    mockRevokeAllSessionsForUser.mockResolvedValue({
      tokens: [{ tokenHash: 'hash-1', expiresAt: new Date(Date.now() + 3_600_000) }],
    })
    mockBlocklistRevokedTokens.mockResolvedValue(undefined)
  })

  it('returns 200 for tenant admin with settings:security:write', async () => {
    const res = await appWithAdminSessionsRoute().request(
      '/api/admin/sessions/user/00000000-0000-4000-8000-000000000001',
      {
        method: 'DELETE',
        headers: { Origin: 'https://app.zync.is' },
      },
      { Bindings: mockEnv },
    )

    expect(res.status).toBe(200)
    expect(mockRevokeAllSessionsForUser).toHaveBeenCalledOnce()
  })
})
