/**
 * Credential Isolation Integration Tests
 *
 * Verifies that UserCredential data never leaks across federation boundaries.
 */

import { describe, it, expect, beforeEach } from "vitest";
import { Test, TestingModule } from "@nestjs/testing";
import { QueryService } from "./query.service";
import { CommandService } from "./command.service";
import { PrismaService } from "../prisma/prisma.service";
import { FederationService } from "./federation.service";
import { SignatureService } from "./signature.service";
import { HttpService } from "@nestjs/axios";
import { ConfigService } from "@nestjs/config";
import { TasksService } from "../tasks/tasks.service";
import { EventsService } from "../events/events.service";
import { ProjectsService } from "../projects/projects.service";
import { ModuleRef } from "@nestjs/core";
import { FederationConnectionStatus } from "@prisma/client";

describe("Credential Isolation (Integration)", () => {
  let queryService: QueryService;
  let commandService: CommandService;

  const mockPrisma = {
    federationConnection: {
      findFirst: () =>
        Promise.resolve({
          id: "connection-1",
          workspaceId: "workspace-1",
          remoteInstanceId: "remote-instance-1",
          status: FederationConnectionStatus.ACTIVE,
        }),
    },
  };

  const mockFederationService = {
    getInstanceIdentity: () =>
      Promise.resolve({
        instanceId: "local-instance-1",
      }),
  };

  const mockSignatureService = {
    validateTimestamp: () => true,
    verifyMessage: () => Promise.resolve({ valid: true }),
    signMessage: () => Promise.resolve("signature"),
  };

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        QueryService,
        CommandService,
        { provide: PrismaService, useValue: mockPrisma },
        { provide: FederationService, useValue: mockFederationService },
        { provide: SignatureService, useValue: mockSignatureService },
        { provide: HttpService, useValue: { post: () => Promise.resolve() } },
        { provide: ConfigService, useValue: { get: () => null } },
        { provide: TasksService, useValue: { findAll: () => Promise.resolve({ data: [] }) } },
        { provide: EventsService, useValue: { findAll: () => Promise.resolve({ data: [] }) } },
        { provide: ProjectsService, useValue: { findAll: () => Promise.resolve({ data: [] }) } },
        { provide: ModuleRef, useValue: { get: () => ({}) } },
      ],
    }).compile();

    queryService = module.get<QueryService>(QueryService);
    commandService = module.get<CommandService>(CommandService);
  });

  describe("Query Isolation", () => {
    it("should block direct credential entity queries", async () => {
      const queryMessage = {
        messageId: "msg-1",
        instanceId: "remote-instance-1",
        query: "SELECT * FROM user_credentials",
        context: { workspaceId: "workspace-1" },
        timestamp: Date.now(),
        signature: "valid-signature",
      };

      const result = await queryService.handleIncomingQuery(queryMessage);

      expect(result.success).toBe(false);
      expect(result.error).toContain("Credential queries are not allowed");
    });

    it("should block queries with credential keywords in different case", async () => {
      const queries = ["Get all CREDENTIALS", "Show API_KEYS", "List oauth TOKENS", "Find secrets"];

      for (const query of queries) {
        const queryMessage = {
          messageId: `msg-${Math.random()}`,
          instanceId: "remote-instance-1",
          query,
          context: { workspaceId: "workspace-1" },
          timestamp: Date.now(),
          signature: "valid-signature",
        };

        const result = await queryService.handleIncomingQuery(queryMessage);

        expect(result.success).toBe(false);
        expect(result.error).toContain("Credential queries are not allowed");
      }
    });

    it("should allow non-credential queries", async () => {
      const queries = ["tasks", "events", "projects"];

      for (const query of queries) {
        const queryMessage = {
          messageId: `msg-${Math.random()}`,
          instanceId: "remote-instance-1",
          query,
          context: { workspaceId: "workspace-1" },
          timestamp: Date.now(),
          signature: "valid-signature",
        };

        const result = await queryService.handleIncomingQuery(queryMessage);

        expect(result.success).toBe(true);
      }
    });
  });

  describe("Command Isolation", () => {
    it("should block credential.create commands", async () => {
      const commandMessage = {
        messageId: "cmd-1",
        instanceId: "remote-instance-1",
        commandType: "credential.create",
        payload: { name: "test", value: "secret" },
        timestamp: Date.now(),
        signature: "valid-signature",
      };

      const result = await commandService.handleIncomingCommand(commandMessage);

      expect(result.success).toBe(false);
      expect(result.error).toContain("Credential operations are not allowed");
    });

    it("should block all credential operations", async () => {
      const operations = [
        "credential.create",
        "credential.update",
        "credential.delete",
        "credential.read",
        "credentials.sync",
        "credentials.list",
      ];

      for (const commandType of operations) {
        const commandMessage = {
          messageId: `cmd-${Math.random()}`,
          instanceId: "remote-instance-1",
          commandType,
          payload: {},
          timestamp: Date.now(),
          signature: "valid-signature",
        };

        const result = await commandService.handleIncomingCommand(commandMessage);

        expect(result.success).toBe(false);
        expect(result.error).toContain("Credential operations are not allowed");
      }
    });

    it("should block credential operations with different case", async () => {
      const operations = ["CREDENTIAL.create", "Credentials.Update", "CrEdEnTiAl.delete"];

      for (const commandType of operations) {
        const commandMessage = {
          messageId: `cmd-${Math.random()}`,
          instanceId: "remote-instance-1",
          commandType,
          payload: {},
          timestamp: Date.now(),
          signature: "valid-signature",
        };

        const result = await commandService.handleIncomingCommand(commandMessage);

        expect(result.success).toBe(false);
        expect(result.error).toContain("Credential operations are not allowed");
      }
    });

    it("should allow agent commands (existing functionality)", async () => {
      const commandMessage = {
        messageId: "cmd-1",
        instanceId: "remote-instance-1",
        commandType: "agent.spawn",
        payload: { agentType: "task-executor" },
        timestamp: Date.now(),
        signature: "valid-signature",
      };

      // Mock FederationAgentService
      const moduleRef = {
        get: () => ({
          handleAgentCommand: () =>
            Promise.resolve({
              success: true,
              data: { agentId: "agent-123" },
            }),
        }),
      };

      // Inject moduleRef
      (commandService as never)["moduleRef"] = moduleRef;

      const result = await commandService.handleIncomingCommand(commandMessage);

      expect(result.success).toBe(true);
    });
  });

  describe("Defense-in-Depth", () => {
    it("should document transit key separation", () => {
      // This test documents the architectural isolation
      // TransitKey.CREDENTIALS is used for user credentials
      // TransitKey.FEDERATION is used for federation private keys
      // Each federated instance has its own OpenBao instance
      // Even if one Transit key is compromised, credentials remain isolated

      const architecture = {
        userCredentials: {
          transitKey: "mosaic-credentials",
          service: "VaultService",
          scope: "per-workspace",
        },
        federationKeys: {
          transitKey: "mosaic-federation",
          service: "CryptoService (legacy) / VaultService (future)",
          scope: "per-instance",
        },
        isolation: {
          cryptographic: "Separate Transit keys prevent cross-contamination",
          infrastructure: "Each instance has its own OpenBao",
          application: "Deny-lists prevent accidental exposure",
        },
      };

      expect(architecture.userCredentials.transitKey).not.toBe(
        architecture.federationKeys.transitKey
      );
      expect(architecture.isolation).toBeDefined();
    });
  });
});
