import path from "path";
import { readJsonFile, writeJsonFile } from "../utils/fileUtils.js";
import { config } from "../config.js";
import { logError, logInfo } from "../utils/logger.js";

export type CleanupJob = {
  id: string;
  oldLocation: string;
  attempts: number;
  nextRunAt: string;
};

const backoffSeconds = [5, 15, 30];

export class CleanupQueue {
  private jobs: CleanupJob[] = [];
  private running = false;
  private timer?: NodeJS.Timeout;
  private readonly filePath: string;
  private readonly handler: (job: CleanupJob) => Promise<void>;

  constructor(handler: (job: CleanupJob) => Promise<void>) {
    this.handler = handler;
    this.filePath = path.join(config.NOTES_DIR, "cleanup-queue.json");
  }

  async load(): Promise<void> {
    this.jobs = await readJsonFile<CleanupJob[]>(this.filePath, []);
  }

  async persist(): Promise<void> {
    await writeJsonFile(this.filePath, this.jobs);
  }

  async enqueue(job: CleanupJob): Promise<void> {
    this.jobs.push(job);
    await this.persist();
  }

  start(): void {
    if (this.timer) {
      return;
    }
    this.timer = setInterval(() => void this.tick(), 1000);
    logInfo("Temizlik kuyrugu calisiyor");
  }

  stop(): void {
    if (this.timer) {
      clearInterval(this.timer);
      this.timer = undefined;
    }
  }

  private async tick(): Promise<void> {
    if (this.running) {
      return;
    }
    const now = Date.now();
    const jobIndex = this.jobs.findIndex((job) => new Date(job.nextRunAt).getTime() <= now);
    if (jobIndex === -1) {
      return;
    }

    const job = this.jobs[jobIndex];
    this.running = true;
    try {
      await this.handler(job);
      this.jobs.splice(jobIndex, 1);
      await this.persist();
      logInfo("Temizlik basarili", { jobId: job.id });
    } catch (error) {
      job.attempts += 1;
      if (job.attempts >= backoffSeconds.length) {
        logError("Temizlik en fazla deneme sayisina ulasti", { jobId: job.id });
        this.jobs.splice(jobIndex, 1);
      } else {
        const delay = backoffSeconds[job.attempts - 1] * 1000;
        job.nextRunAt = new Date(Date.now() + delay).toISOString();
      }
      await this.persist();
    } finally {
      this.running = false;
    }
  }
}
