import { Router } from "express";
import crypto from "node:crypto";
import { z } from "zod";
import {
  createWatcher,
  deleteWatcher,
  fetchWatcherImage,
  getQbitCategories,
  getWatcherItems,
  getWatcherSummary,
  listTrackers,
  listWatchers,
  runWatcherById,
  updateWatcher,
} from "./watcher.service";

const router = Router();

const createWatcherSchema = z.object({
  tracker: z.string().min(1),
  cookie: z.string().min(1),
  intervalMinutes: z.number().int().min(1).max(24 * 60),
  category: z.string().optional(),
  wishlistUrl: z.string().optional(),
  enabled: z.boolean().optional(),
});

const updateWatcherSchema = z.object({
  cookie: z.string().min(1).optional(),
  intervalMinutes: z.number().int().min(1).max(24 * 60).optional(),
  category: z.string().optional(),
  wishlistUrl: z.string().optional(),
  enabled: z.boolean().optional(),
});

router.get("/trackers", async (_req, res) => {
  return res.json(await listTrackers());
});

router.get("/categories", async (_req, res) => {
  try {
    return res.json(await getQbitCategories());
  } catch (error) {
    return res.status(400).json({ error: error instanceof Error ? error.message : "Failed to load qBittorrent categories" });
  }
});

router.get("/", async (_req, res) => {
  return res.json(await listWatchers());
});

router.post("/", async (req, res) => {
  const parsed = createWatcherSchema.safeParse(req.body ?? {});
  if (!parsed.success) {
    return res.status(400).json({ error: "Invalid watcher payload" });
  }
  try {
    const watcher = await createWatcher(parsed.data);
    return res.status(201).json(watcher);
  } catch (error) {
    return res.status(400).json({ error: error instanceof Error ? error.message : "Failed to create watcher" });
  }
});

router.patch("/:id", async (req, res) => {
  const parsed = updateWatcherSchema.safeParse(req.body ?? {});
  if (!parsed.success) {
    return res.status(400).json({ error: "Invalid watcher payload" });
  }
  try {
    const watcher = await updateWatcher(req.params.id, parsed.data);
    return res.json(watcher);
  } catch (error) {
    return res.status(400).json({ error: error instanceof Error ? error.message : "Failed to update watcher" });
  }
});

router.delete("/:id", async (req, res) => {
  try {
    return res.json(await deleteWatcher(req.params.id));
  } catch (error) {
    return res.status(400).json({ error: error instanceof Error ? error.message : "Failed to delete watcher" });
  }
});

router.post("/:id/run", async (req, res) => {
  try {
    await runWatcherById(req.params.id);
    return res.json({ ok: true });
  } catch (error) {
    return res.status(400).json({ error: error instanceof Error ? error.message : "Watcher run failed" });
  }
});

router.get("/summary", async (_req, res) => {
  return res.json(await getWatcherSummary());
});

router.get("/items", async (_req, res) => {
  return res.json(await getWatcherItems());
});

router.get("/image", async (req, res) => {
  const watcherId = String(req.query.watcherId ?? "");
  const imageUrl = String(req.query.url ?? "");
  if (!watcherId || !imageUrl) {
    return res.status(400).json({ error: "Missing watcherId or url" });
  }
  try {
    const image = await fetchWatcherImage(watcherId, imageUrl);
    const etag = `"${crypto
      .createHash("sha1")
      .update(`${watcherId}:${imageUrl}:${image.data.length}`)
      .digest("hex")}"`;
    if (req.headers["if-none-match"] === etag) {
      res.status(304);
      return res.end();
    }
    res.setHeader("Content-Type", image.contentType);
    res.setHeader("Cache-Control", "private, max-age=1800, immutable");
    res.setHeader("ETag", etag);
    res.setHeader("Vary", "Accept-Encoding");
    return res.send(image.data);
  } catch (error) {
    return res.status(400).json({ error: error instanceof Error ? error.message : "Failed to fetch image" });
  }
});

export default router;
