import { randomUUID } from "node:crypto";
import { QbitClient } from "../qbit/qbit.client";
import { readDb, writeDb } from "../storage/jsondb";
import { TimerLog, TimerSummary } from "../types";
import { emitTimerLog, emitTimerSummary } from "../realtime/emitter";
import { nowIso } from "../utils/time";
import { logger } from "../utils/logger";

const MAX_LOGS = 2000;

const normalizeTags = (tags?: string, category?: string) => {
  const tagList = tags ? tags.split(",").map((tag) => tag.trim()).filter(Boolean) : [];
  if (category) {
    tagList.push(category);
  }
  return Array.from(new Set(tagList.map((tag) => tag.toLowerCase())));
};

export const startTimerWorker = (qbit: QbitClient, intervalMs: number) => {
  setInterval(async () => {
    try {
      const db = await readDb();
      const rules = db.timerRules ?? [];
      if (rules.length === 0) {
        return;
      }
      const torrents = await qbit.getTorrentsInfo();
      let summary: TimerSummary =
        db.timerSummary ?? {
          totalDeleted: 0,
          totalSeededSeconds: 0,
          totalUploadedBytes: 0,
          updatedAt: nowIso(),
        };

      const logs: TimerLog[] = [];

      for (const torrent of torrents) {
        const tags = normalizeTags(torrent.tags, torrent.category);
        const matchingRules = rules.filter((rule) => {
          return rule.tags.some((tag) => tags.includes(tag.toLowerCase()));
        });
        if (matchingRules.length === 0) {
          continue;
        }
        const matchingRule = matchingRules.reduce((best, current) =>
          current.seedLimitSeconds < best.seedLimitSeconds ? current : best
        );
        const addedOnMs = Number(torrent.added_on ?? 0) * 1000;
        const elapsedSeconds =
          addedOnMs > 0
            ? Math.max(0, (Date.now() - addedOnMs) / 1000)
            : Number(torrent.seeding_time ?? 0);
        const seedingSeconds = Number(torrent.seeding_time ?? 0);
        if (elapsedSeconds < matchingRule.seedLimitSeconds) {
          continue;
        }

        try {
          await qbit.deleteTorrent(torrent.hash, matchingRule.deleteFiles ?? true);
        } catch (error) {
          continue;
        }

        const logEntry: TimerLog = {
          id: randomUUID(),
          hash: torrent.hash,
          name: torrent.name,
          sizeBytes: torrent.size,
          tracker: torrent.tracker,
          tags,
          category: torrent.category,
          seedingTimeSeconds: seedingSeconds,
          uploadedBytes: torrent.uploaded ?? 0,
          deletedAt: nowIso(),
        };
        logs.push(logEntry);
        summary = {
          totalDeleted: summary.totalDeleted + 1,
          totalSeededSeconds: summary.totalSeededSeconds + seedingSeconds,
          totalUploadedBytes: summary.totalUploadedBytes + (torrent.uploaded ?? 0),
          updatedAt: nowIso(),
        };
        emitTimerLog(logEntry);
        emitTimerSummary(summary);
      }

      if (logs.length > 0) {
        db.timerLogs = [...(db.timerLogs ?? []), ...logs].slice(-MAX_LOGS);
        db.timerSummary = summary;
        await writeDb(db);
      }
    } catch (error) {
      logger.error({ error }, "Timer worker tick failed");
    }
  }, intervalMs);
};
