/**
 * Workflow Management Integration Tests
 *
 * Tests the complete workflow lifecycle:
 * - User creation with subscription
 * - Workflow creation
 * - API key management
 * - Workflow activation
 * - Conversation logging
 * - Daily statistics
 * - Deactivation
 * - Tier restrictions
 */

import { WorkflowManagementService } from "@/lib/services/workflow-management.service";
import { apiKeyManagementService } from "@/lib/services/api-key-management.service";
import { ConversationTrackerService } from "@/lib/services/conversation-tracker.service";
import { prisma } from "@/lib/db";
import { WorkflowType } from "@/lib/types/workflow.types";

// Mock cuid2 module
jest.mock("@paralleldrive/cuid2", () => ({
  createId: jest.fn(
    () => "mock-cuid-" + Math.random().toString(36).substr(2, 9),
  ),
}));

const { createId } = require("@paralleldrive/cuid2");

// Mock dual database sync
jest.mock("@/lib/dual-database", () => ({
  saveToBothDatabases: jest.fn((model: string, operation: string, params: Record<string, unknown>) => {
    // Simulate database save
    if (operation === "create") {
      return Promise.resolve({
        id: createId(),
        ...(params.data as Record<string, unknown>),
        createdAt: new Date(),
        updatedAt: new Date(),
      });
    }
    if (operation === "update") {
      return Promise.resolve({
        id: (params.where as Record<string, unknown>).id,
        ...(params.data as Record<string, unknown>),
        updatedAt: new Date(),
      });
    }
    return Promise.resolve({});
  }),
  saveUserToBoth: jest.fn(),
  saveAuditLogToBoth: jest.fn(),
}), { virtual: true });
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { saveToBothDatabases } = require("@/lib/dual-database");

jest.mock("@/lib/supabase", () => ({
  supabaseAdmin: null,
}));

jest.mock("@/lib/logger", () => ({
  logger: {
    scope: jest.fn().mockReturnValue({
      info: jest.fn(),
      warn: jest.fn(),
      error: jest.fn(),
    }),
  },
}));

