import type { SamSearchParams, SamSearchResponse } from "@/lib/sam-gov/types";

const SAM_BASE_URL = "https://api.sam.gov/opportunities/v2/search";

/** Open solicitations and pre-solicitations — excludes award notices */
const OPEN_PROCUREMENT_TYPES = ["o", "k", "p", "r", "s"];

function formatSamDate(date: Date): string {
  const mm = String(date.getMonth() + 1).padStart(2, "0");
  const dd = String(date.getDate()).padStart(2, "0");
  const yyyy = date.getFullYear();
  return `${mm}/${dd}/${yyyy}`;
}

export function defaultSamDateRange(daysBack = 90): { postedFrom: string; postedTo: string } {
  const postedTo = new Date();
  const postedFrom = new Date();
  postedFrom.setDate(postedFrom.getDate() - daysBack);
  return { postedFrom: formatSamDate(postedFrom), postedTo: formatSamDate(postedTo) };
}

export async function searchSamOpportunities(
  apiKey: string,
  params: SamSearchParams,
): Promise<SamSearchResponse> {
  const url = new URL(SAM_BASE_URL);
  url.searchParams.set("api_key", apiKey);
  url.searchParams.set("ncode", params.naicsCode);
  url.searchParams.set("postedFrom", params.postedFrom);
  url.searchParams.set("postedTo", params.postedTo);
  url.searchParams.set("limit", String(Math.min(params.limit ?? 25, 100)));
  url.searchParams.set("offset", String(params.offset ?? 0));

  for (const ptype of OPEN_PROCUREMENT_TYPES) {
    url.searchParams.append("ptype", ptype);
  }

  if (params.state) {
    url.searchParams.set("state", params.state);
  }
  if (params.title) {
    url.searchParams.set("title", params.title);
  }

  const response = await fetch(url.toString(), {
    headers: { Accept: "application/json" },
    next: { revalidate: 3600 },
  });

  const data = (await response.json()) as SamSearchResponse;

  if (!response.ok || data.errorCode) {
    throw new Error(data.errorMessage ?? `SAM.gov request failed (${response.status})`);
  }

  return data;
}

export async function searchSamByNaicsList(
  apiKey: string,
  naicsCodes: string[],
  options: Omit<SamSearchParams, "naicsCode"> & { perCodeLimit?: number },
): Promise<{ records: SamSearchResponse["opportunitiesData"]; totalRecords: number; naicsUsed: string[] }> {
  const perCodeLimit = options.perCodeLimit ?? 10;
  const seen = new Set<string>();
  const records: NonNullable<SamSearchResponse["opportunitiesData"]> = [];
  const naicsUsed: string[] = [];

  for (const naicsCode of naicsCodes.slice(0, 3)) {
    naicsUsed.push(naicsCode);
    const result = await searchSamOpportunities(apiKey, {
      ...options,
      naicsCode,
      limit: perCodeLimit,
      offset: 0,
    });

    for (const item of result.opportunitiesData ?? []) {
      if (!seen.has(item.noticeId)) {
        seen.add(item.noticeId);
        records.push(item);
      }
    }
  }

  return { records, totalRecords: records.length, naicsUsed };
}
