import { PIPELINE_STAGES, type PipelineStage, SOURCES, type SourceValue } from '@/lib/constants';

import type { SalesFilters } from './sales.service';

/**
 * Lead-category + outcome allowlists for the Sales report filters. Kept
 * here (rather than inline in the route) so the parsing logic is a pure,
 * unit-testable function — the route just hands it the query params.
 */
export const LEAD_CATEGORIES = ['general_interest', 'specific_qualified', 'hot_lead'] as const;
export const OUTCOMES = [
  'won',
  'lost_other_marina',
  'lost_unqualified',
  'lost_no_response',
  'lost_other',
  'cancelled',
] as const;

const SOURCE_VALUES = SOURCES.map((s) => s.value) as ReadonlyArray<SourceValue>;

/**
 * Parse a CSV filter param into a typed allowlist. Unknown values are
 * silently dropped — that way a stale bookmark with a removed enum value
 * degrades to "no filter" instead of a 400.
 */
function parseCsvAllowed<T extends string>(
  raw: string | null,
  allowed: ReadonlyArray<T>,
): T[] | undefined {
  if (!raw) return undefined;
  const parts = raw
    .split(',')
    .map((s) => s.trim())
    .filter((s): s is T => (allowed as ReadonlyArray<string>).includes(s));
  return parts.length > 0 ? parts : undefined;
}

/**
 * Parse a CSV filter param into a free list of ids (no allowlist). Used
 * for the rep filter — `assigned_to` holds user ids, which have no static
 * enum. Empty / whitespace entries are dropped. Drizzle parameterises the
 * downstream `inArray`, so unvalidated ids are injection-safe.
 */
function parseCsvFree(raw: string | null): string[] | undefined {
  if (!raw) return undefined;
  const parts = raw
    .split(',')
    .map((s) => s.trim())
    .filter((s) => s.length > 0);
  return parts.length > 0 ? parts : undefined;
}

/**
 * Parse the Sales report filter query params into a `SalesFilters`
 * object, or `undefined` when no filters are active. Pure — takes a
 * `URLSearchParams` so it round-trips trivially in tests.
 *
 * Recognised params (all CSV): `stage`, `leadCategory`, `outcome`,
 * `source`, `assignedTo`. Date-range (`from`/`to`) and `compare` are NOT
 * filters and are ignored here.
 */
export function parseSalesFilters(params: URLSearchParams): SalesFilters | undefined {
  const stages = parseCsvAllowed<PipelineStage>(params.get('stage'), PIPELINE_STAGES);
  const leadCategories = parseCsvAllowed<(typeof LEAD_CATEGORIES)[number]>(
    params.get('leadCategory'),
    LEAD_CATEGORIES,
  );
  const outcomes = parseCsvAllowed<(typeof OUTCOMES)[number]>(params.get('outcome'), OUTCOMES);
  const sources = parseCsvAllowed<SourceValue>(params.get('source'), SOURCE_VALUES);
  const assignedTo = parseCsvFree(params.get('assignedTo'));

  if (!stages && !leadCategories && !outcomes && !sources && !assignedTo) return undefined;
  return { stages, leadCategories, outcomes, sources, assignedTo };
}
