import { describe, it, expect, vi, beforeEach } from "vitest";
import { Test, TestingModule } from "@nestjs/testing";
import { ConfigModule } from "@nestjs/config";
import { MosaicTelemetryModule } from "./mosaic-telemetry.module";
import { MosaicTelemetryService } from "./mosaic-telemetry.service";
import { PrismaService } from "../prisma/prisma.service";

// Mock the telemetry client to avoid real HTTP calls
vi.mock("@mosaicstack/telemetry-client", async (importOriginal) => {
  const actual = await importOriginal<typeof import("@mosaicstack/telemetry-client")>();

  class MockTelemetryClient {
    private _isRunning = false;

    constructor(_config: unknown) {
      // no-op
    }

    get eventBuilder() {
      return { build: vi.fn().mockReturnValue({ event_id: "test-event-id" }) };
    }

    start(): void {
      this._isRunning = true;
    }

    async stop(): Promise<void> {
      this._isRunning = false;
    }

    track(_event: unknown): void {
      // no-op
    }

    getPrediction(_query: unknown): unknown {
      return null;
    }

    async refreshPredictions(_queries: unknown): Promise<void> {
      // no-op
    }

    get queueSize(): number {
      return 0;
    }

    get isRunning(): boolean {
      return this._isRunning;
    }
  }

  return {
    ...actual,
    TelemetryClient: MockTelemetryClient,
  };
});

describe("MosaicTelemetryModule", () => {
  let module: TestingModule;
  const sharedTestEnv = {
    ENCRYPTION_KEY: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
  };
  const mockPrismaService = {
    onModuleInit: vi.fn(),
    onModuleDestroy: vi.fn(),
    $connect: vi.fn(),
    $disconnect: vi.fn(),
  };

  const buildTestModule = async (env: Record<string, string>): Promise<TestingModule> =>
    Test.createTestingModule({
      imports: [
        ConfigModule.forRoot({
          isGlobal: true,
          envFilePath: [],
          load: [() => ({ ...env, ...sharedTestEnv })],
        }),
        MosaicTelemetryModule,
      ],
    })
      .overrideProvider(PrismaService)
      .useValue(mockPrismaService)
      .compile();

  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe("module initialization", () => {
    it("should compile the module successfully", async () => {
      module = await buildTestModule({
        MOSAIC_TELEMETRY_ENABLED: "false",
      });

      expect(module).toBeDefined();
      await module.close();
    });

    it("should provide MosaicTelemetryService", async () => {
      module = await buildTestModule({
        MOSAIC_TELEMETRY_ENABLED: "false",
      });

      const service = module.get<MosaicTelemetryService>(MosaicTelemetryService);
      expect(service).toBeDefined();
      expect(service).toBeInstanceOf(MosaicTelemetryService);

      await module.close();
    });

    it("should export MosaicTelemetryService for injection in other modules", async () => {
      module = await buildTestModule({
        MOSAIC_TELEMETRY_ENABLED: "false",
      });

      const service = module.get(MosaicTelemetryService);
      expect(service).toBeDefined();

      await module.close();
    });
  });

  describe("lifecycle integration", () => {
    it("should initialize service on module init when enabled", async () => {
      module = await buildTestModule({
        MOSAIC_TELEMETRY_ENABLED: "true",
        MOSAIC_TELEMETRY_SERVER_URL: "https://tel.test.local",
        MOSAIC_TELEMETRY_API_KEY: "a".repeat(64),
        MOSAIC_TELEMETRY_INSTANCE_ID: "550e8400-e29b-41d4-a716-446655440000",
        MOSAIC_TELEMETRY_DRY_RUN: "false",
      });

      await module.init();

      const service = module.get<MosaicTelemetryService>(MosaicTelemetryService);
      expect(service.isEnabled).toBe(true);

      await module.close();
    });

    it("should not start client when disabled via env", async () => {
      module = await buildTestModule({
        MOSAIC_TELEMETRY_ENABLED: "false",
      });

      await module.init();

      const service = module.get<MosaicTelemetryService>(MosaicTelemetryService);
      expect(service.isEnabled).toBe(false);

      await module.close();
    });

    it("should cleanly shut down on module destroy", async () => {
      module = await buildTestModule({
        MOSAIC_TELEMETRY_ENABLED: "true",
        MOSAIC_TELEMETRY_SERVER_URL: "https://tel.test.local",
        MOSAIC_TELEMETRY_API_KEY: "a".repeat(64),
        MOSAIC_TELEMETRY_INSTANCE_ID: "550e8400-e29b-41d4-a716-446655440000",
        MOSAIC_TELEMETRY_DRY_RUN: "false",
      });

      await module.init();

      const service = module.get<MosaicTelemetryService>(MosaicTelemetryService);
      expect(service.isEnabled).toBe(true);

      await expect(module.close()).resolves.not.toThrow();
    });
  });
});
