import { needsAttention, type DomainStatus } from "./status";

// The Domains page's filters live in the URL (?status=&source=&q=) so views are
// linkable and survive the auto-refresh during a run. Shared by the page and its links.

export const DOMAIN_FILTERS = {
  attention: { label: "Needs Attention", matches: (status: DomainStatus) => needsAttention(status) },
  expired: { label: "Expired / Not Registered", matches: (status: DomainStatus) => status === "EXPIRED" || status === "NOT_REGISTERED" },
  critical: { label: "Critical", matches: (status: DomainStatus) => status === "CRITICAL" },
  warning: { label: "Expiring Soon", matches: (status: DomainStatus) => status === "WARNING" },
  unknown: { label: "Unknown / Not checked", matches: (status: DomainStatus) => status === "UNKNOWN" || status === "PENDING" },
  ok: { label: "OK", matches: (status: DomainStatus) => status === "OK" },
} as const;

export type DomainFilter = keyof typeof DOMAIN_FILTERS;
export const DOMAIN_FILTER_KEYS = Object.keys(DOMAIN_FILTERS) as DomainFilter[];

export const DOMAIN_SOURCES = { all: "All sources", apps: "Used by apps", manual: "Added manually" } as const;
export type DomainSource = keyof typeof DOMAIN_SOURCES;

export type DomainQuery = { status: DomainFilter | null; source: DomainSource; q: string };
export const DEFAULT_DOMAIN_QUERY: DomainQuery = { status: null, source: "all", q: "" };

type RawParams = { [key: string]: string | string[] | undefined };
const first = (value: string | string[] | undefined) => (Array.isArray(value) ? value[0] : value) ?? "";

export function parseDomainQuery(params: RawParams): DomainQuery {
  const status = first(params.status);
  const source = first(params.source);
  return {
    status: status in DOMAIN_FILTERS ? (status as DomainFilter) : null,
    source: source in DOMAIN_SOURCES ? (source as DomainSource) : "all",
    q: first(params.q).trim().slice(0, 100),
  };
}

/** Href for the Domains page with `changes` applied; defaults are left out of the URL. */
export function domainsHref(current: DomainQuery, changes: Partial<DomainQuery> = {}): string {
  const next = { ...current, ...changes };
  const params = new URLSearchParams();
  if (next.status) params.set("status", next.status);
  if (next.source !== "all") params.set("source", next.source);
  if (next.q) params.set("q", next.q);
  const query = params.toString();
  return query ? `/domains?${query}` : "/domains";
}

type FilterableRow = {
  name: string;
  status: DomainStatus;
  apps: Array<{ projectCode: string; projectName: string }>;
  domain: { registrar: string | null; addedManually: boolean } | null;
};

/**
 * Source and search narrow the rows; the status tabs count within that and pick
 * one group. Search matches the domain, its registrar, and its apps' code or name.
 */
export function filterDomainRows<T extends FilterableRow>(rows: T[], query: DomainQuery) {
  const term = query.q.toLowerCase();
  const narrowed = rows.filter((row) => {
    if (query.source === "apps" && row.apps.length === 0) return false;
    if (query.source === "manual" && !row.domain?.addedManually) return false;
    if (!term) return true;
    return (
      row.name.includes(term) ||
      (row.domain?.registrar ?? "").toLowerCase().includes(term) ||
      row.apps.some((app) => app.projectCode.toLowerCase().includes(term) || app.projectName.toLowerCase().includes(term))
    );
  });

  const counts = Object.fromEntries(
    DOMAIN_FILTER_KEYS.map((key) => [key, narrowed.filter((row) => DOMAIN_FILTERS[key].matches(row.status)).length]),
  ) as Record<DomainFilter, number>;
  const shown = query.status ? narrowed.filter((row) => DOMAIN_FILTERS[query.status!].matches(row.status)) : narrowed;

  return { shown, total: narrowed.length, counts };
}
