import { vi } from 'vitest'
import type {
  SupabaseClient,
  SupabaseUserProfile,
  SupabaseOrganization,
  SupabaseOrgMembership,
  SupabaseApiKey
} from '../../supabase'

/**
 * Fixture data structure for mock Supabase client
 */
export interface MockSupabaseFixtures {
  users?: SupabaseUserProfile[]
  organizations?: SupabaseOrganization[]
  org_memberships?: SupabaseOrgMembership[]
  api_keys?: SupabaseApiKey[]
}

/**
 * Mock Supabase client with query builder pattern
 *
 * Supports common query patterns:
 * - .from(table).select().eq(column, value).single()
 * - .from(table).select().eq(column, value).maybeSingle()
 * - .from(table).select().eq(column1, value1).eq(column2, value2).single()
 *
 * Usage:
 * ```typescript
 * import { createMockSupabaseClient, TEST_USERS, TEST_ORGS } from '@elevasis/core/test-utils'
 *
 * const mockClient = createMockSupabaseClient({
 *   users: [TEST_USERS.admin, TEST_USERS.regularUser],
 *   organizations: [TEST_ORGS.acme]
 * })
 *
 * vi.mock('../lib/supabase', () => ({ supabaseClient: mockClient }))
 * ```
 */
export function createMockSupabaseClient(fixtures: MockSupabaseFixtures = {}): Partial<SupabaseClient> {
  const tables = {
    users: fixtures.users || [],
    organizations: fixtures.organizations || [],
    org_memberships: fixtures.org_memberships || [],
    api_keys: fixtures.api_keys || []
  }

  // Create mock query builder
  const createQueryBuilder = (tableName: keyof typeof tables) => {
    let filters: Array<{ column: string; value: unknown }> = []

    const queryBuilder = {
      select: vi.fn((_columns?: string) => {
        return {
          eq: vi.fn((column: string, value: unknown) => {
            filters.push({ column, value })
            return {
              eq: vi.fn((column2: string, value2: unknown) => {
                filters.push({ column: column2, value: value2 })
                return {
                  single: vi.fn(async () => {
                    const table = tables[tableName]
                    const row = table?.find((r: unknown) =>
                      filters.every((f) => (r as Record<string, unknown>)[f.column] === f.value)
                    )
                    if (row) {
                      return { data: row, error: null }
                    }
                    return {
                      data: null,
                      error: { message: 'Row not found', code: 'PGRST116', details: null, hint: null }
                    }
                  }),
                  maybeSingle: vi.fn(async () => {
                    const table = tables[tableName]
                    const row = table?.find((r: unknown) =>
                      filters.every((f) => (r as Record<string, unknown>)[f.column] === f.value)
                    )
                    return { data: row || null, error: null }
                  })
                }
              }),
              single: vi.fn(async () => {
                const table = tables[tableName]
                const row = table?.find((r: unknown) => filters.every((f) => (r as Record<string, unknown>)[f.column] === f.value))
                if (row) {
                  return { data: row, error: null }
                }
                return {
                  data: null,
                  error: { message: 'Row not found', code: 'PGRST116', details: null, hint: null }
                }
              }),
              maybeSingle: vi.fn(async () => {
                const table = tables[tableName]
                const row = table?.find((r: unknown) => filters.every((f) => (r as Record<string, unknown>)[f.column] === f.value))
                return { data: row || null, error: null }
              })
            }
          }),
          order: vi.fn((_column: string, _options?: { ascending?: boolean }) => {
            return {
              then: vi.fn(async (resolve: (data: unknown) => unknown) => {
                const table = tables[tableName] || []
                return resolve({ data: table, error: null })
              })
            }
          })
        }
      })
    }

    return queryBuilder
  }

  return {
    from: vi.fn((tableName: string) => {
      return createQueryBuilder(tableName as keyof typeof tables)
    })
  } as unknown as SupabaseClient
}

/**
 * Helper to create a mock that returns specific data for a query
 *
 * Usage:
 * ```typescript
 * const mockClient = createMockSupabaseResponse('users', TEST_USERS.admin)
 * ```
 */
export function createMockSupabaseResponse<T>(_tableName: string, data: T | null, error: unknown = null) {
  return {
    from: vi.fn(() => ({
      select: vi.fn(() => ({
        eq: vi.fn(() => ({
          single: vi.fn(async () => ({ data, error })),
          maybeSingle: vi.fn(async () => ({ data, error }))
        }))
      }))
    }))
  }
}
