import { beforeEach, describe, expect, it, vi } from 'vitest'
import { Hono } from 'hono'

const {
  createIncident,
  addIncidentUpdate,
  resolveIncident,
  findAdminById,
  invalidateStatusCache,
  notifySubscribers,
} = vi.hoisted(() => ({
  createIncident: vi.fn(),
  addIncidentUpdate: vi.fn(),
  resolveIncident: vi.fn(),
  findAdminById: vi.fn(),
  invalidateStatusCache: vi.fn(),
  notifySubscribers: vi.fn(),
}))

vi.mock('@zync/db/queries', () => ({
  createDb: vi.fn(() => ({})),
  createIncident,
  addIncidentUpdate,
  resolveIncident,
  findAdminById,
  IncidentNotFoundError: class IncidentNotFoundError extends Error {},
  IncidentAlreadyResolvedError: class IncidentAlreadyResolvedError extends Error {},
}))

vi.mock('../src/lib/status-cache', () => ({
  invalidateStatusCache,
}))

vi.mock('../src/lib/status-notify', () => ({
  notifySubscribers,
}))

vi.mock('../src/middleware/admin-auth', () => ({
  adminAuthMiddleware: async (c: { set: (key: string, value: unknown) => void }, next: () => Promise<void>) => {
    c.set('session', {
      sub: 'admin-1',
      type: 'admin',
      totp_verified: true,
      role: 'BILLING',
      permissions: ['admin.billing:read', 'admin.billing:write'],
    })
    await next()
  },
}))

vi.mock('../src/middleware/guards', () => ({
  requireAdminSession: () => async (_c: unknown, next: () => Promise<void>) => next(),
}))

import { adminIncidentsRoutes } from '../src/routes/admin/incidents'
import type { AppEnv } from '../src/types'

function appWithRoute() {
  const app = new Hono<AppEnv>()
  app.route('/api/admin/incidents', adminIncidentsRoutes)
  return app
}

describe('admin incidents permissions', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    findAdminById.mockResolvedValue({ email: 'ops@zync.is' })
  })

  it('rejects non-SUPER_ADMIN incident creation', async () => {
    const res = await appWithRoute().request('/api/admin/incidents', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Origin: 'https://admin.zync.is',
      },
      body: JSON.stringify({
        title: 'Email delivery delays',
        status: 'investigating',
        impact: 'major',
        affectedServices: ['email_delivery'],
        body: 'Investigating reports of email delivery delays.',
      }),
    })

    expect(res.status).toBe(403)
    await expect(res.json()).resolves.toMatchObject({ error: 'Forbidden' })
    expect(createIncident).not.toHaveBeenCalled()
  })

  it('rejects non-SUPER_ADMIN incident updates', async () => {
    const res = await appWithRoute().request(
      '/api/admin/incidents/11111111-1111-1111-1111-111111111111/update',
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          Origin: 'https://admin.zync.is',
        },
        body: JSON.stringify({
          status: 'identified',
          body: 'We have identified the upstream provider issue.',
        }),
      },
    )

    expect(res.status).toBe(403)
    await expect(res.json()).resolves.toMatchObject({ error: 'Forbidden' })
    expect(addIncidentUpdate).not.toHaveBeenCalled()
  })

  it('rejects non-SUPER_ADMIN incident resolution', async () => {
    const res = await appWithRoute().request(
      '/api/admin/incidents/11111111-1111-1111-1111-111111111111/resolve',
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          Origin: 'https://admin.zync.is',
        },
        body: JSON.stringify({
          body: 'Service is stable again and we are closing the incident.',
        }),
      },
    )

    expect(res.status).toBe(403)
    await expect(res.json()).resolves.toMatchObject({ error: 'Forbidden' })
    expect(resolveIncident).not.toHaveBeenCalled()
  })
})
