import { describe, expect, it, vi } from 'vitest'
import { Hono } from 'hono'
import type { AppEnv } from '../src/types'
import { loginRoute } from '../src/routes/auth/login'

describe('login durable-object offload', () => {
  it('keeps edge validation outside the DO and forwards the login response intact', async () => {
    const fetch = vi.fn(async (_input: RequestInfo | URL, init?: RequestInit) => {
      const request = new Request(_input, init)
      expect(new URL(request.url).pathname).toBe('/login')
      expect(request.headers.get('x-zync-authwrite')).toBe('internal-secret')
      const body = (await request.json()) as {
        email: string
        password: string
        headers: Record<string, string>
      }
      expect(body).toMatchObject({
        email: 'user@example.com',
        password: 'password123',
        headers: {
          cookie: 'zync_device_trust=trusted',
          'cf-connecting-ip': '203.0.113.10',
        },
      })
      return new Response(JSON.stringify({ expiresAt: 123 }), {
        status: 200,
        headers: {
          'content-type': 'application/json',
          'set-cookie': 'zync_session=signed; HttpOnly; Secure; Path=/',
        },
      })
    })
    const limit = vi.fn(async () => ({ success: true }))
    const env = {
      AUTHWRITE_DO_SECRET: 'internal-secret',
      AUTHWRITE_DO: {
        idFromName: vi.fn(() => ({ toString: () => 'id' })),
        get: vi.fn(() => ({ fetch })),
      },
      RATE_LIMITER_AUTH: { limit },
    } as unknown as AppEnv['Bindings']
    const app = new Hono<AppEnv>().route('/api/auth', loginRoute)

    const response = await app.request(
      '/api/auth/login',
      {
        method: 'POST',
        headers: {
          Origin: 'https://app.zync.is',
          'Content-Type': 'application/json',
          Cookie: 'zync_device_trust=trusted',
          'CF-Connecting-IP': '203.0.113.10',
        },
        body: JSON.stringify({ email: 'user@example.com', password: 'password123' }),
      },
      env,
    )

    expect(limit).toHaveBeenCalledWith({ key: 'login:203.0.113.10' })
    expect(fetch).toHaveBeenCalledOnce()
    expect(response.status).toBe(200)
    expect(response.headers.get('set-cookie')).toContain('zync_session=signed')
    await expect(response.json()).resolves.toEqual({ expiresAt: 123 })
  })

  it('fails closed when a configured DO cannot return a response', async () => {
    const diagnostic = vi.spyOn(console, 'warn').mockImplementation(() => undefined)
    const env = {
      AUTHWRITE_DO_SECRET: 'internal-secret',
      AUTHWRITE_DO: {
        idFromName: vi.fn(() => ({ toString: () => 'id' })),
        get: vi.fn(() => ({ fetch: vi.fn(async () => { throw new Error('unavailable') }) })),
      },
      RATE_LIMITER_AUTH: { limit: vi.fn(async () => ({ success: true })) },
    } as unknown as AppEnv['Bindings']
    const app = new Hono<AppEnv>().route('/api/auth', loginRoute)

    const response = await app.request(
      '/api/auth/login',
      {
        method: 'POST',
        headers: { Origin: 'https://app.zync.is', 'Content-Type': 'application/json' },
        body: JSON.stringify({ email: 'user@example.com', password: 'password123' }),
      },
      env,
    )

    expect(response.status).toBe(503)
    await expect(response.json()).resolves.toEqual({
      error: 'Login temporarily unavailable. Please retry.',
    })
    expect(diagnostic).toHaveBeenCalledOnce()
    expect(diagnostic).toHaveBeenCalledWith(
      'AuthWriteDO login transport failure — not inline-retrying session issuance',
    )
    diagnostic.mockRestore()
  })
})
