import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { POST } from '@/app/api/chat/route'
import { NextRequest } from 'next/server'
import { resetFlagsCache } from '@/lib/flags'

// Mock fetch globally
global.fetch = vi.fn()

describe('/api/chat', () => {
  const originalEnv = { ...process.env }

  beforeEach(() => {
    resetFlagsCache()
    vi.clearAllMocks()

    // Set up default agent
    process.env.AGENT_1_URL = 'https://example.com/webhook/test'
    process.env.IMAGE_UPLOADS_ENABLED = 'true'
    process.env.DIFF_TOOL_ENABLED = 'true'
  })

  afterEach(() => {
    process.env = { ...originalEnv }
    vi.restoreAllMocks()
  })

  it('requires message field', async () => {
    const request = new NextRequest('http://localhost:3000/api/chat', {
      method: 'POST',
      body: JSON.stringify({
        agentId: 'agent-1',
        sessionId: 'test-session',
        timestamp: new Date().toISOString(),
      }),
    })

    const response = await POST(request)
    const data = await response.json()

    expect(response.status).toBe(400)
    expect(data.error).toBe('Message is required')
  })

  it('requires agentId field', async () => {
    const request = new NextRequest('http://localhost:3000/api/chat', {
      method: 'POST',
      body: JSON.stringify({
        message: 'Hello',
        sessionId: 'test-session',
        timestamp: new Date().toISOString(),
      }),
    })

    const response = await POST(request)
    const data = await response.json()

    expect(response.status).toBe(400)
    expect(data.error).toBe('Agent ID is required')
  })

  it('rejects images when IMAGE_UPLOADS_ENABLED is false', async () => {
    process.env.IMAGE_UPLOADS_ENABLED = 'false'
    resetFlagsCache()

    const request = new NextRequest('http://localhost:3000/api/chat', {
      method: 'POST',
      body: JSON.stringify({
        message: 'Hello',
        agentId: 'agent-1',
        sessionId: 'test-session',
        timestamp: new Date().toISOString(),
        images: ['data:image/png;base64,abc123'],
      }),
    })

    const response = await POST(request)
    const data = await response.json()

    expect(response.status).toBe(403)
    expect(data.error).toBe('Image uploads are currently disabled')
  })

  it('forwards message to webhook successfully', async () => {
    const mockResponse = JSON.stringify({ response: 'Hello back!' })

    ;(global.fetch as any).mockResolvedValueOnce({
      ok: true,
      status: 200,
      text: async () => mockResponse,
    })

    const request = new NextRequest('http://localhost:3000/api/chat', {
      method: 'POST',
      body: JSON.stringify({
        message: 'Hello',
        agentId: 'agent-1',
        sessionId: 'test-session',
        timestamp: new Date().toISOString(),
      }),
    })

    const response = await POST(request)
    const data = await response.json()

    expect(response.status).toBe(200)
    expect(data.response).toBe('Hello back!')
    expect(global.fetch).toHaveBeenCalledWith(
      'https://example.com/webhook/test',
      expect.objectContaining({
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
      })
    )
  })

  it('handles streaming response with chunks', async () => {
    const mockResponse = `{"type":"item","content":"Hello "}
{"type":"item","content":"World!"}`

    ;(global.fetch as any).mockResolvedValueOnce({
      ok: true,
      status: 200,
      text: async () => mockResponse,
    })

    const request = new NextRequest('http://localhost:3000/api/chat', {
      method: 'POST',
      body: JSON.stringify({
        message: 'Hi',
        agentId: 'agent-1',
        sessionId: 'test-session',
        timestamp: new Date().toISOString(),
      }),
    })

    const response = await POST(request)
    const data = await response.json()

    expect(response.status).toBe(200)
    expect(data.response).toBe('Hello World!')
  })

  it('converts diff tool calls to markdown when enabled', async () => {
    const mockResponse = JSON.stringify({
      type: 'tool_call',
      name: 'show_diff',
      args: {
        oldCode: 'const x = 1',
        newCode: 'const x = 2',
        title: 'Update value',
        language: 'javascript',
      },
    })

    ;(global.fetch as any).mockResolvedValueOnce({
      ok: true,
      status: 200,
      text: async () => mockResponse,
    })

    const request = new NextRequest('http://localhost:3000/api/chat', {
      method: 'POST',
      body: JSON.stringify({
        message: 'Show me diff',
        agentId: 'agent-1',
        sessionId: 'test-session',
        timestamp: new Date().toISOString(),
      }),
    })

    const response = await POST(request)
    const data = await response.json()

    expect(response.status).toBe(200)
    expect(data.response).toContain('```diff-tool')
    expect(data.response).toContain('oldCode')
    expect(data.response).toContain('newCode')
  })

  it('converts diff tool calls to plain markdown when disabled', async () => {
    process.env.DIFF_TOOL_ENABLED = 'false'
    resetFlagsCache()

    const mockResponse = JSON.stringify({
      type: 'tool_call',
      name: 'show_diff',
      args: {
        oldCode: 'const x = 1',
        newCode: 'const x = 2',
        title: 'Update value',
        language: 'javascript',
      },
    })

    ;(global.fetch as any).mockResolvedValueOnce({
      ok: true,
      status: 200,
      text: async () => mockResponse,
    })

    const request = new NextRequest('http://localhost:3000/api/chat', {
      method: 'POST',
      body: JSON.stringify({
        message: 'Show me diff',
        agentId: 'agent-1',
        sessionId: 'test-session',
        timestamp: new Date().toISOString(),
      }),
    })

    const response = await POST(request)
    const data = await response.json()

    expect(response.status).toBe(200)
    expect(data.response).not.toContain('```diff-tool')
    expect(data.response).toContain('**Before:**')
    expect(data.response).toContain('**After:**')
  })

  it('returns error for unconfigured agent', async () => {
    const request = new NextRequest('http://localhost:3000/api/chat', {
      method: 'POST',
      body: JSON.stringify({
        message: 'Hello',
        agentId: 'agent-99',
        sessionId: 'test-session',
        timestamp: new Date().toISOString(),
      }),
    })

    const response = await POST(request)
    const data = await response.json()

    expect(response.status).toBe(400)
    expect(data.error).toContain('not properly configured')
  })
})