// Variable scoping bugs and Convex migration - needs rewrite
describe.skip("Workflow Management Integration Tests", () => {
  let testUserId: string;
  let testWorkflowId: string;
  let testApiKeyId: string;
  let testConversationId: string;
  let conversationService: ConversationTrackerService;

  beforeAll(() => {
    conversationService = new ConversationTrackerService();
  });

  beforeEach(() => {
    jest.clearAllMocks();
    testUserId = `user_${createId()}`;
    testWorkflowId = createId();
    testApiKeyId = createId();
    testConversationId = createId();
  });

  afterAll(async () => {
    await prisma.$disconnect();
  });

  describe("Full Workflow Lifecycle - tier2 Professional User", () => {
    it("should complete entire workflow setup and usage", async () => {
      // Step 1: Mock user with tier2 subscription
      const mockUser = {
        id: testUserId,
        email: "test@mawidi.com",
        name: "Test User",
        subscription: {
          planId: "tier2",
          status: "active",
        },
      };

      jest.spyOn(prisma.users, "findUnique").mockResolvedValue(mockUser as any);

      // Step 2: Create workflow (AI Agent - allowed in tier2)
      jest.spyOn(prisma.userWorkflow, "findFirst").mockResolvedValue(null);

      const mockCreatedWorkflow = {
        id: testWorkflowId,
        userId: testUserId,
        workflowType: "ai_agent" as WorkflowType,
        n8nWorkflowId: "n8n_123",
        status: "inactive",
        config: {},
        lastRunAt: null,
        lastRunStatus: null,
        createdAt: new Date(),
        updatedAt: new Date(),
      };

      (saveToBothDatabases as jest.Mock).mockResolvedValueOnce(
        mockCreatedWorkflow,
      );

      const workflow = await WorkflowManagementService.createWorkflow(
        testUserId,
        {
          workflowType: "ai_agent",
          n8nWorkflowId: "n8n_123",
          config: { greeting: "Hello!" },
        },
      );

      expect(workflow.status).toBe("inactive");
      expect(workflow.workflowType).toBe("ai_agent");

      // Step 3: Create API key for the workflow
      const mockApiKey = {
        id: testApiKeyId,
        userId: testUserId,
        service: "n8n",
        keyName: "Production Key",
        encryptedKey: "encrypted_key_data",
        isActive: true,
        expiresAt: null,
        lastUsedAt: null,
        createdAt: new Date(),
        updatedAt: new Date(),
      };

      jest.spyOn(prisma.userAPIKey, "create").mockResolvedValue(mockApiKey);

      const apiKeyResult = await apiKeyManagementService.createAPIKey(
        testUserId,
        {
          service: "n8n",
          keyName: "Production Key",
          apiKey: "sk-n8n-test-key-12345",
        },
      );

      expect(apiKeyResult.key.isActive).toBe(true);
      expect(apiKeyResult.plaintextKey).toBe("sk-n8n-test-key-12345");

      // Step 4: Activate workflow (tier2 can activate ai_agent)
      jest
        .spyOn(prisma.userWorkflow, "findFirst")
        .mockResolvedValue(mockCreatedWorkflow);

      const mockActivatedWorkflow = {
        ...mockCreatedWorkflow,
        status: "active",
      };

      (saveToBothDatabases as jest.Mock).mockResolvedValueOnce(
        mockActivatedWorkflow,
      );

      const activation = await WorkflowManagementService.activateWorkflow(
        testWorkflowId,
        testUserId,
        "tier2",
      );

      expect(activation.success).toBe(true);
      expect(activation.status).toBe("active");

      // Step 5: Log conversation
      const mockConversation = {
        id: testConversationId,
        userId: testUserId,
        platform: "whatsapp",
        customerPhone: "+974-5555-1234",
        customerName: "John Doe",
        messages: JSON.stringify([
          {
            role: "user",
            content: "Hello, I need help",
            timestamp: new Date("2025-01-15T10:00:00Z"),
          },
          {
            role: "agent",
            content: "Hi! How can I assist you?",
            timestamp: new Date("2025-01-15T10:01:00Z"),
          },
        ]),
        metadata: null,
        status: "open",
        createdAt: new Date("2025-01-15T10:00:00Z"),
        updatedAt: new Date("2025-01-15T10:00:00Z"),
      };

      jest
        .spyOn(prisma.conversationLog, "create")
        .mockResolvedValue(mockConversation as any);

      const conversation = await conversationService.createConversation(
        testUserId,
        {
          platform: "whatsapp",
          customerPhone: "+974-5555-1234",
          customerName: "John Doe",
          messages: [
            {
              role: "user",
              content: "Hello, I need help",
              timestamp: new Date("2025-01-15T10:00:00Z"),
            },
            {
              role: "agent",
              content: "Hi! How can I assist you?",
              timestamp: new Date("2025-01-15T10:01:00Z"),
            },
          ],
        },
      );

      expect(conversation.platform).toBe("whatsapp");
      expect(conversation.status).toBe("open");

      // Step 6: Get daily stats
      jest
        .spyOn(prisma.conversationLog, "findMany")
        .mockResolvedValue([mockConversation] as any);

      const stats = await conversationService.getDailyStats(
        testUserId,
        new Date("2025-01-15"),
      );

      expect(stats.totalConversations).toBe(1);
      expect(stats.platforms.whatsapp).toBe(1);
      expect(stats.messagesReceived).toBe(1);
      expect(stats.messagesSent).toBe(1);

      // Step 7: Deactivate workflow
      (saveToBothDatabases as jest.Mock).mockResolvedValueOnce({
        ...mockActivatedWorkflow,
        status: "inactive",
      });

      jest
        .spyOn(prisma.userWorkflow, "findFirst")
        .mockResolvedValue(mockActivatedWorkflow);

      const deactivation = await WorkflowManagementService.deactivateWorkflow(
        testWorkflowId,
        testUserId,
      );

      expect(deactivation.success).toBe(true);
      expect(deactivation.status).toBe("inactive");
    });
  });

  describe("Tier Restriction Tests", () => {
    it("should prevent tier2 user from activating tier5 features", async () => {
      // Create tier5 workflow (lead_generation)
      const mockWorkflow = {
        id: testWorkflowId,
        userId: testUserId,
        workflowType: "lead_generation" as WorkflowType,
        n8nWorkflowId: "n8n_lead",
        status: "inactive",
        config: {},
        lastRunAt: null,
        lastRunStatus: null,
        createdAt: new Date(),
        updatedAt: new Date(),
      };

      jest
        .spyOn(prisma.userWorkflow, "findFirst")
        .mockResolvedValue(mockWorkflow);

      // Attempt to activate as tier2 user
      await expect(
        WorkflowManagementService.activateWorkflow(
          testWorkflowId,
          testUserId,
          "tier2",
        ),
      ).rejects.toThrow("requires Ultimate tier or higher");
    });

    it("should prevent tier1 user from activating tier3 features", async () => {
      const mockWorkflow = {
        id: testWorkflowId,
        userId: testUserId,
        workflowType: "voice_agent" as WorkflowType,
        n8nWorkflowId: "n8n_voice",
        status: "inactive",
        config: {},
        lastRunAt: null,
        lastRunStatus: null,
        createdAt: new Date(),
        updatedAt: new Date(),
      };

      jest
        .spyOn(prisma.userWorkflow, "findFirst")
        .mockResolvedValue(mockWorkflow);

      await expect(
        WorkflowManagementService.activateWorkflow(
          testWorkflowId,
          testUserId,
          "tier1",
        ),
      ).rejects.toThrow("requires Business tier or higher");
    });

    it("should allow tier5 user to activate all features", async () => {
      const tier5Workflows: WorkflowType[] = [
        "ai_agent",
        "voice_agent",
        "lead_generation",
        "lead_scoring",
        "social_media",
      ];

      for (const workflowType of tier5Workflows) {
        const mockWorkflow = {
          id: createId(),
          userId: testUserId,
          workflowType,
          n8nWorkflowId: `n8n_${workflowType}`,
          status: "inactive",
          config: {},
          lastRunAt: null,
          lastRunStatus: null,
          createdAt: new Date(),
          updatedAt: new Date(),
        };

        jest
          .spyOn(prisma.userWorkflow, "findFirst")
          .mockResolvedValue(mockWorkflow);

        const mockActivated = {
          ...mockWorkflow,
          status: "active",
        };

        (saveToBothDatabases as jest.Mock).mockResolvedValueOnce(mockActivated);

        const result = await WorkflowManagementService.activateWorkflow(
          mockWorkflow.id,
          testUserId,
          "tier5",
        );

        expect(result.success).toBe(true);
        expect(result.status).toBe("active");
      }
    });
  });

  describe("API Key Integration with Workflows", () => {
    it("should create, use, and rotate API key for workflow", async () => {
      // Create API key
      const mockApiKey = {
        id: testApiKeyId,
        userId: testUserId,
        service: "whatsapp",
        keyName: "WhatsApp API Key",
        encryptedKey: "encrypted_key_data",
        isActive: true,
        expiresAt: null,
        lastUsedAt: null,
        createdAt: new Date(),
        updatedAt: new Date(),
      };

      jest.spyOn(prisma.userAPIKey, "create").mockResolvedValue(mockApiKey);

      const apiKey = await apiKeyManagementService.createAPIKey(testUserId, {
        service: "whatsapp",
        keyName: "WhatsApp API Key",
        apiKey: "whatsapp_original_key",
      });

      expect(apiKey.key.service).toBe("whatsapp");

      // Rotate the key
      jest.spyOn(prisma.userAPIKey, "findUnique").mockResolvedValue(mockApiKey);
      jest.spyOn(prisma.userAPIKey, "update").mockResolvedValue({
        ...mockApiKey,
        updatedAt: new Date(),
      });

      const rotated = await apiKeyManagementService.rotateAPIKey(
        testApiKeyId,
        testUserId,
        "whatsapp_new_key",
      );

      expect(rotated.id).toBe(testApiKeyId);
      expect(prisma.userAPIKey.update).toHaveBeenCalled();

      // Deactivate the key
      const deactivated = await apiKeyManagementService.deactivateAPIKey(
        testApiKeyId,
        testUserId,
      );

      expect(prisma.userAPIKey.update).toHaveBeenCalledWith({
        where: { id: testApiKeyId },
        data: { isActive: false },
      });
    });

    it("should prevent access to other users API keys", async () => {
      const otherUserId = "other_user_123";
      const mockApiKey = {
        id: testApiKeyId,
        userId: otherUserId,
        service: "n8n",
        keyName: "Other User Key",
        encryptedKey: "encrypted_data",
        isActive: true,
        expiresAt: null,
        lastUsedAt: null,
        createdAt: new Date(),
        updatedAt: new Date(),
      };

      jest.spyOn(prisma.userAPIKey, "findUnique").mockResolvedValue(mockApiKey);

      await expect(
        apiKeyManagementService.rotateAPIKey(
          testApiKeyId,
          testUserId,
          "new_key",
        ),
      ).rejects.toThrow("API key not found or access denied");

      await expect(
        apiKeyManagementService.deactivateAPIKey(testApiKeyId, testUserId),
      ).rejects.toThrow("API key not found or access denied");

      await expect(
        apiKeyManagementService.deleteAPIKey(testApiKeyId, testUserId),
      ).rejects.toThrow("API key not found or access denied");
    });
  });

  describe("Conversation Tracking Integration", () => {
    it("should track multiple conversations and calculate accurate stats", async () => {
      const testDate = new Date("2025-01-15");

      const conversations = [
        {
          id: createId(),
          userId: testUserId,
          platform: "whatsapp",
          customerPhone: "+974-1111-1111",
          customerName: "Customer A",
          messages: JSON.stringify([
            { role: "user", content: "Message 1", timestamp: new Date() },
            { role: "agent", content: "Reply 1", timestamp: new Date() },
            { role: "user", content: "Message 2", timestamp: new Date() },
          ]),
          metadata: null,
          status: "open",
          createdAt: testDate,
          updatedAt: testDate,
        },
        {
          id: createId(),
          userId: testUserId,
          platform: "voice",
          customerPhone: "+974-2222-2222",
          customerName: "Customer B",
          messages: JSON.stringify([
            { role: "user", content: "Voice call", timestamp: new Date() },
            { role: "agent", content: "Response", timestamp: new Date() },
          ]),
          metadata: null,
          status: "resolved",
          createdAt: testDate,
          updatedAt: testDate,
        },
        {
          id: createId(),
          userId: testUserId,
          platform: "social",
          customerPhone: null,
          customerName: "Social User",
          messages: JSON.stringify([
            { role: "user", content: "Social message", timestamp: new Date() },
          ]),
          metadata: null,
          status: "open",
          createdAt: testDate,
          updatedAt: testDate,
        },
      ];

      jest
        .spyOn(prisma.conversationLog, "findMany")
        .mockResolvedValue(conversations as any);

      const stats = await conversationService.getDailyStats(
        testUserId,
        testDate,
      );

      expect(stats.totalConversations).toBe(3);
      expect(stats.platforms.whatsapp).toBe(1);
      expect(stats.platforms.voice).toBe(1);
      expect(stats.platforms.social).toBe(1);
      expect(stats.messagesReceived).toBe(4); // user messages
      expect(stats.messagesSent).toBe(2); // agent messages
      expect(stats.topCustomers).toHaveLength(2); // Only those with phone numbers
    });

    it("should append messages to existing conversation", async () => {
      const existingConversation = {
        id: testConversationId,
        userId: testUserId,
        platform: "whatsapp",
        customerPhone: "+974-5555-1234",
        customerName: "Test Customer",
        messages: JSON.stringify([
          { role: "user", content: "Initial message", timestamp: new Date() },
        ]),
        metadata: null,
        status: "open",
        createdAt: new Date(),
        updatedAt: new Date(),
      };

      jest
        .spyOn(prisma.conversationLog, "findUnique")
        .mockResolvedValue(existingConversation as any);

      const newMessages = [
        { role: "agent", content: "Response", timestamp: new Date() },
        { role: "user", content: "Follow-up", timestamp: new Date() },
      ];

      const updatedConversation = {
        ...existingConversation,
        messages: JSON.stringify([
          { role: "user", content: "Initial message", timestamp: new Date() },
          ...newMessages,
        ]),
      };

      jest
        .spyOn(prisma.conversationLog, "update")
        .mockResolvedValue(updatedConversation as any);

      const result = await conversationService.appendMessages(
        testConversationId,
        testUserId,
        newMessages,
      );

      const messages = JSON.parse(result.messages);
      expect(messages).toHaveLength(3);
      expect(messages[1].content).toBe("Response");
      expect(messages[2].content).toBe("Follow-up");
    });

    it("should update conversation status", async () => {
      const mockConversation = {
        id: testConversationId,
        userId: testUserId,
        platform: "whatsapp",
        customerPhone: "+974-5555-1234",
        customerName: "Test Customer",
        messages: "[]",
        metadata: null,
        status: "open",
        createdAt: new Date(),
        updatedAt: new Date(),
      };

      jest
        .spyOn(prisma.conversationLog, "findUnique")
        .mockResolvedValue(mockConversation as any);
      jest.spyOn(prisma.conversationLog, "update").mockResolvedValue({
        ...mockConversation,
        status: "resolved",
      } as any);

      const result = await conversationService.updateConversationStatus(
        testConversationId,
        testUserId,
        "resolved",
      );

      expect(result.status).toBe("resolved");
    });
  });

  describe("Workflow Statistics", () => {
    it("should calculate correct workflow statistics", async () => {
      const workflows = [
        { status: "active", workflowType: "ai_agent" },
        { status: "active", workflowType: "whatsapp" },
        { status: "inactive", workflowType: "crm" },
        { status: "error", workflowType: "voice_agent" },
        { status: "active", workflowType: "appointments" },
      ];

      jest
        .spyOn(prisma.userWorkflow, "findMany")
        .mockResolvedValue(workflows as any);

      const stats =
        await WorkflowManagementService.getWorkflowStats(testUserId);

      expect(stats.total).toBe(5);
      expect(stats.active).toBe(3);
      expect(stats.inactive).toBe(1);
      expect(stats.error).toBe(1);
    });
  });

  describe("Error Handling and Edge Cases", () => {
    it("should handle workflow not found", async () => {
      jest.spyOn(prisma.userWorkflow, "findFirst").mockResolvedValue(null);

      await expect(
        WorkflowManagementService.getWorkflowById(testWorkflowId, testUserId),
      ).resolves.toBeNull();
    });

    it("should prevent duplicate workflow creation", async () => {
      const existingWorkflow = {
        id: testWorkflowId,
        userId: testUserId,
        workflowType: "ai_agent",
        status: "active",
        config: {},
        createdAt: new Date(),
        updatedAt: new Date(),
      };

      jest
        .spyOn(prisma.userWorkflow, "findFirst")
        .mockResolvedValue(existingWorkflow as any);

      await expect(
        WorkflowManagementService.createWorkflow(testUserId, {
          workflowType: "ai_agent",
          config: {},
        }),
      ).rejects.toThrow("already exists");
    });

    it("should handle conversation authorization errors", async () => {
      const otherUserConversation = {
        id: testConversationId,
        userId: "other_user_123",
        platform: "whatsapp",
        customerPhone: "+974-5555-1234",
        customerName: "Test Customer",
        messages: "[]",
        metadata: null,
        status: "open",
        createdAt: new Date(),
        updatedAt: new Date(),
      };

      jest
        .spyOn(prisma.conversationLog, "findUnique")
        .mockResolvedValue(otherUserConversation as any);

      await expect(
        conversationService.appendMessages(testConversationId, testUserId, [
          { role: "user", content: "Hello", timestamp: new Date() },
        ]),
      ).rejects.toThrow("Unauthorized");
    });

    it("should validate conversation platform", async () => {
      await expect(
        conversationService.createConversation(testUserId, {
          platform: "invalid-platform" as any,
          messages: [{ role: "user", content: "Test", timestamp: new Date() }],
        }),
      ).rejects.toThrow("Invalid platform");
    });

    it("should require at least one message", async () => {
      await expect(
        conversationService.createConversation(testUserId, {
          platform: "whatsapp",
          messages: [],
        }),
      ).rejects.toThrow("At least one message is required");
    });
  });
});
