import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'

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

describe('DSFA API Client', () => {
  beforeEach(() => {
    mockFetch.mockClear()
  })

  afterEach(() => {
    vi.restoreAllMocks()
  })

  describe('listDSFAs', () => {
    it('should fetch DSFAs without status filter', async () => {
      const mockDSFAs = [
        { id: 'dsfa-1', name: 'Test DSFA 1', status: 'draft' },
        { id: 'dsfa-2', name: 'Test DSFA 2', status: 'approved' },
      ]

      mockFetch.mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve({ dsfas: mockDSFAs }),
      })

      const { listDSFAs } = await import('../api')
      const result = await listDSFAs()

      expect(mockFetch).toHaveBeenCalledTimes(1)
      expect(result).toHaveLength(2)
      expect(result[0].name).toBe('Test DSFA 1')
    })

    it('should fetch DSFAs with status filter', async () => {
      const mockDSFAs = [{ id: 'dsfa-1', name: 'Draft DSFA', status: 'draft' }]

      mockFetch.mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve({ dsfas: mockDSFAs }),
      })

      const { listDSFAs } = await import('../api')
      const result = await listDSFAs('draft')

      expect(mockFetch).toHaveBeenCalledTimes(1)
      const calledUrl = mockFetch.mock.calls[0][0]
      expect(calledUrl).toContain('status=draft')
    })

    it('should return empty array when no DSFAs', async () => {
      mockFetch.mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve({ dsfas: null }),
      })

      const { listDSFAs } = await import('../api')
      const result = await listDSFAs()

      expect(result).toEqual([])
    })
  })

  describe('getDSFA', () => {
    it('should fetch a single DSFA by ID', async () => {
      const mockDSFA = {
        id: 'dsfa-123',
        name: 'Test DSFA',
        status: 'draft',
        risks: [],
        mitigations: [],
      }

      mockFetch.mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve(mockDSFA),
      })

      const { getDSFA } = await import('../api')
      const result = await getDSFA('dsfa-123')

      expect(mockFetch).toHaveBeenCalledTimes(1)
      expect(result.id).toBe('dsfa-123')
      expect(result.name).toBe('Test DSFA')
    })

    it('should throw error for non-existent DSFA', async () => {
      mockFetch.mockResolvedValueOnce({
        ok: false,
        status: 404,
        text: () => Promise.resolve('{"error": "DSFA not found"}'),
      })

      const { getDSFA } = await import('../api')

      await expect(getDSFA('non-existent')).rejects.toThrow()
    })
  })

  describe('createDSFA', () => {
    it('should create a new DSFA', async () => {
      const newDSFA = {
        name: 'New DSFA',
        description: 'Test description',
        processing_purpose: 'Testing',
      }

      const createdDSFA = {
        id: 'dsfa-new',
        ...newDSFA,
        status: 'draft',
      }

      mockFetch.mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve(createdDSFA),
      })

      const { createDSFA } = await import('../api')
      const result = await createDSFA(newDSFA)

      expect(mockFetch).toHaveBeenCalledTimes(1)
      expect(result.id).toBe('dsfa-new')
      expect(result.name).toBe('New DSFA')
    })
  })

  describe('updateDSFA', () => {
    it('should update an existing DSFA', async () => {
      const updates = {
        name: 'Updated DSFA Name',
        processing_purpose: 'Updated purpose',
      }

      const updatedDSFA = {
        id: 'dsfa-123',
        ...updates,
        status: 'draft',
      }

      mockFetch.mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve(updatedDSFA),
      })

      const { updateDSFA } = await import('../api')
      const result = await updateDSFA('dsfa-123', updates)

      expect(mockFetch).toHaveBeenCalledTimes(1)
      expect(result.name).toBe('Updated DSFA Name')
    })
  })

  describe('deleteDSFA', () => {
    it('should delete a DSFA', async () => {
      mockFetch.mockResolvedValueOnce({
        ok: true,
      })

      const { deleteDSFA } = await import('../api')
      await deleteDSFA('dsfa-123')

      expect(mockFetch).toHaveBeenCalledTimes(1)
      const calledConfig = mockFetch.mock.calls[0][1]
      expect(calledConfig.method).toBe('DELETE')
    })

    it('should throw error when deletion fails', async () => {
      mockFetch.mockResolvedValueOnce({
        ok: false,
        statusText: 'Not Found',
      })

      const { deleteDSFA } = await import('../api')

      await expect(deleteDSFA('non-existent')).rejects.toThrow()
    })
  })

  describe('updateDSFASection', () => {
    it('should update a specific section', async () => {
      const sectionData = {
        processing_purpose: 'Updated purpose',
        data_categories: ['personal_data', 'contact_data'],
      }

      const updatedDSFA = {
        id: 'dsfa-123',
        section_progress: {
          section_1_complete: true,
        },
      }

      mockFetch.mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve(updatedDSFA),
      })

      const { updateDSFASection } = await import('../api')
      const result = await updateDSFASection('dsfa-123', 1, sectionData)

      expect(mockFetch).toHaveBeenCalledTimes(1)
      const calledUrl = mockFetch.mock.calls[0][0]
      expect(calledUrl).toContain('/sections/1')
    })
  })

  describe('submitDSFAForReview', () => {
    it('should submit DSFA for review', async () => {
      const response = {
        message: 'DSFA submitted for review',
        dsfa: {
          id: 'dsfa-123',
          status: 'in_review',
        },
      }

      mockFetch.mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve(response),
      })

      const { submitDSFAForReview } = await import('../api')
      const result = await submitDSFAForReview('dsfa-123')

      expect(mockFetch).toHaveBeenCalledTimes(1)
      expect(result.dsfa.status).toBe('in_review')
    })
  })

  describe('approveDSFA', () => {
    it('should approve a DSFA', async () => {
      mockFetch.mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve({ message: 'DSFA approved' }),
      })

      const { approveDSFA } = await import('../api')
      const result = await approveDSFA('dsfa-123', {
        dpo_opinion: 'Approved after review',
        approved: true,
      })

      expect(mockFetch).toHaveBeenCalledTimes(1)
      expect(result.message).toBe('DSFA approved')
    })

    it('should reject a DSFA', async () => {
      mockFetch.mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve({ message: 'DSFA rejected' }),
      })

      const { approveDSFA } = await import('../api')
      const result = await approveDSFA('dsfa-123', {
        dpo_opinion: 'Needs more details',
        approved: false,
      })

      expect(result.message).toBe('DSFA rejected')
    })
  })

  describe('getDSFAStats', () => {
    it('should fetch DSFA statistics', async () => {
      const stats = {
        total: 10,
        status_stats: {
          draft: 4,
          in_review: 2,
          approved: 3,
          rejected: 1,
        },
        risk_stats: {
          low: 3,
          medium: 4,
          high: 2,
          very_high: 1,
        },
      }

      mockFetch.mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve(stats),
      })

      const { getDSFAStats } = await import('../api')
      const result = await getDSFAStats()

      expect(mockFetch).toHaveBeenCalledTimes(1)
      expect(result.total).toBe(10)
      expect(result.status_stats.approved).toBe(3)
    })
  })

  describe('createDSFAFromAssessment', () => {
    it('should create DSFA from UCCA assessment', async () => {
      const response = {
        dsfa: {
          id: 'dsfa-new',
          name: 'AI Chatbot DSFA',
          status: 'draft',
        },
        prefilled: true,
        message: 'DSFA created from assessment',
      }

      mockFetch.mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve(response),
      })

      const { createDSFAFromAssessment } = await import('../api')
      const result = await createDSFAFromAssessment('assessment-123')

      expect(mockFetch).toHaveBeenCalledTimes(1)
      expect(result.prefilled).toBe(true)
      expect(result.dsfa.id).toBe('dsfa-new')
    })
  })

  describe('getDSFAByAssessment', () => {
    it('should return DSFA linked to assessment', async () => {
      const dsfa = {
        id: 'dsfa-123',
        assessment_id: 'assessment-123',
        name: 'Linked DSFA',
      }

      mockFetch.mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve(dsfa),
      })

      const { getDSFAByAssessment } = await import('../api')
      const result = await getDSFAByAssessment('assessment-123')

      expect(result?.id).toBe('dsfa-123')
    })

    it('should return null when no DSFA exists for assessment', async () => {
      mockFetch.mockResolvedValueOnce({
        ok: false,
        status: 404,
        text: () => Promise.resolve('Not found'),
      })

      const { getDSFAByAssessment } = await import('../api')
      const result = await getDSFAByAssessment('no-dsfa-assessment')

      expect(result).toBeNull()
    })
  })
})
