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

const mockGetTenantTimezone = vi.fn()
const mockSetTenantTimezone = vi.fn()
const mockRequirePermission = vi.fn()

let mockSession: Record<string, unknown>

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('../src/middleware/guards', () => ({
  requirePermission: (...args: unknown[]) => mockRequirePermission(...args),
}))

vi.mock('@zync/db/queries', () => ({
  createDb: vi.fn(() => ({})),
  getTenantTimezone: (...args: unknown[]) => mockGetTenantTimezone(...args),
  setTenantTimezone: (...args: unknown[]) => mockSetTenantTimezone(...args),
}))

async function appWithRoute() {
  const { settingsLocaleRoute } = await import('../src/routes/settings/locale')
  const app = new Hono<AppEnv>()
  app.route('/api/settings/locale', settingsLocaleRoute)
  return app
}

describe('settings locale route', () => {
  beforeEach(() => {
    vi.resetModules()
    vi.clearAllMocks()
    mockSession = {
      type: 'user',
      sub: 'user-1',
      tid: 'tenant-1',
      permissions: ['settings:modules:write'],
    }
    mockRequirePermission.mockImplementation(
      (permission: string) =>
        async (
          c: {
            get: (key: string) => { permissions?: string[] } | undefined
            json: (body: unknown, status: number) => Response
          },
          next: () => Promise<void>,
        ) => {
          const session = c.get('session')
          if (!session?.permissions?.includes(permission)) {
            return c.json({ error: 'Forbidden' }, 403)
          }
          await next()
        },
    )
  })

  it('returns the current tenant operations timezone from GET /', async () => {
    mockGetTenantTimezone.mockResolvedValue('America/New_York')
    const app = await appWithRoute()

    const res = await app.request('/api/settings/locale')
    const body = await res.json() as Record<string, unknown>

    expect(res.status).toBe(200)
    expect(body).toEqual({ timezone: 'America/New_York' })
    expect(mockGetTenantTimezone).toHaveBeenCalledWith({}, 'tenant-1')
  })

  it('returns the updated timezone shape from PATCH /', async () => {
    mockSetTenantTimezone.mockResolvedValue({ defaultTimezone: 'Europe/London' })
    const app = await appWithRoute()

    const res = await app.request('/api/settings/locale', {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ timezone: 'Europe/London' }),
    })
    const body = await res.json() as Record<string, unknown>

    expect(res.status).toBe(200)
    expect(body).toEqual({ timezone: 'Europe/London' })
    expect(mockSetTenantTimezone).toHaveBeenCalledWith({}, 'tenant-1', 'user-1', 'Europe/London')
  })
})
