import { beforeEach, describe, expect, it, vi } from 'vitest'
import { Hono } from 'hono'
import { TenantTier } from '@zync/types'
import type { AppEnv } from '../src/types'

const mockListSlaPolicies = vi.fn()
const mockGetSlaEnabled = vi.fn()
const mockGetSlaPolicyById = vi.fn()
const mockUpdateSlaPolicy = vi.fn()
const mockCreateDb = vi.fn(() => ({}))

const session = {
  type: 'user',
  sub: 'user-1',
  tid: 'tenant-1',
  role: 'OWNER',
  permissions: ['settings:read', 'settings:write'],
}

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

vi.mock('../src/middleware/guards', () => ({
  requirePermission: (permission: string) => {
    return async (
      c: {
        get: (key: string) => { permissions?: string[] } | undefined
        json: (body: unknown, status: number) => Response
      },
      next: () => Promise<void>,
    ) => {
      const current = c.get('session')
      if (!current?.permissions?.includes(permission)) {
        return c.json({ error: 'Forbidden' }, 403)
      }
      await next()
    }
  },
  requireTier: (_tier: TenantTier) => {
    return async (_c: unknown, next: () => Promise<void>) => next()
  },
}))

vi.mock('@zync/db/queries', async () => {
  const actual = await vi.importActual<Record<string, unknown>>('@zync/db/queries')
  return {
    ...actual,
    createDb: (...args: unknown[]) => mockCreateDb(...args),
    listSlaPolicies: (...args: unknown[]) => mockListSlaPolicies(...args),
    getSlaEnabled: (...args: unknown[]) => mockGetSlaEnabled(...args),
    getSlaPolicyById: (...args: unknown[]) => mockGetSlaPolicyById(...args),
    updateSlaPolicy: (...args: unknown[]) => mockUpdateSlaPolicy(...args),
  }
})

import { slaPolicyRoutes } from '../src/routes/support/sla'

function appWithRoute() {
  const app = new Hono<AppEnv>()
  app.route('/api/settings/sla', slaPolicyRoutes)
  return app
}

describe('ticket SLA settings route', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    session.role = 'OWNER'
    session.permissions = ['settings:read', 'settings:write']
    mockListSlaPolicies.mockResolvedValue([
      {
        id: 'policy-1',
        tenant_id: 'tenant-1',
        priority: 'urgent',
        first_response_hours: 1,
        resolution_hours: 4,
        escalation_email: 'ops@example.com',
        notify_email: true,
        notify_in_app: true,
        created_at: '2026-07-01T00:00:00.000Z',
        updated_at: '2026-07-01T00:00:00.000Z',
      },
    ])
    mockGetSlaEnabled.mockResolvedValue(true)
    mockGetSlaPolicyById.mockResolvedValue({ id: 'policy-1' })
    mockUpdateSlaPolicy.mockResolvedValue({ id: 'policy-1', priority: 'urgent' })
  })

  it('returns policies together with sla_enabled on GET /api/settings/sla', async () => {
    const res = await appWithRoute().request('/api/settings/sla')

    expect(res.status).toBe(200)
    await expect(res.json()).resolves.toEqual({
      policies: expect.any(Array),
      sla_enabled: true,
    })
    expect(mockListSlaPolicies).toHaveBeenCalledWith({}, 'tenant-1')
    expect(mockGetSlaEnabled).toHaveBeenCalledWith({}, 'tenant-1')
  })

  it('rejects GET for a non-owner-admin role even with settings:read', async () => {
    session.role = 'MEMBER'

    const res = await appWithRoute().request('/api/settings/sla')

    expect(res.status).toBe(403)
    await expect(res.json()).resolves.toEqual({ error: 'Forbidden — OWNER or ADMIN only' })
  })

  it('rejects PATCH for non-owner sessions', async () => {
    session.role = 'ADMIN'

    const res = await appWithRoute().request('/api/settings/sla/policy-1', {
      method: 'PATCH',
      headers: { 'content-type': 'application/json' },
      body: JSON.stringify({ resolution_hours: 8 }),
    })

    expect(res.status).toBe(403)
    await expect(res.json()).resolves.toEqual({ error: 'Forbidden — OWNER only' })
  })
})
