/**
 * Test database setup and teardown utilities for migration tests
 * Updated for PostgreSQL
 */

import { PrismaClient } from '@prisma/client'

/**
 * Create a Prisma client instance for testing
 * Uses DATABASE_URL from environment
 */
export function createTestPrismaClient(): PrismaClient {
  return new PrismaClient()
}

/**
 * Initialize test database schema
 * Runs prisma migrate deploy or db push
 */
export async function initializeTestDatabase(prisma: PrismaClient) {
  await prisma.$connect()
}

/**
 * Cleanup test database
 * Disconnects Prisma client and cleans all data
 */
export async function cleanupTestDatabase(prisma: PrismaClient) {
  try {
    // Delete in dependency order
    await prisma.aiFeedback.deleteMany()
    await prisma.memoryEchoInsight.deleteMany()
    await prisma.noteShare.deleteMany()
    await prisma.note.deleteMany()
    await prisma.label.deleteMany()
    await prisma.notebook.deleteMany()
    await prisma.userAISettings.deleteMany()
    await prisma.systemConfig.deleteMany()
    await prisma.session.deleteMany()
    await prisma.account.deleteMany()
    await prisma.verificationToken.deleteMany()
    await prisma.user.deleteMany()
    await prisma.$disconnect()
  } catch (error) {
    console.error('Error cleaning up test database:', error)
  }
}

/**
 * Create sample test data
 */
export async function createSampleNotes(prisma: PrismaClient, count: number = 10) {
  const notes = []
  const userId = 'test-user-123'

  for (let i = 0; i < count; i++) {
    const note = await prisma.note.create({
      data: {
        title: `Test Note ${i + 1}`,
        content: `This is test content for note ${i + 1}`,
        userId,
        color: `color-${i % 5}`,
        order: i,
        isPinned: i % 3 === 0,
        isArchived: false,
        type: 'text',
        size: i % 3 === 0 ? 'small' : 'medium'
      }
    })
    notes.push(note)
  }

  return notes
}

/**
 * Create sample AI-enabled notes
 */
export async function createSampleAINotes(prisma: PrismaClient, count: number = 10) {
  const notes = []
  const userId = 'test-user-ai'

  for (let i = 0; i < count; i++) {
    const note = await prisma.note.create({
      data: {
        title: `AI Test Note ${i + 1}`,
        content: `This is AI test content for note ${i + 1}`,
        userId,
        color: 'default',
        order: i,
        autoGenerated: i % 2 === 0,
        aiProvider: i % 3 === 0 ? 'openai' : 'ollama',
        aiConfidence: 70 + i * 2,
        language: i % 2 === 0 ? 'en' : 'fr',
        languageConfidence: 0.85 + (i * 0.01),
        lastAiAnalysis: new Date()
      }
    })
    notes.push(note)
  }

  return notes
}

/**
 * Measure execution time for a function
 */
export async function measureExecutionTime<T>(fn: () => Promise<T>): Promise<{ result: T; duration: number }> {
  const start = performance.now()
  const result = await fn()
  const end = performance.now()
  return {
    result,
    duration: end - start
  }
}

/**
 * Verify data integrity after migration
 */
export async function verifyDataIntegrity(prisma: PrismaClient, expectedNoteCount: number) {
  const noteCount = await prisma.note.count()

  if (noteCount !== expectedNoteCount) {
    throw new Error(`Data integrity check failed: Expected ${expectedNoteCount} notes, found ${noteCount}`)
  }

  return true
}

/**
 * Check if database table exists (PostgreSQL version)
 */
export async function verifyTableExists(prisma: PrismaClient, tableName: string): Promise<boolean> {
  try {
    const result = await prisma.$queryRawUnsafe<Array<{ exists: boolean }>>(
      `SELECT EXISTS (
        SELECT FROM information_schema.tables
        WHERE table_schema = 'public'
        AND table_name = $1
      )`,
      tableName
    )
    return result[0]?.exists ?? false
  } catch (error) {
    return false
  }
}

/**
 * Check if index exists on a table (PostgreSQL version)
 */
export async function verifyIndexExists(prisma: PrismaClient, tableName: string, indexName: string): Promise<boolean> {
  try {
    const result = await prisma.$queryRawUnsafe<Array<{ exists: boolean }>>(
      `SELECT EXISTS (
        SELECT FROM pg_indexes
        WHERE schemaname = 'public'
        AND tablename = $1
        AND indexname = $2
      )`,
      tableName,
      indexName
    )
    return result[0]?.exists ?? false
  } catch (error) {
    return false
  }
}

/**
 * Check if column exists in table (PostgreSQL version)
 */
export async function verifyColumnExists(prisma: PrismaClient, tableName: string, columnName: string): Promise<boolean> {
  try {
    const result = await prisma.$queryRawUnsafe<Array<{ exists: boolean }>>(
      `SELECT EXISTS (
        SELECT FROM information_schema.columns
        WHERE table_schema = 'public'
        AND table_name = $1
        AND column_name = $2
      )`,
      tableName,
      columnName
    )
    return result[0]?.exists ?? false
  } catch (error) {
    return false
  }
}

/**
 * Get table schema information (PostgreSQL version)
 */
export async function getTableSchema(prisma: PrismaClient, tableName: string) {
  try {
    const result = await prisma.$queryRawUnsafe<Array<{
      column_name: string
      data_type: string
      is_nullable: string
      column_default: string | null
    }>>(
      `SELECT column_name, data_type, is_nullable, column_default
       FROM information_schema.columns
       WHERE table_schema = 'public'
       AND table_name = $1
       ORDER BY ordinal_position`,
      tableName
    )
    return result
  } catch (error) {
    return null
  }
}
