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";

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 () => {
    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 addedOnMs = Number(torrent.added_on ?? 0) * 1000;
      const matchingRules = rules.filter((rule) => {
        const ruleCreatedAtMs = Date.parse(rule.createdAt);
        if (Number.isFinite(ruleCreatedAtMs) && addedOnMs > 0) {
          if (addedOnMs < ruleCreatedAtMs) {
            return false;
          }
        }
        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 seedingSeconds = Number(torrent.seeding_time ?? 0);
      if (seedingSeconds < matchingRule.seedLimitSeconds) {
        continue;
      }

      try {
        await qbit.deleteTorrent(torrent.hash, 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);
    }
  }, intervalMs);
};
