/**
 * Tests de sincronización de rol desde DB.
 * Verifica que buildAuthUser retorna el valor optimista correcto y que
 * syncProfileFromDB sobrescribe la heurística de email con el rol real de DB.
 */
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { SupabaseAuthService } from '@/auth/SupabaseAuthService'

// ─── Mocks con vi.hoisted para evitar el TDZ al ser elevados al tope del archivo ──

const { mockGetSession, mockMaybeSingle } = vi.hoisted(() => ({
  mockGetSession: vi.fn(),
  mockMaybeSingle: vi.fn(),
}))

vi.mock('@/lib/supabase', () => {
  const buildChain = () => {
    const chain: Record<string, unknown> = {}
    chain.select = vi.fn().mockReturnValue(chain)
    chain.eq = vi.fn().mockReturnValue(chain)
    chain.abortSignal = vi.fn().mockReturnValue(chain)
    chain.maybeSingle = mockMaybeSingle
    return chain
  }

  return {
    supabase: {
      auth: {
        getSession: mockGetSession,
        onAuthStateChange: vi.fn(() => ({ data: { subscription: { unsubscribe: vi.fn() } } })),
        signInWithPassword: vi.fn(),
      },
      from: vi.fn().mockImplementation(() => buildChain()),
    },
    SUPABASE_URL: 'https://test.supabase.co',
    SUPABASE_ANON_KEY: 'test-key',
  }
})

// ─── Tests ───────────────────────────────────────────────────────────────────

describe('SupabaseAuthService', () => {
  const service = new SupabaseAuthService()

  beforeEach(() => {
    vi.clearAllMocks()
    mockMaybeSingle.mockResolvedValue({ data: null })
  })

  describe('buildAuthUser (vía getCurrentUser)', () => {
    it('devuelve platform_admin optimista para email @inquality.com.py', async () => {
      mockGetSession.mockResolvedValue({
        data: {
          session: {
            user: {
              id: 'user-1',
              email: 'test@inquality.com.py',
              user_metadata: { full_name: 'Test InQ' },
            },
          },
        },
      })

      const user = await service.getCurrentUser()
      expect(user?.platformRole).toBe('platform_admin')
      expect(user?.email).toBe('test@inquality.com.py')
    })

    it('devuelve guest optimista para email externo', async () => {
      mockGetSession.mockResolvedValue({
        data: {
          session: {
            user: {
              id: 'user-2',
              email: 'cliente@empresa.com',
              user_metadata: { full_name: 'Cliente Externo' },
            },
          },
        },
      })

      const user = await service.getCurrentUser()
      expect(user?.platformRole).toBe('guest')
    })
  })

  describe('syncProfileFromDB', () => {
    it('retorna client_editor desde DB (sobrescribe heurística guest para email externo)', async () => {
      mockMaybeSingle.mockResolvedValue({
        data: {
          name: 'Lucia García',
          company: 'Banco Solar',
          platform_role: 'client_editor',
          org_id: 'org-abc-123',
        },
      })

      const profile = await service.syncProfileFromDB('user-2')
      expect(profile?.platformRole).toBe('client_editor')
      expect(profile?.orgId).toBe('org-abc-123')
      expect(profile?.company).toBe('Banco Solar')
    })

    it('retorna platform_admin desde DB incluso para email sin dominio @inquality', async () => {
      mockMaybeSingle.mockResolvedValue({
        data: {
          name: 'Admin Externo',
          company: null,
          platform_role: 'platform_admin',
          org_id: 'org-inq-456',
        },
      })

      const profile = await service.syncProfileFromDB('user-3')
      expect(profile?.platformRole).toBe('platform_admin')
      expect(profile?.orgId).toBe('org-inq-456')
    })

    it('retiene orgId correctamente tras sync con client_viewer', async () => {
      const orgId = 'b1c2d3e4-f5a6-7890-abcd-ef1234567890'
      mockMaybeSingle.mockResolvedValue({
        data: {
          name: 'Viewer Test',
          company: 'Empresa SA',
          platform_role: 'client_viewer',
          org_id: orgId,
        },
      })

      const profile = await service.syncProfileFromDB('user-4')
      expect(profile?.orgId).toBe(orgId)
      expect(profile?.platformRole).toBe('client_viewer')
    })

    it('retorna null cuando el usuario no existe en DB', async () => {
      mockMaybeSingle.mockResolvedValue({ data: null })

      const profile = await service.syncProfileFromDB('nonexistent-user')
      expect(profile).toBeNull()
    })
  })
})
