import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { extractPermit } from '@/lib/adapters/flask'
import { NextRequest } from 'next/server'

const mocks = vi.hoisted(() => ({ admin: vi.fn(), process: vi.fn() }))
vi.mock('@/lib/supabase/admin', () => ({ createAdminClient: mocks.admin }))
vi.mock('@/lib/data/permit-processing', () => ({ processWorkspacePermit: mocks.process }))
import { POST } from '@/app/api/internal/permit-processing/route'

beforeEach(() => {
  vi.stubEnv('HHA_API_BASE_URL', 'https://gpt.test')
  vi.stubEnv('CRON_SECRET', 'test-only-'.repeat(5))
  mocks.admin.mockReset(); mocks.process.mockReset()
})
afterEach(() => { vi.unstubAllGlobals(); vi.unstubAllEnvs() })

describe('route extraction contract', () => {
  it.each(['unsupported', 'failed'])('preserves GPT route status %s', async (status) => {
    vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response(JSON.stringify({
      states_info: [{ state_name: 'Texas', route_token: null, route_status: status }],
    }))))
    expect((await extractPermit(new Blob(['test']), 'permit.pdf')).data?.route_status).toBe(status)
  })

  it('keeps a namespaced Workspace token and its provenance without claiming a ready map', async () => {
    vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response(JSON.stringify({
      states_info: [{ state_name: 'Texas', route_token: 'workspace:abc', route_source: 'workspace', route_status: 'needs_preparation' }],
    }))))
    expect((await extractPermit(new Blob(['test']), 'permit.pdf')).data).toMatchObject({
      route_token: 'workspace:abc', route_source: 'workspace', route_status: 'needs_preparation',
    })
  })

  it('delivers matched route links and named route text from GPT', async () => {
    vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response(JSON.stringify({
      states_info: [{
        state_name: 'South Carolina', route_token: '470154', route_source: 'synchron', route_status: 'ready',
        route_texts: { routing_from: 'Charleston', routing_to: 'Georgia state line', via: 'I-20' },
        route_links: ['https://maps.example.test/part-1', 'javascript:alert(1)'],
      }],
    }))))
    expect((await extractPermit(new Blob(['test']), 'permit.pdf')).data).toMatchObject({
      route_token: '470154', route_source: 'synchron', route_status: 'ready',
      route_description: 'Charleston Georgia state line I-20',
      route_links: ['https://maps.example.test/part-1'],
    })
  })

  it('does not claim a ready route when no safe link was returned', async () => {
    vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response(JSON.stringify({
      states_info: [{ state_name: 'Texas', route_token: '123', route_status: 'ready', route_links: ['http://localhost/map'] }],
    }))))
    expect((await extractPermit(new Blob(['test']), 'permit.pdf')).data).toMatchObject({
      route_status: 'needs_preparation', route_links: [],
    })
  })

  it.each(['application/pdf', 'image/png', 'image/jpeg'])('uses the unchanged GPT token-only response for %s', async (type) => {
    const fetch = vi.fn().mockResolvedValue(new Response(JSON.stringify({
      states_info: [{ state_name: 'Texas', route_token: '123', route_texts: ['I-10'] }],
    })))
    vi.stubGlobal('fetch', fetch)
    const file = new Blob(['test'], { type })
    const result = await extractPermit(file, 'permit', { tripId: 'trip', permitId: 'permit', documentId: 'doc', sourceUrl: 'https://files.test/permit' })
    expect(result.data).toMatchObject({ route_token: '123', route_status: 'needs_preparation', route_description: 'I-10' })
    expect(result.data?.route_gpx_url).toBeUndefined()
    expect(fetch).toHaveBeenCalledOnce()
    const [url, init] = fetch.mock.calls[0]
    expect(url).toBe('https://gpt.test/api/workspace/extract/permit')
    expect(init.body.get('permit_id')).toBe('permit')
    expect(init.body.get('source_url')).toBe('https://files.test/permit')
    expect(init.body.get('file').type).toBe(type)
  })

  it('does not claim route success when GPT returns no token', async () => {
    const fetch = vi.fn().mockResolvedValue(new Response(JSON.stringify({ states_info: [{ state_name: 'Texas', route_token: null }] })))
    vi.stubGlobal('fetch', fetch)
    expect((await extractPermit(new Blob(['test']), 'permit.pdf')).data?.route_status).toBe('failed')
    expect(fetch.mock.calls[0][0]).toBe('https://gpt.test/api/workspace/extract/permit')
    expect(fetch).toHaveBeenCalledOnce()
  })
})

describe('internal permit worker authorization', () => {
  it('rejects missing or wrong credentials before accessing any data', async () => {
    const response = await POST(new NextRequest('https://workspace.test/api/internal/permit-processing', { method: 'POST', body: '{}' }))
    expect(response.status).toBe(401)
    expect(mocks.admin).not.toHaveBeenCalled()
    expect(mocks.process).not.toHaveBeenCalled()
  })
  it('processes one due job when authorized', async () => {
    mocks.process.mockResolvedValue({ ok: true, status: 'ready' })
    const response = await POST(new NextRequest('https://workspace.test/api/internal/permit-processing', {
      method: 'POST', headers: { authorization: `Bearer ${process.env.CRON_SECRET}` }, body: '{}',
    }))
    expect(response.status).toBe(200)
    expect(mocks.process).toHaveBeenCalledOnce()
  })
})
