"use server";

// Manual search, the Sonarr-style "show me what is out there" button.
//
// Both actions re-check the session. Server Actions are reachable by direct
// POST, not only through the buttons on the page, so the layout's admin guard
// governs rendering and nothing else -- and the second of these adds torrents.

import { auth } from "@/auth";
import { revalidatePath } from "next/cache";
import {
  grabRelease,
  searchReleases,
  IndexerUnavailableError,
  type SearchResult,
} from "@/lib/indexer";

async function requireAdmin() {
  const session = await auth();
  if (!session?.user?.isAdmin) throw new Error("Unauthorized");
}

// Errors are returned rather than thrown: an indexer being down, or the fetch
// stack being stopped, is an ordinary condition that belongs in the panel next
// to the results, not an error boundary that blanks the inventory page.
export type SearchState =
  | { ok: true; result: SearchResult }
  | { ok: false; error: string };

export async function runManualSearch(target: {
  mediaItemId: string;
  seasonNumber?: number | null;
  episodeNumber?: number | null;
}): Promise<SearchState> {
  await requireAdmin();
  try {
    return { ok: true, result: await searchReleases(target) };
  } catch (error) {
    if (error instanceof IndexerUnavailableError) return { ok: false, error: error.message };
    return { ok: false, error: error instanceof Error ? error.message : "Search failed" };
  }
}

export type GrabState = { ok: true; message: string } | { ok: false; error: string };

export async function grabCandidate(choice: {
  searchId: string;
  infoHash: string;
}): Promise<GrabState> {
  await requireAdmin();
  try {
    const result = await grabRelease(choice);
    // Sending it to qBittorrent changes what the Downloads page shows, and it
    // changes the inventory row's "in flight" state.
    revalidatePath("/admin/downloads");
    revalidatePath("/admin/inventory");
    revalidatePath("/admin/calendar");
    return result.grabbed
      ? { ok: true, message: `Sent to qBittorrent: ${result.title}` }
      : { ok: false, error: result.reason ?? "Not grabbed" };
  } catch (error) {
    return { ok: false, error: error instanceof Error ? error.message : "Grab failed" };
  }
}
