/* oxlint-disable no-explicit-any */
import { afterAll, beforeAll, describe, expect, it, vi } from "bun:test";
import { type Meter, trace } from "@opentelemetry/api";
import {
  closeTestPgDatabase,
  connectTestPgDatabase,
  resetTestPgDatabase,
} from "../database/test-db-pg";
import type { StudioDatabase } from "../database";
import { createStudioContextFactory } from "./context-factory";
import type { BetterAuthInstance } from "./studio-context";
import type { QueryEngine } from "../monitoring/query-engine";

// Pass stub engines so the factory's default branch (which lazy-imports
// `@duckdb/node-api`) never runs. DuckDB's native finalizer trips a
// Bun teardown crash (SIGSEGV/SIGILL/SIGABRT) on process exit — same
// behavior on 1.3.5, 1.3.14, and 1.4-canary. The factory doesn't use
// `monitoringEngines` for any of the assertions in this file, so the
// stubs just need to satisfy the interface.
const noopEngine: QueryEngine = { query: async () => [] };
const stubMonitoringEngines = () => ({
  monitoringEngine: noopEngine,
  metricEngine: noopEngine,
});

describe("createStudioContextFactory", () => {
  let database: StudioDatabase;

  beforeAll(async () => {
    database = await connectTestPgDatabase();
    await resetTestPgDatabase(database);
  });

  afterAll(async () => {
    await closeTestPgDatabase(database);
  });

  // Helper to create a mock Request object (factory expects Request, not Hono context)
  const createMockRequest = (options?: {
    url?: string;
    headers?: Record<string, string>;
  }): Request => {
    const url = options?.url ?? "https://studio.example.com/mcp/tools";
    const headers = new Headers(
      options?.headers ?? {
        Authorization: "Bearer test_key",
      },
    );
    return new Request(url, { headers });
  };

  const createMockAuth = (): any => ({
    api: {
      getMcpSession: vi.fn().mockResolvedValue(null) as any,
      verifyApiKey: vi.fn().mockResolvedValue({
        valid: true,
        key: {
          id: "key_1",
          name: "Test Key",
          userId: "user_1",
          permissions: { self: ["COLLECTION_CONNECTIONS_LIST"] },
          metadata: {
            organization: {
              id: "org_123",
              slug: "test-org",
              name: "Test Organization",
            },
          },
        },
      }),
      setActiveOrganization: vi.fn().mockResolvedValue(null),
    },
  });

  describe("factory creation", () => {
    it("should create context factory function", async () => {
      const factory = await createStudioContextFactory({
        db: database.db,

        auth: createMockAuth() as unknown as BetterAuthInstance,
        encryption: { key: "test_key" },
        observability: {
          tracer: trace.getTracer("test"),
          meter: {} as unknown as Meter,
        },
        monitoringEngines: stubMonitoringEngines(),
      });

      expect(typeof factory).toBe("function");
    });
  });

  // Create mock auth with minimal API for unauthenticated requests
  const createMinimalMockAuth = (): any => ({
    api: {
      getMcpSession: vi.fn().mockResolvedValue(null),
      verifyApiKey: vi.fn().mockResolvedValue({ valid: false }),
      getSession: vi.fn().mockResolvedValue(null),
    },
  });

  describe("StudioContext creation", () => {
    it("should create StudioContext from Request", async () => {
      const factory = await createStudioContextFactory({
        db: database.db,

        auth: createMinimalMockAuth() as unknown as BetterAuthInstance,
        encryption: { key: "test_key" },
        observability: {
          tracer: trace.getTracer("test"),
          meter: {} as unknown as Meter,
        },
        monitoringEngines: stubMonitoringEngines(),
      });

      const request = createMockRequest({
        url: "https://studio.example.com/mcp/tools",
        headers: {}, // No Authorization
      });

      const studioCtx = await factory(request);

      expect(studioCtx).toBeDefined();
      expect(studioCtx.auth).toBeDefined();
      expect(studioCtx.storage).toBeDefined();
      expect(studioCtx.access).toBeDefined();
      expect(studioCtx.baseUrl).toBe("https://studio.example.com");
      expect(studioCtx.metadata.requestId).toBeDefined();
    });

    it("should derive base URL from request", async () => {
      const factory = await createStudioContextFactory({
        db: database.db,

        auth: createMinimalMockAuth() as unknown as BetterAuthInstance,
        encryption: { key: "test_key" },
        observability: {
          tracer: trace.getTracer("test"),
          meter: {} as unknown as Meter,
        },
        monitoringEngines: stubMonitoringEngines(),
      });

      const request = createMockRequest({
        url: "http://localhost:3000/mcp/tools",
        headers: {},
      });

      const studioCtx = await factory(request);

      expect(studioCtx.baseUrl).toBe("http://localhost:3000");
    });

    it("should populate request metadata", async () => {
      const factory = await createStudioContextFactory({
        db: database.db,

        auth: createMinimalMockAuth() as unknown as BetterAuthInstance,
        encryption: { key: "test_key" },
        observability: {
          tracer: trace.getTracer("test"),
          meter: {} as unknown as Meter,
        },
        monitoringEngines: stubMonitoringEngines(),
      });

      const request = createMockRequest({
        url: "https://studio.example.com/mcp/tools",
        headers: {
          "User-Agent": "Test/1.0",
          "X-Forwarded-For": "192.168.1.1",
        },
      });

      const studioCtx = await factory(request);

      expect(studioCtx.metadata.userAgent).toBe("Test/1.0");
      expect(studioCtx.metadata.ipAddress).toBe("192.168.1.1");
      expect(studioCtx.metadata.timestamp).toBeInstanceOf(Date);
    });
  });

  describe("organization scope", () => {
    it("should extract organization from Better Auth", async () => {
      const factory = await createStudioContextFactory({
        db: database.db,

        auth: createMockAuth() as unknown as BetterAuthInstance,
        encryption: { key: "test_key" },
        observability: {
          tracer: trace.getTracer("test"),
          meter: {} as unknown as Meter,
        },
        monitoringEngines: stubMonitoringEngines(),
      });

      const request = createMockRequest();

      const studioCtx = await factory(request);

      expect(studioCtx.organization).toBeDefined();
      expect(studioCtx.organization?.id).toBe("org_123");
      expect(studioCtx.organization?.slug).toBe("test-org");
      expect(studioCtx.organization?.name).toBe("Test Organization");
    });

    it("should work without organization (system-level)", async () => {
      const authWithoutOrg = {
        api: {
          getMcpSession: vi.fn().mockResolvedValue(null),
          verifyApiKey: vi.fn().mockResolvedValue({
            valid: true,
            key: {
              id: "key_1",
              permissions: { self: ["COLLECTION_CONNECTIONS_LIST"] },
              metadata: {},
            },
          }),
          setActiveOrganization: vi.fn().mockResolvedValue(null),
        },
      };

      const factory = await createStudioContextFactory({
        db: database.db,

        auth: authWithoutOrg as unknown as BetterAuthInstance,
        encryption: { key: "test_key" },
        observability: {
          tracer: trace.getTracer("test"),
          meter: {} as unknown as Meter,
        },
        monitoringEngines: stubMonitoringEngines(),
      });

      const request = createMockRequest();
      const studioCtx = await factory(request);

      expect(studioCtx.organization).toBeUndefined();
    });
  });

  describe("storage initialization", () => {
    it("should create storage adapters", async () => {
      const factory = await createStudioContextFactory({
        db: database.db,

        auth: createMinimalMockAuth() as unknown as BetterAuthInstance,
        encryption: { key: "test_key" },
        observability: {
          tracer: trace.getTracer("test"),
          meter: {} as unknown as Meter,
        },
        monitoringEngines: stubMonitoringEngines(),
      });

      const request = createMockRequest({
        url: "https://studio.example.com/mcp/tools",
        headers: {},
      });

      const studioCtx = await factory(request);

      expect(studioCtx.storage.connections).toBeDefined();
      expect(studioCtx.storage.organizationSettings).toBeDefined();
    });
  });

  describe("access control initialization", () => {
    it("should create AccessControl instance", async () => {
      const factory = await createStudioContextFactory({
        db: database.db,

        auth: createMinimalMockAuth() as unknown as BetterAuthInstance,
        encryption: { key: "test_key" },
        observability: {
          tracer: trace.getTracer("test"),
          meter: {} as unknown as Meter,
        },
        monitoringEngines: stubMonitoringEngines(),
      });

      const request = createMockRequest({
        url: "https://studio.example.com/mcp/tools",
        headers: {},
      });

      const studioCtx = await factory(request);

      expect(studioCtx.access).toBeDefined();
      expect(studioCtx.access.granted).toBeDefined();
      expect(studioCtx.access.check).toBeDefined();
      expect(studioCtx.access.grant).toBeDefined();
    });
  });

  describe("API Key organization scope", () => {
    it("should set organization from API key metadata", async () => {
      const mockAuthWithOrgInApiKey = {
        api: {
          getMcpSession: vi.fn().mockResolvedValue(null),
          verifyApiKey: vi.fn().mockResolvedValue({
            valid: true,
            key: {
              id: "key_org_a",
              name: "Org A Key",
              userId: "user_1",
              permissions: { self: ["*"] },
              metadata: {
                organization: {
                  id: "org_a",
                  slug: "org-a",
                  name: "Organization A",
                },
              },
            },
          }),
          setActiveOrganization: vi.fn().mockResolvedValue(null),
        },
      };

      const factory = await createStudioContextFactory({
        db: database.db,

        auth: mockAuthWithOrgInApiKey as unknown as BetterAuthInstance,
        encryption: { key: "test_key" },
        observability: {
          tracer: trace.getTracer("test"),
          meter: {} as unknown as Meter,
        },
        monitoringEngines: stubMonitoringEngines(),
      });

      const request = createMockRequest({
        headers: { Authorization: "Bearer api_key_org_a" },
      });

      const studioCtx = await factory(request);

      // Organization should be extracted from API key metadata
      expect(studioCtx.organization).toBeDefined();
      expect(studioCtx.organization?.id).toBe("org_a");
      expect(studioCtx.organization?.slug).toBe("org-a");
      expect(studioCtx.organization?.name).toBe("Organization A");
    });

    it("should have undefined organization when API key has no org metadata", async () => {
      const mockAuthWithoutOrg = {
        api: {
          getMcpSession: vi.fn().mockResolvedValue(null),
          verifyApiKey: vi.fn().mockResolvedValue({
            valid: true,
            key: {
              id: "key_no_org",
              name: "No Org Key",
              userId: "user_1",
              permissions: { self: ["*"] },
              metadata: {}, // No organization
            },
          }),
        },
      };

      const factory = await createStudioContextFactory({
        db: database.db,

        auth: mockAuthWithoutOrg as unknown as BetterAuthInstance,
        encryption: { key: "test_key" },
        observability: {
          tracer: trace.getTracer("test"),
          meter: {} as unknown as Meter,
        },
        monitoringEngines: stubMonitoringEngines(),
      });

      const request = createMockRequest({
        headers: { Authorization: "Bearer api_key_no_org" },
      });

      const studioCtx = await factory(request);

      // Organization should be undefined when not in API key metadata
      expect(studioCtx.organization).toBeUndefined();
    });

    it("should set different organizations for different API keys", async () => {
      // Create factory for Org A key
      const mockAuthOrgA = {
        api: {
          getMcpSession: vi.fn().mockResolvedValue(null),
          verifyApiKey: vi.fn().mockResolvedValue({
            valid: true,
            key: {
              id: "key_org_a",
              userId: "user_1",
              permissions: { self: ["*"] },
              metadata: {
                organization: { id: "org_a", slug: "org-a", name: "Org A" },
              },
            },
          }),
          setActiveOrganization: vi.fn().mockResolvedValue(null),
        },
      };

      const factoryA = await createStudioContextFactory({
        db: database.db,

        auth: mockAuthOrgA as unknown as BetterAuthInstance,
        encryption: { key: "test_key" },
        observability: {
          tracer: trace.getTracer("test"),
          meter: {} as unknown as Meter,
        },
        monitoringEngines: stubMonitoringEngines(),
      });

      const requestA = createMockRequest({
        headers: { Authorization: "Bearer api_key_org_a" },
      });

      const ctxA = await factoryA(requestA);
      expect(ctxA.organization?.id).toBe("org_a");

      // Create factory for Org B key
      const mockAuthOrgB = {
        api: {
          getMcpSession: vi.fn().mockResolvedValue(null),
          verifyApiKey: vi.fn().mockResolvedValue({
            valid: true,
            key: {
              id: "key_org_b",
              userId: "user_1", // Same user, different org
              permissions: { self: ["*"] },
              metadata: {
                organization: { id: "org_b", slug: "org-b", name: "Org B" },
              },
            },
          }),
          setActiveOrganization: vi.fn().mockResolvedValue(null),
        },
      };

      const factoryB = await createStudioContextFactory({
        db: database.db,

        auth: mockAuthOrgB as unknown as BetterAuthInstance,
        encryption: { key: "test_key" },
        observability: {
          tracer: trace.getTracer("test"),
          meter: {} as unknown as Meter,
        },
        monitoringEngines: stubMonitoringEngines(),
      });

      const requestB = createMockRequest({
        headers: { Authorization: "Bearer api_key_org_b" },
      });

      const ctxB = await factoryB(requestB);
      expect(ctxB.organization?.id).toBe("org_b");

      // Verify they are different organizations
      expect(ctxA.organization?.id).not.toBe(ctxB.organization?.id);
    });
  });
});
