/**
 * Voice Agent API Integration Tests
 *
 * Tests for voice agent provisioning, configuration, and webhook endpoints
 */

import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest';
import { prisma } from '@/lib/db';
import { createId } from '@paralleldrive/cuid2';
import bcrypt from 'bcryptjs';

// Test user data
let testUser: any;
let testUserId: string;

describe('Voice Agent API Integration Tests', () => {
  beforeAll(async () => {
    // Create test user
    testUserId = createId();
    const hashedPassword = await bcrypt.hash('TestPassword123!', 12);

    testUser = await prisma.users.create({
      data: {
        id: testUserId,
        email: `voice-agent-test-${Date.now()}@test.com`,
        name: 'Voice Agent Test User',
        password: hashedPassword,
        role: 'CUSTOMER',
        emailVerified: true,
        isActive: true,
        onboardingCompleted: true,
        plan: 'BUSINESS',
        createdAt: new Date(),
        updatedAt: new Date(),
      },
    });
  });

  afterAll(async () => {
    // Cleanup test data
    if (testUserId) {
      // Delete conversation logs
      await prisma.conversationLog.deleteMany({
        where: { userId: testUserId },
      });

      // Delete user
      await prisma.users.delete({
        where: { id: testUserId },
      });
    }
  });

  describe('Voice Agent Configuration', () => {
    it('should store and retrieve voice agent config', async () => {
      const config = {
        language: 'both',
        voiceTone: 'professional',
        useKnowledgeBase: true,
        greetingMessage: {
          en: 'Hello from test',
          ar: 'مرحبا من الاختبار',
        },
      };

      // Update user with voice agent config
      await prisma.users.update({
        where: { id: testUserId },
        data: {
          voiceAgentId: 'test_agent_123',
          voiceAgentConfig: config as any,
        },
      });

      // Retrieve and verify
      const user = await prisma.users.findUnique({
        where: { id: testUserId },
        select: {
          voiceAgentId: true,
          voiceAgentConfig: true,
        },
      });

      expect(user?.voiceAgentId).toBe('test_agent_123');
      expect(user?.voiceAgentConfig).toMatchObject(config);
    });

    it('should update voice agent config', async () => {
      const updatedConfig = {
        language: 'ar',
        voiceTone: 'friendly',
        useKnowledgeBase: false,
      };

      await prisma.users.update({
        where: { id: testUserId },
        data: {
          voiceAgentConfig: updatedConfig as any,
        },
      });

      const user = await prisma.users.findUnique({
        where: { id: testUserId },
        select: { voiceAgentConfig: true },
      });

      expect(user?.voiceAgentConfig).toMatchObject(updatedConfig);
    });

    it('should clear voice agent config', async () => {
      await prisma.users.update({
        where: { id: testUserId },
        data: {
          voiceAgentId: null,
          voiceAgentConfig: null,
        },
      });

      const user = await prisma.users.findUnique({
        where: { id: testUserId },
        select: {
          voiceAgentId: true,
          voiceAgentConfig: true,
        },
      });

      expect(user?.voiceAgentId).toBeNull();
      expect(user?.voiceAgentConfig).toBeNull();
    });
  });

  describe('Conversation Logs', () => {
    beforeEach(async () => {
      // Clean up existing conversation logs
      await prisma.conversationLog.deleteMany({
        where: { userId: testUserId },
      });
    });

    it('should create voice conversation log', async () => {
      const logId = createId();
      const callId = `call_${Date.now()}`;

      const log = await prisma.conversationLog.create({
        data: {
          id: logId,
          userId: testUserId,
          platform: 'voice',
          customerPhone: '+971501234567',
          messages: [
            {
              role: 'assistant',
              content: 'Hello, how can I help you?',
              timestamp: new Date().toISOString(),
            },
            {
              role: 'user',
              content: 'I need to book an appointment',
              timestamp: new Date().toISOString(),
            },
          ] as any,
          metadata: {
            callId,
            agentId: 'agent_123',
            status: 'started',
          } as any,
          status: 'open',
          createdAt: new Date(),
        },
      });

      expect(log.id).toBe(logId);
      expect(log.platform).toBe('voice');
      expect(log.customerPhone).toBe('+971501234567');
    });

    it('should retrieve voice conversation logs for user', async () => {
      // Create multiple logs
      const logs = await Promise.all([
        prisma.conversationLog.create({
          data: {
            id: createId(),
            userId: testUserId,
            platform: 'voice',
            messages: [] as any,
            status: 'open',
            createdAt: new Date(),
          },
        }),
        prisma.conversationLog.create({
          data: {
            id: createId(),
            userId: testUserId,
            platform: 'voice',
            messages: [] as any,
            status: 'resolved',
            createdAt: new Date(),
          },
        }),
      ]);

      // Retrieve logs
      const retrievedLogs = await prisma.conversationLog.findMany({
        where: {
          userId: testUserId,
          platform: 'voice',
        },
        orderBy: { createdAt: 'desc' },
      });

      expect(retrievedLogs).toHaveLength(2);
      expect(retrievedLogs.every((log) => log.platform === 'voice')).toBe(true);
    });

    it('should update conversation log status', async () => {
      const log = await prisma.conversationLog.create({
        data: {
          id: createId(),
          userId: testUserId,
          platform: 'voice',
          messages: [] as any,
          status: 'open',
          createdAt: new Date(),
        },
      });

      // Update status
      await prisma.conversationLog.update({
        where: { id: log.id },
        data: { status: 'resolved' },
      });

      const updatedLog = await prisma.conversationLog.findUnique({
        where: { id: log.id },
      });

      expect(updatedLog?.status).toBe('resolved');
    });

    it('should update conversation log with transcript', async () => {
      const log = await prisma.conversationLog.create({
        data: {
          id: createId(),
          userId: testUserId,
          platform: 'voice',
          messages: [] as any,
          metadata: {
            callId: 'call_123',
          } as any,
          status: 'open',
          createdAt: new Date(),
        },
      });

      const transcript = [
        {
          role: 'assistant',
          content: 'Hello',
          timestamp: new Date().toISOString(),
        },
        {
          role: 'user',
          content: 'Hi',
          timestamp: new Date().toISOString(),
        },
        {
          role: 'assistant',
          content: 'How can I help you today?',
          timestamp: new Date().toISOString(),
        },
      ];

      await prisma.conversationLog.update({
        where: { id: log.id },
        data: {
          messages: transcript as any,
          status: 'resolved',
          metadata: {
            callId: 'call_123',
            durationSeconds: 180,
          } as any,
        },
      });

      const updatedLog = await prisma.conversationLog.findUnique({
        where: { id: log.id },
      });

      expect(updatedLog?.messages).toHaveLength(3);
      expect(updatedLog?.status).toBe('resolved');
    });

    it('should filter logs by status', async () => {
      // Create logs with different statuses
      await Promise.all([
        prisma.conversationLog.create({
          data: {
            id: createId(),
            userId: testUserId,
            platform: 'voice',
            messages: [] as any,
            status: 'open',
            createdAt: new Date(),
          },
        }),
        prisma.conversationLog.create({
          data: {
            id: createId(),
            userId: testUserId,
            platform: 'voice',
            messages: [] as any,
            status: 'resolved',
            createdAt: new Date(),
          },
        }),
        prisma.conversationLog.create({
          data: {
            id: createId(),
            userId: testUserId,
            platform: 'voice',
            messages: [] as any,
            status: 'archived',
            createdAt: new Date(),
          },
        }),
      ]);

      // Get only resolved logs
      const resolvedLogs = await prisma.conversationLog.findMany({
        where: {
          userId: testUserId,
          platform: 'voice',
          status: 'resolved',
        },
      });

      expect(resolvedLogs.every((log) => log.status === 'resolved')).toBe(true);
    });
  });

  describe('Agent ID Lookup', () => {
    it('should find user by voice agent ID', async () => {
      const agentId = 'test_lookup_agent_123';

      // Set agent ID
      await prisma.users.update({
        where: { id: testUserId },
        data: { voiceAgentId: agentId },
      });

      // Find user by agent ID
      const user = await prisma.users.findFirst({
        where: { voiceAgentId: agentId },
        select: { id: true, email: true },
      });

      expect(user?.id).toBe(testUserId);
    });

    it('should return null for non-existent agent ID', async () => {
      const user = await prisma.users.findFirst({
        where: { voiceAgentId: 'non_existent_agent' },
      });

      expect(user).toBeNull();
    });
  });

  describe('Conversation Log Queries', () => {
    beforeEach(async () => {
      // Create sample logs with different timestamps
      const now = new Date();
      await Promise.all([
        prisma.conversationLog.create({
          data: {
            id: createId(),
            userId: testUserId,
            platform: 'voice',
            messages: [] as any,
            status: 'open',
            createdAt: new Date(now.getTime() - 3600000), // 1 hour ago
          },
        }),
        prisma.conversationLog.create({
          data: {
            id: createId(),
            userId: testUserId,
            platform: 'voice',
            messages: [] as any,
            status: 'resolved',
            createdAt: new Date(now.getTime() - 7200000), // 2 hours ago
          },
        }),
      ]);
    });

    it('should retrieve logs ordered by creation date', async () => {
      const logs = await prisma.conversationLog.findMany({
        where: {
          userId: testUserId,
          platform: 'voice',
        },
        orderBy: { createdAt: 'desc' },
      });

      expect(logs.length).toBeGreaterThanOrEqual(2);
      // Verify descending order
      for (let i = 1; i < logs.length; i++) {
        expect(logs[i - 1].createdAt.getTime()).toBeGreaterThanOrEqual(
          logs[i].createdAt.getTime()
        );
      }
    });

    it('should support pagination', async () => {
      const page1 = await prisma.conversationLog.findMany({
        where: {
          userId: testUserId,
          platform: 'voice',
        },
        orderBy: { createdAt: 'desc' },
        take: 1,
        skip: 0,
      });

      const page2 = await prisma.conversationLog.findMany({
        where: {
          userId: testUserId,
          platform: 'voice',
        },
        orderBy: { createdAt: 'desc' },
        take: 1,
        skip: 1,
      });

      expect(page1).toHaveLength(1);
      expect(page2).toHaveLength(1);
      expect(page1[0].id).not.toBe(page2[0].id);
    });
  });
});
