// Small CSV helpers shared across import features.

/** Parse CSV text (handles quoted fields, escaped quotes, CRLF) into row objects keyed by lowercased headers. */
export function parseCsv(text: string): Record<string, string>[] {
  const rows: string[][] = [];
  let cur: string[] = [];
  let field = "";
  let inQuotes = false;
  for (let i = 0; i < text.length; i++) {
    const ch = text[i];
    if (inQuotes) {
      if (ch === '"') {
        if (text[i + 1] === '"') { field += '"'; i++; }
        else inQuotes = false;
      } else field += ch;
    } else {
      if (ch === '"') inQuotes = true;
      else if (ch === ",") { cur.push(field); field = ""; }
      else if (ch === "\n" || ch === "\r") {
        if (ch === "\r" && text[i + 1] === "\n") i++;
        cur.push(field); field = "";
        if (cur.some((c) => c.trim() !== "")) rows.push(cur);
        cur = [];
      } else field += ch;
    }
  }
  if (field !== "" || cur.length) { cur.push(field); if (cur.some((c) => c.trim() !== "")) rows.push(cur); }
  if (rows.length === 0) return [];
  const headers = rows[0].map((h) => h.trim().toLowerCase());
  return rows.slice(1).map((r) => {
    const obj: Record<string, string> = {};
    headers.forEach((h, idx) => { obj[h] = (r[idx] ?? "").trim(); });
    return obj;
  });
}

/** First non-empty value among the candidates. */
export function pick(...vals: (string | undefined)[]): string {
  return vals.find((v) => v && v.trim()) ?? "";
}

const todayET = () => new Date().toLocaleDateString("en-CA", { timeZone: "America/New_York" });

/**
 * Parse a date to YYYY-MM-DD. Returns null when the value can't be understood,
 * so callers can skip rather than silently defaulting. Handles ISO (with or
 * without a time part), M/D/Y and YYYY/M/D with 2- or 4-digit years and
 * `/`, `-`, or `.` separators, and month-name formats (e.g. "Jan 5, 2026").
 */
export function tryParseDate(s: string): string | null {
  if (!s) return null;
  const str = s.trim();
  if (!str) return null;

  // ISO, optionally with a time component
  const iso = str.match(/^(\d{4})-(\d{1,2})-(\d{1,2})/);
  if (iso) return `${iso[1]}-${iso[2].padStart(2, "0")}-${iso[3].padStart(2, "0")}`;

  // Numeric with separators: M/D/Y, D/M/Y, or YYYY/M/D
  const parts = str.split(/[\/\-.]/).map((p) => p.trim());
  if (parts.length === 3 && parts.every((p) => /^\d+$/.test(p))) {
    let [a, b, c] = parts;
    if (a.length === 4) {
      // YYYY/M/D
      return `${a}-${b.padStart(2, "0")}-${c.padStart(2, "0")}`;
    }
    // M/D/Y by default; swap to D/M/Y when the first part can't be a month
    let month = Number(a);
    let day = Number(b);
    if (month > 12 && day <= 12) { [month, day] = [day, month]; }
    let year = c;
    if (year.length <= 2) year = (Number(year) >= 70 ? "19" : "20") + year.padStart(2, "0");
    if (month >= 1 && month <= 12 && day >= 1 && day <= 31) {
      return `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
    }
  }

  // Month-name and other locale formats — let the engine try
  const d = new Date(str);
  if (!isNaN(d.getTime())) {
    return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
  }
  return null;
}

/** Like {@link tryParseDate} but falls back to today (ET) when unparseable. */
export function parseDateStr(s: string): string {
  return tryParseDate(s) ?? todayET();
}
