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

type Row = { user_id: string; username: string; supabase_auth_user_id: string | null }
const database = vi.hoisted(() => ({ rows: new Map<string, Row>() }))

vi.mock('@/lib/supabase/admin', () => ({
  createAdminClient: () => ({
    from: () => ({
      select: () => ({
        eq: (column: string, value: string) => ({
          maybeSingle: async () => ({
            data: [...database.rows.values()].find((row) => row[column as keyof Row] === value) ?? null,
            error: null,
          }),
        }),
      }),
      update: (patch: Partial<Row>) => ({
        eq: (_column: string, userId: string) => ({
          is: () => ({
            select: () => ({
              maybeSingle: async () => {
                const row = database.rows.get(userId)
                if (!row?.supabase_auth_user_id && row &&
                    ![...database.rows.values()].some((candidate) => candidate.supabase_auth_user_id === patch.supabase_auth_user_id)) {
                  Object.assign(row, patch)
                  return { data: row, error: null }
                }
                return { data: null, error: null }
              },
            }),
          }),
        }),
      }),
      insert: async (row: Row) => {
        if (database.rows.has(row.user_id) ||
            [...database.rows.values()].some((candidate) => candidate.supabase_auth_user_id === row.supabase_auth_user_id)) {
          return { error: { message: 'duplicate key' } }
        }
        database.rows.set(row.user_id, row)
        return { error: null }
      },
    }),
  }),
}))

import { findAppAccountBySupabaseUserId, linkAppAccountToSupabaseUser } from '@/lib/auth/google-account-link'

beforeEach(() => database.rows.clear())

describe('Google identity link', () => {
  it('persists the Supabase Auth user, allows repeat sign-in, and refuses a different identity', async () => {
    const first = { appUserId: 'app-1', username: 'driver@example.com', supabaseUserId: 'auth-1' }
    expect(await linkAppAccountToSupabaseUser(first)).toBe(true)
    expect(await findAppAccountBySupabaseUserId('auth-1')).toBe('app-1')
    expect(await linkAppAccountToSupabaseUser(first)).toBe(true)
    expect(await linkAppAccountToSupabaseUser({ ...first, supabaseUserId: 'auth-2' })).toBe(false)
    expect(await linkAppAccountToSupabaseUser({ appUserId: 'app-2', username: 'other@example.com', supabaseUserId: 'auth-1' })).toBe(false)
    expect(await findAppAccountBySupabaseUserId('auth-2')).toBeNull()
  })

  it('links an existing app account without replacing its other fields', async () => {
    database.rows.set('app-1', { user_id: 'app-1', username: 'existing@example.com', supabase_auth_user_id: null })
    expect(await linkAppAccountToSupabaseUser({ appUserId: 'app-1', username: 'changed@example.com', supabaseUserId: 'auth-1' })).toBe(true)
    expect(database.rows.get('app-1')).toMatchObject({ username: 'existing@example.com', supabase_auth_user_id: 'auth-1' })
  })
})
