import { describe, test, expect, beforeEach, afterEach } from "bun:test";
import { mkdtempSync, mkdirSync, rmSync, utimesSync, existsSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { PromptCleanupScheduler } from "@/scheduler/prompt-cleanup.js";
import { createLogger } from "@/utils/logger.js";
import type { Logger } from "pino";

describe("PromptCleanupScheduler", () => {
  let workdir: string;
  let logger: Logger;

  beforeEach(() => {
    workdir = mkdtempSync(join(tmpdir(), "prompt-cleanup-test-"));
    logger = createLogger("silent");
  });

  afterEach(() => {
    rmSync(workdir, { recursive: true, force: true });
  });

  test("constructor does not throw", () => {
    expect(() => new PromptCleanupScheduler(workdir, logger)).not.toThrow();
  });

  describe("start / stop lifecycle", () => {
    test("start creates a cron job", () => {
      const scheduler = new PromptCleanupScheduler(workdir, logger);
      scheduler.start();

      const job = (scheduler as unknown as { job: unknown }).job;
      expect(job).toBeTruthy();

      scheduler.stop();
    });

    test("stop clears the cron job", () => {
      const scheduler = new PromptCleanupScheduler(workdir, logger);
      scheduler.start();
      scheduler.stop();

      const job = (scheduler as unknown as { job: unknown }).job;
      expect(job).toBeNull();
    });

    test("start is idempotent — second call does not replace the job", () => {
      const scheduler = new PromptCleanupScheduler(workdir, logger);
      scheduler.start();

      const jobAfterFirst = (scheduler as unknown as { job: unknown }).job;
      scheduler.start();
      const jobAfterSecond = (scheduler as unknown as { job: unknown }).job;

      expect(jobAfterFirst).toBe(jobAfterSecond);

      scheduler.stop();
    });

    test("stop is idempotent — calling twice does not throw", () => {
      const scheduler = new PromptCleanupScheduler(workdir, logger);
      scheduler.start();
      scheduler.stop();
      expect(() => scheduler.stop()).not.toThrow();
    });
  });

  describe("cleanup", () => {
    test("removes directories older than 7 days under .hu-bot", () => {
      const huBotDir = join(workdir, ".hu-bot");
      mkdirSync(huBotDir, { recursive: true });

      const staleDir = join(huBotDir, "stale-session");
      mkdirSync(staleDir);
      const eightDaysAgo = new Date(Date.now() - 8 * 24 * 60 * 60 * 1000);
      utimesSync(staleDir, eightDaysAgo, eightDaysAgo);

      const freshDir = join(huBotDir, "fresh-session");
      mkdirSync(freshDir);

      const scheduler = new PromptCleanupScheduler(workdir, logger);
      scheduler.cleanup();

      expect(existsSync(staleDir)).toBe(false);
      expect(existsSync(freshDir)).toBe(true);
    });

    test("does nothing when .hu-bot directory does not exist", () => {
      const scheduler = new PromptCleanupScheduler(workdir, logger);
      expect(() => scheduler.cleanup()).not.toThrow();
    });

    test("skips regular files inside .hu-bot (only removes directories)", () => {
      const huBotDir = join(workdir, ".hu-bot");
      mkdirSync(huBotDir, { recursive: true });

      const filePath = join(huBotDir, "some-file.txt");
      writeFileSync(filePath, "content");
      const eightDaysAgo = new Date(Date.now() - 8 * 24 * 60 * 60 * 1000);
      utimesSync(filePath, eightDaysAgo, eightDaysAgo);

      const scheduler = new PromptCleanupScheduler(workdir, logger);
      scheduler.cleanup();

      expect(existsSync(filePath)).toBe(true);
    });
  });
});
