// src/components/keywords/keyword-modal-utils.ts — pure helpers for the
// keyword detail modal (relative time, KD levels, month labels…).
import type {
  Keyword,
  KeywordSource,
  MonthlyVolume,
  SourceMetrics,
} from "@/lib/keywords/types";

/** Trend série for a source: the per-source series if present, else (for the
 *  primary source) the legacy `trend`, else empty. */
export function trendFor(
  keyword: Keyword,
  source: KeywordSource,
): MonthlyVolume[] {
  return (
    keyword.trendBySource?.[source] ??
    (source === keyword.primarySource ? keyword.trend : [])
  );
}

/** Short French relative time: « il y a 3 h », « il y a 2 j »… */
export function relativeFr(iso: string | null | undefined): string | null {
  if (!iso) return null;
  const ts = Date.parse(iso);
  if (Number.isNaN(ts)) return null;
  const diffMin = Math.max(0, Math.round((Date.now() - ts) / 60_000));
  if (diffMin < 1) return "à l'instant";
  if (diffMin < 60) return `il y a ${diffMin} min`;
  const h = Math.round(diffMin / 60);
  if (h < 24) return `il y a ${h} h`;
  const d = Math.round(h / 24);
  if (d < 31) return `il y a ${d} j`;
  const mo = Math.round(d / 30);
  if (mo < 12) return `il y a ${mo} mois`;
  return `il y a ${Math.round(mo / 12)} an(s)`;
}

const MONTHS_FR = [
  "Jan",
  "Fév",
  "Mar",
  "Avr",
  "Mai",
  "Juin",
  "Juil",
  "Août",
  "Sep",
  "Oct",
  "Nov",
  "Déc",
];

/** "2025-12" → "Déc". Falls back to the raw string when unparseable. */
export function monthLabelFr(month: string): string {
  const m = Number(month.slice(5, 7));
  return m >= 1 && m <= 12 ? MONTHS_FR[m - 1] : month;
}

export type KdLevel = {
  label: string;
  /** Design hues (locked): green <30, amber 30–50, red >50, gray for 0/unknown. */
  color: string;
  chipClass: string;
  /** true when KD is absent/0 — show a muted « — » dash, never a green chip
   *  (KD is coerced to 0 on import when missing, so 0 ≠ « Facile »). */
  unknown: boolean;
};

/** KD difficulty level per the design: Facile <30 / Moyen 30–50 / Difficile >50.
 *  Unknown KD (null / ≤0) is NOT « Facile » — it returns a muted « — » level so
 *  missing data never masquerades as an easy keyword (matches KdBadge restraint). */
export function kdLevel(kd: number | null | undefined): KdLevel {
  if (kd == null || kd <= 0) {
    return {
      label: "—",
      color: "var(--color-muted-foreground)",
      chipClass: "bg-muted text-muted-foreground",
      unknown: true,
    };
  }
  if (kd > 50) {
    return {
      label: "Difficile",
      color: "#f06363",
      chipClass: "bg-rose-500/10 text-rose-400",
      unknown: false,
    };
  }
  if (kd >= 30) {
    return {
      label: "Moyen",
      color: "#f5b544",
      chipClass: "bg-amber-500/10 text-amber-400",
      unknown: false,
    };
  }
  return {
    label: "Facile",
    color: "#34d399",
    chipClass: "bg-emerald-500/10 text-emerald-400",
    unknown: false,
  };
}

export const SOURCE_LABELS: Record<KeywordSource, string> = {
  mangools: "Mangools",
  ahrefs: "Ahrefs",
  gsc: "GSC",
  semrush: "Semrush",
  seranking: "SE Ranking",
  manual: "Manuel",
};

/**
 * % delta over a displayed trend window: last point vs first point.
 * Returns null when fewer than 2 points or the base (first point) is 0 —
 * a 0-base ratio is meaningless. Works for absolute volumes and for
 * relative series (Semrush 0..1) alike since it's a pure ratio.
 * Rounded to the nearest integer to match native growthPct rendering.
 */
export function trendDeltaPct(
  points: readonly { volume: number }[],
): number | null {
  if (points.length < 2) return null;
  const base = points[0].volume;
  if (base === 0) return null;
  const last = points[points.length - 1].volume;
  return Math.round(((last - base) / base) * 100);
}

/** Primary metrics with fallback to the first source that actually has data. */
export function primaryMetrics(
  keyword: Keyword,
): { source: KeywordSource; metrics: SourceMetrics } | null {
  const primary = keyword.metrics[keyword.primarySource];
  if (primary) return { source: keyword.primarySource, metrics: primary };
  for (const [source, metrics] of Object.entries(keyword.metrics)) {
    if (metrics) return { source: source as KeywordSource, metrics };
  }
  return null;
}

/** Metrics for the chosen source (toolbar « Source » view), falling back to the
 *  primary metrics when no source is selected or the keyword lacks it. Drives
 *  the keyword modal so it mirrors the reservoir's active source. */
export function activeMetrics(
  keyword: Keyword,
  source?: KeywordSource | "",
): { source: KeywordSource; metrics: SourceMetrics } | null {
  if (source) {
    const m = keyword.metrics[source];
    if (m) return { source, metrics: m };
  }
  return primaryMetrics(keyword);
}

/** Latest data timestamp across per-source metrics + the GSC overlay. */
export function latestUpdatedAt(keyword: Keyword): string | null {
  const dates: string[] = [];
  for (const m of Object.values(keyword.metrics)) {
    if (m?.updatedAt) dates.push(m.updatedAt);
  }
  if (keyword.gsc?.updatedAt) dates.push(keyword.gsc.updatedAt);
  if (dates.length === 0) return null;
  return dates.sort().at(-1) ?? null;
}
