import { describe, it, expect, vi, beforeEach } from "vitest";
import { HttpException } from "@nestjs/common";

const mockGetDb = vi.fn();
const mockGetNeo4jSession = vi.fn();
const mockIsKafkaConnected = vi.fn();

vi.mock("../../config/database.js", () => ({
  getDb: () => mockGetDb(),
}));

vi.mock("../../config/neo4j.js", () => ({
  getNeo4jSession: () => mockGetNeo4jSession(),
}));

vi.mock("../../config/kafka.js", () => ({
  isKafkaProducerConnected: () => mockIsKafkaConnected(),
}));

vi.mock("../../config/env.js", () => ({
  env: { NEO4J_URL: undefined, NEO4J_PASSWORD: undefined },
}));

import { HealthController } from "./health.controller.js";

describe("HealthController", () => {
  let controller: HealthController;

  beforeEach(() => {
    vi.clearAllMocks();
    controller = new HealthController();
  });

  describe("liveness", () => {
    it("should return ok status with service name", () => {
      const result = controller.liveness();
      expect(result.status).toBe("ok");
      expect(result.service).toBe("content");
      expect(result.timestamp).toBeDefined();
    });
  });

  describe("readiness", () => {
    it("should return ok when all dependencies healthy", async () => {
      mockGetDb.mockReturnValue({
        execute: vi.fn().mockResolvedValue(undefined),
      });
      mockIsKafkaConnected.mockReturnValue(true);
      const result = await controller.readiness();
      expect(result.status).toBe("ok");
      expect(result.dependencies).toHaveLength(3);
      const names = result.dependencies.map((d) => d.name);
      expect(names).toEqual(["mysql", "neo4j", "kafka"]);
      expect(result.dependencies.every((d) => d.status === "ok")).toBe(true);
    });

    it("should report neo4j as ok when not configured", async () => {
      mockGetDb.mockReturnValue({
        execute: vi.fn().mockResolvedValue(undefined),
      });
      mockIsKafkaConnected.mockReturnValue(true);
      const result = await controller.readiness();
      const neo4jDep = result.dependencies.find((d) => d.name === "neo4j");
      expect(neo4jDep?.status).toBe("ok");
    });

    it("should report mysql error when db check fails", async () => {
      mockGetDb.mockReturnValue({
        execute: vi.fn().mockRejectedValue(new Error("db down")),
      });
      mockIsKafkaConnected.mockReturnValue(true);
      await expect(controller.readiness()).rejects.toThrow(HttpException);
    });

    it("should report kafka error when producer disconnected", async () => {
      mockGetDb.mockReturnValue({
        execute: vi.fn().mockResolvedValue(undefined),
      });
      mockIsKafkaConnected.mockReturnValue(false);
      await expect(controller.readiness()).rejects.toThrow(HttpException);
    });
  });
});
