/**
 * Test suite for AI field migrations
 * Validates that Note and AiFeedback models work correctly with new AI fields
 */

import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

describe('AI Fields Migration Tests', () => {
  beforeAll(async () => {
    // Ensure clean test environment
    await prisma.aiFeedback.deleteMany({})
    await prisma.note.deleteMany({
      where: { title: { contains: 'TEST_AI' } }
    })
  })

  afterAll(async () => {
    // Cleanup
    await prisma.aiFeedback.deleteMany({})
    await prisma.note.deleteMany({
      where: { title: { contains: 'TEST_AI' } }
    })
    await prisma.$disconnect()
  })

  describe('Note Model - AI Fields', () => {
    test('should create note without AI fields (backward compatibility)', async () => {
      const note = await prisma.note.create({
        data: {
          title: 'TEST_AI: Note without AI',
          content: 'This is a test note without AI fields',
          userId: 'test-user-id'
        }
      })

      expect(note).toBeDefined()
      expect(note.id).toBeDefined()
      expect(note.title).toBe('TEST_AI: Note without AI')
      expect(note.autoGenerated).toBeNull()
      expect(note.aiProvider).toBeNull()
      expect(note.aiConfidence).toBeNull()
      expect(note.language).toBeNull()
      expect(note.languageConfidence).toBeNull()
      expect(note.lastAiAnalysis).toBeNull()
    })

    test('should create note with all AI fields populated', async () => {
      const testDate = new Date()
      const note = await prisma.note.create({
        data: {
          title: 'TEST_AI: Note with AI fields',
          content: 'This is a test note with AI fields',
          userId: 'test-user-id',
          autoGenerated: true,
          aiProvider: 'openai',
          aiConfidence: 95,
          language: 'fr',
          languageConfidence: 0.98,
          lastAiAnalysis: testDate
        }
      })

      expect(note).toBeDefined()
      expect(note.autoGenerated).toBe(true)
      expect(note.aiProvider).toBe('openai')
      expect(note.aiConfidence).toBe(95)
      expect(note.language).toBe('fr')
      expect(note.languageConfidence).toBe(0.98)
      expect(note.lastAiAnalysis).toEqual(testDate)
    })

    test('should update note with AI fields', async () => {
      const note = await prisma.note.create({
        data: {
          title: 'TEST_AI: Note for update test',
          content: 'Initial content',
          userId: 'test-user-id'
        }
      })

      const updatedNote = await prisma.note.update({
        where: { id: note.id },
        data: {
          autoGenerated: true,
          aiProvider: 'ollama',
          aiConfidence: 87
        }
      })

      expect(updatedNote.autoGenerated).toBe(true)
      expect(updatedNote.aiProvider).toBe('ollama')
      expect(updatedNote.aiConfidence).toBe(87)
    })

    test('should query notes filtered by AI fields', async () => {
      await prisma.note.create({
        data: {
          title: 'TEST_AI: Auto-generated note 1',
          content: 'Test content',
          userId: 'test-user-id',
          autoGenerated: true,
          aiProvider: 'openai'
        }
      })

      await prisma.note.create({
        data: {
          title: 'TEST_AI: Auto-generated note 2',
          content: 'Test content',
          userId: 'test-user-id',
          autoGenerated: true,
          aiProvider: 'ollama'
        }
      })

      const autoGeneratedNotes = await prisma.note.findMany({
        where: {
          title: { contains: 'TEST_AI' },
          autoGenerated: true
        }
      })

      expect(autoGeneratedNotes.length).toBeGreaterThanOrEqual(2)
      expect(autoGeneratedNotes.every(n => n.autoGenerated === true)).toBe(true)
    })
  })

  describe('AiFeedback Model', () => {
    test('should create feedback entry', async () => {
      const note = await prisma.note.create({
        data: {
          title: 'TEST_AI: Note for feedback',
          content: 'Test note',
          userId: 'test-user-id'
        }
      })

      const feedback = await prisma.aiFeedback.create({
        data: {
          noteId: note.id,
          userId: 'test-user-id',
          feedbackType: 'thumbs_up',
          feature: 'title_suggestion',
          originalContent: 'AI suggested title',
          metadata: JSON.stringify({
            aiProvider: 'openai',
            confidence: 95,
            model: 'gpt-4',
            timestamp: new Date().toISOString()
          })
        }
      })

      expect(feedback).toBeDefined()
      expect(feedback.id).toBeDefined()
      expect(feedback.feedbackType).toBe('thumbs_up')
      expect(feedback.feature).toBe('title_suggestion')
      expect(feedback.originalContent).toBe('AI suggested title')
      expect(feedback.noteId).toBe(note.id)
    })

    test('should handle thumbs_down feedback', async () => {
      const note = await prisma.note.create({
        data: {
          title: 'TEST_AI: Note for thumbs down',
          content: 'Test note',
          userId: 'test-user-id'
        }
      })

      const feedback = await prisma.aiFeedback.create({
        data: {
          noteId: note.id,
          userId: 'test-user-id',
          feedbackType: 'thumbs_down',
          feature: 'title_suggestion',
          originalContent: 'Bad suggestion'
        }
      })

      expect(feedback.feedbackType).toBe('thumbs_down')
    })

    test('should handle correction feedback', async () => {
      const note = await prisma.note.create({
        data: {
          title: 'TEST_AI: Note for correction',
          content: 'Test note',
          userId: 'test-user-id'
        }
      })

      const feedback = await prisma.aiFeedback.create({
        data: {
          noteId: note.id,
          userId: 'test-user-id',
          feedbackType: 'correction',
          feature: 'title_suggestion',
          originalContent: 'Wrong suggestion',
          correctedContent: 'Corrected version'
        }
      })

      expect(feedback.feedbackType).toBe('correction')
      expect(feedback.correctedContent).toBe('Corrected version')
    })

    test('should query feedback by note', async () => {
      const note = await prisma.note.create({
        data: {
          title: 'TEST_AI: Note for feedback query',
          content: 'Test note',
          userId: 'test-user-id'
        }
      })

      await prisma.aiFeedback.create({
        data: {
          noteId: note.id,
          userId: 'test-user-id',
          feedbackType: 'thumbs_up',
          feature: 'title_suggestion',
          originalContent: 'Feedback 1'
        }
      })

      await prisma.aiFeedback.create({
        data: {
          noteId: note.id,
          userId: 'test-user-id',
          feedbackType: 'thumbs_down',
          feature: 'title_suggestion',
          originalContent: 'Feedback 2'
        }
      })

      const feedbacks = await prisma.aiFeedback.findMany({
        where: { noteId: note.id },
        orderBy: { createdAt: 'asc' }
      })

      expect(feedbacks.length).toBe(2)
    })

    test('should query feedback by feature', async () => {
      const note = await prisma.note.create({
        data: {
          title: 'TEST_AI: Note for feature query',
          content: 'Test note',
          userId: 'test-user-id'
        }
      })

      await prisma.aiFeedback.create({
        data: {
          noteId: note.id,
          userId: 'test-user-id',
          feedbackType: 'thumbs_up',
          feature: 'title_suggestion',
          originalContent: 'Feedback 1'
        }
      })

      await prisma.aiFeedback.create({
        data: {
          noteId: note.id,
          userId: 'test-user-id',
          feedbackType: 'thumbs_up',
          feature: 'semantic_search',
          originalContent: 'Feedback 2'
        }
      })

      const titleFeedbacks = await prisma.aiFeedback.findMany({
        where: { feature: 'title_suggestion' }
      })

      expect(titleFeedbacks.length).toBeGreaterThanOrEqual(1)
      expect(titleFeedbacks.every(f => f.feature === 'title_suggestion')).toBe(true)
    })
  })

  describe('Cascade Deletion', () => {
    test('should cascade delete feedback when note is deleted', async () => {
      const note = await prisma.note.create({
        data: {
          title: 'TEST_AI: Note for cascade test',
          content: 'Test note',
          userId: 'test-user-id'
        }
      })

      await prisma.aiFeedback.create({
        data: {
          noteId: note.id,
          userId: 'test-user-id',
          feedbackType: 'thumbs_up',
          feature: 'title_suggestion',
          originalContent: 'Feedback to be deleted'
        }
      })

      // Verify feedback exists
      const feedbacksBefore = await prisma.aiFeedback.findMany({
        where: { noteId: note.id }
      })
      expect(feedbacksBefore.length).toBe(1)

      // Delete the note
      await prisma.note.delete({
        where: { id: note.id }
      })

      // Verify feedback was cascade deleted
      const feedbacksAfter = await prisma.aiFeedback.findMany({
        where: { noteId: note.id }
      })
      expect(feedbacksAfter.length).toBe(0)
    })

    test('should cascade delete feedback when user is deleted', async () => {
      // This test would require a User model with proper setup
      // For now, we'll skip as user deletion is a more complex operation
      // that may involve authentication and authorization
    })
  })

  describe('Index Performance', () => {
    test('should have indexes on critical fields', async () => {
      // Verify indexes exist by checking query plan or performance
      // For SQLite, indexes are created in the migration
      // This is more of a documentation test than a runtime test

      const note = await prisma.note.create({
        data: {
          title: 'TEST_AI: Note for index test',
          content: 'Test note',
          userId: 'test-user-id'
        }
      })

      await prisma.aiFeedback.createMany({
        data: [
          {
            noteId: note.id,
            userId: 'test-user-id',
            feedbackType: 'thumbs_up',
            feature: 'title_suggestion',
            originalContent: 'Feedback 1'
          },
          {
            noteId: note.id,
            userId: 'test-user-id',
            feedbackType: 'thumbs_down',
            feature: 'semantic_search',
            originalContent: 'Feedback 2'
          }
        ]
      })

      // Query by noteId (should use index)
      const byNoteId = await prisma.aiFeedback.findMany({
        where: { noteId: note.id }
      })
      expect(byNoteId.length).toBe(2)

      // Query by userId (should use index)
      const byUserId = await prisma.aiFeedback.findMany({
        where: { userId: 'test-user-id' }
      })
      expect(byUserId.length).toBeGreaterThanOrEqual(2)

      // Query by feature (should use index)
      const byFeature = await prisma.aiFeedback.findMany({
        where: { feature: 'title_suggestion' }
      })
      expect(byFeature.length).toBeGreaterThanOrEqual(1)
    })
  })

  describe('Data Types Validation', () => {
    test('should accept valid aiProvider values', async () => {
      const providers = ['openai', 'ollama', null]

      for (const provider of providers) {
        const note = await prisma.note.create({
          data: {
            title: `TEST_AI: Note with provider ${provider}`,
            content: 'Test note',
            userId: 'test-user-id',
            aiProvider: provider
          }
        })
        expect(note.aiProvider).toBe(provider)
      }
    })

    test('should accept valid aiConfidence range (0-100)', async () => {
      const confidences = [0, 50, 100]

      for (const conf of confidences) {
        const note = await prisma.note.create({
          data: {
            title: `TEST_AI: Note with confidence ${conf}`,
            content: 'Test note',
            userId: 'test-user-id',
            aiConfidence: conf
          }
        })
        expect(note.aiConfidence).toBe(conf)
      }
    })

    test('should accept valid languageConfidence range (0.0-1.0)', async () => {
      const confidences = [0.0, 0.5, 0.99, 1.0]

      for (const conf of confidences) {
        const note = await prisma.note.create({
          data: {
            title: `TEST_AI: Note with lang confidence ${conf}`,
            content: 'Test note',
            userId: 'test-user-id',
            languageConfidence: conf
          }
        })
        expect(note.languageConfidence).toBe(conf)
      }
    })

    test('should accept valid ISO 639-1 language codes', async () => {
      const languages = ['en', 'fr', 'es', 'de', 'fa', null]

      for (const lang of languages) {
        const note = await prisma.note.create({
          data: {
            title: `TEST_AI: Note in language ${lang}`,
            content: 'Test note',
            userId: 'test-user-id',
            language: lang
          }
        })
        expect(note.language).toBe(lang)
      }
    })
  })
})
