/**
 * Tests for OAuth connections API route
 *
 * @vitest-environment node
 */
import {
  authMockFns,
  createMockRequest,
  dbChainMock,
  dbChainMockFns,
  resetDbChainMock,
} from '@sim/testing'
import { beforeEach, describe, expect, it, vi } from 'vitest'

const { mockParseProvider, mockDecodeJwt, mockEq } = vi.hoisted(() => ({
  mockParseProvider: vi.fn(),
  mockDecodeJwt: vi.fn(),
  mockEq: vi.fn((field: unknown, value: unknown) => ({ field, value, type: 'eq' })),
}))

vi.mock('@sim/db', () => ({
  ...dbChainMock,
  account: { userId: 'userId', providerId: 'providerId' },
  user: { email: 'email', id: 'id' },
  eq: mockEq,
}))

vi.mock('drizzle-orm', () => ({
  eq: mockEq,
}))

vi.mock('jose', () => ({
  decodeJwt: mockDecodeJwt,
}))

vi.mock('@/lib/oauth/utils', () => ({
  parseProvider: mockParseProvider,
}))

import { GET } from '@/app/api/auth/oauth/connections/route'

describe('OAuth Connections API Route', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    resetDbChainMock()

    mockParseProvider.mockImplementation((providerId: string) => ({
      baseProvider: providerId.split('-')[0] || providerId,
      featureType: providerId.split('-')[1] || 'default',
    }))
  })

  it('should return connections successfully', async () => {
    authMockFns.mockGetSession.mockResolvedValueOnce({
      user: { id: 'user-123' },
    })

    const mockAccounts = [
      {
        id: 'account-1',
        providerId: 'google-email',
        accountId: 'test@example.com',
        scope: 'email profile',
        updatedAt: new Date('2024-01-01'),
        idToken: null,
      },
      {
        id: 'account-2',
        providerId: 'github',
        accountId: 'testuser',
        scope: 'repo',
        updatedAt: new Date('2024-01-02'),
        idToken: null,
      },
    ]

    const mockUserRecord = [{ email: 'user@example.com' }]

    dbChainMockFns.where.mockResolvedValueOnce(mockAccounts)
    dbChainMockFns.limit.mockResolvedValueOnce(mockUserRecord)

    const req = createMockRequest('GET')

    const response = await GET(req)
    const data = await response.json()

    expect(response.status).toBe(200)
    expect(data.connections).toHaveLength(2)
    expect(data.connections[0]).toMatchObject({
      provider: 'google-email',
      baseProvider: 'google',
      featureType: 'email',
      isConnected: true,
    })
    expect(data.connections[1]).toMatchObject({
      provider: 'github',
      baseProvider: 'github',
      featureType: 'default',
      isConnected: true,
    })
  })

  it('should handle unauthenticated user', async () => {
    authMockFns.mockGetSession.mockResolvedValueOnce(null)

    const req = createMockRequest('GET')

    const response = await GET(req)
    const data = await response.json()

    expect(response.status).toBe(401)
    expect(data.error).toBe('User not authenticated')
  })

  it('should handle user with no connections', async () => {
    authMockFns.mockGetSession.mockResolvedValueOnce({
      user: { id: 'user-123' },
    })

    dbChainMockFns.where.mockResolvedValueOnce([])
    dbChainMockFns.limit.mockResolvedValueOnce([])

    const req = createMockRequest('GET')

    const response = await GET(req)
    const data = await response.json()

    expect(response.status).toBe(200)
    expect(data.connections).toHaveLength(0)
  })

  it('should handle database error', async () => {
    authMockFns.mockGetSession.mockResolvedValueOnce({
      user: { id: 'user-123' },
    })

    dbChainMockFns.where.mockRejectedValueOnce(new Error('Database error'))

    const req = createMockRequest('GET')

    const response = await GET(req)
    const data = await response.json()

    expect(response.status).toBe(500)
    expect(data.error).toBe('Internal server error')
  })

  it('should decode ID token for display name', async () => {
    authMockFns.mockGetSession.mockResolvedValueOnce({
      user: { id: 'user-123' },
    })

    const mockAccounts = [
      {
        id: 'account-1',
        providerId: 'google',
        accountId: 'google-user-id',
        scope: 'email profile',
        updatedAt: new Date('2024-01-01'),
        idToken: 'mock-jwt-token',
      },
    ]

    mockDecodeJwt.mockReturnValueOnce({
      email: 'decoded@example.com',
      name: 'Decoded User',
    })

    dbChainMockFns.where.mockResolvedValueOnce(mockAccounts)
    dbChainMockFns.limit.mockResolvedValueOnce([])

    const req = createMockRequest('GET')

    const response = await GET(req)
    const data = await response.json()

    expect(response.status).toBe(200)
    expect(data.connections[0].accounts[0].name).toBe('decoded@example.com')
  })
})
