"use server";

import { z } from "zod";

import { apiBaseUrl, getAuthHeaders } from "@/lib";
import { handleApiResponse } from "@/lib/server-actions-helper";
import { AttackPathScan, AttackPathScansResponse } from "@/types/attack-paths";

import { adaptAttackPathScansResponse } from "./scans.adapter";

const UUIDSchema = z.uuid();

const ATTACK_PATH_SCANS_PAGE_SIZE = 100;
const ATTACK_PATH_SCANS_MAX_PAGES = 50;

/**
 * Fetch list of attack path scans (latest scan for each provider).
 *
 * Iterates through every backend page so callers receive the complete
 * dedup'd dataset along with an accurate total count. The underlying
 * endpoint is paginated server-side (default page_size=10), so fetching
 * only the first page would silently hide providers beyond that window.
 */
export const getAttackPathScans = async (): Promise<
  { data: AttackPathScan[] } | undefined
> => {
  const headers = await getAuthHeaders({ contentType: false });
  const allScans: AttackPathScan[] = [];
  let currentPage = 1;
  let lastResponse: AttackPathScansResponse | undefined;
  let hasMorePages = true;

  while (hasMorePages && currentPage <= ATTACK_PATH_SCANS_MAX_PAGES) {
    try {
      const url = new URL(`${apiBaseUrl}/attack-paths-scans`);
      url.searchParams.append("page[number]", currentPage.toString());
      url.searchParams.append(
        "page[size]",
        ATTACK_PATH_SCANS_PAGE_SIZE.toString(),
      );

      const response = await fetch(url.toString(), {
        headers,
        method: "GET",
      });

      const data = (await handleApiResponse(response)) as
        | AttackPathScansResponse
        | undefined;

      if (!data?.data || data.data.length === 0) {
        hasMorePages = false;
        continue;
      }

      allScans.push(...data.data);
      lastResponse = data;

      const totalPages = data.meta?.pagination?.pages ?? 1;
      if (currentPage >= totalPages) {
        hasMorePages = false;
      } else {
        currentPage++;
      }
    } catch (error) {
      console.error("Error fetching attack path scans:", error);
      if (allScans.length === 0) {
        return undefined;
      }
      break;
    }
  }

  if (!lastResponse) {
    return { data: [] };
  }

  const adapted = adaptAttackPathScansResponse({
    ...lastResponse,
    data: allScans,
  });

  return { data: adapted.data };
};

/**
 * Fetch detail of a specific attack path scan
 */
export const getAttackPathScanDetail = async (
  scanId: string,
): Promise<{ data: AttackPathScan } | undefined> => {
  // Validate scanId is a valid UUID format to prevent request forgery
  const validatedScanId = UUIDSchema.safeParse(scanId);
  if (!validatedScanId.success) {
    console.error("Invalid scan ID format");
    return undefined;
  }

  const headers = await getAuthHeaders({ contentType: false });

  try {
    const response = await fetch(
      `${apiBaseUrl}/attack-paths-scans/${validatedScanId.data}`,
      {
        headers,
        method: "GET",
      },
    );

    return handleApiResponse(response);
  } catch (error) {
    console.error("Error fetching attack path scan detail:", error);
    return undefined;
  }
};
