import { parseJsonValue } from "@/lib/utils/parse-json-column";

/** Format seconds as "3m 42s". */
export function formatDuration(seconds: number): string {
  if (seconds <= 0) return "0s";
  const m = Math.floor(seconds / 60);
  const s = seconds % 60;
  if (m === 0) return `${s}s`;
  return `${m}m ${s}s`;
}

/** Format a number with locale grouping. */
export function formatCount(n: number): string {
  return n.toLocaleString("en-US");
}

/** Format percent with one decimal. */
export function formatPercent(n: number): string {
  return `${n.toFixed(1)}%`;
}

const COLLECTOR_LABELS: Record<string, string> = {
  web_link: "Web Link",
  embed: "Embed",
  qr_code: "QR Code",
  email_campaign: "Email",
  social: "Social",
};

export function collectorTypeLabel(type: string | null | undefined): string {
  if (!type) return "Direct";
  return COLLECTOR_LABELS[type] ?? type;
}

/** Human-readable answer from stored JSON value. */
export function formatAnswerDisplay(value: unknown): string {
  const parsed = parseJsonValue(value);
  if (parsed === null || parsed === undefined) return "—";

  if (typeof parsed === "string" || typeof parsed === "number") {
    return String(parsed);
  }

  if (typeof parsed === "object" && !Array.isArray(parsed)) {
    const obj = parsed as Record<string, unknown>;
    if ("text" in obj && obj.text != null) return String(obj.text);
    if ("score" in obj && obj.score != null) return String(obj.score);
    if ("choice" in obj) {
      const c = obj.choice;
      if (Array.isArray(c)) return c.join(", ");
      return String(c ?? "—");
    }
    if ("datetime" in obj && obj.datetime != null) return String(obj.datetime);
    if ("fileName" in obj && obj.fileName != null) return String(obj.fileName);
    if ("matrix" in obj && obj.matrix != null) {
      const m = obj.matrix as Record<string, string>;
      return Object.entries(m)
        .map(([k, v]) => `${k}: ${v}`)
        .join("; ");
    }
  }

  if (Array.isArray(parsed)) return parsed.join(", ");
  return String(parsed);
}

/** Extract scalar values from stored answer for aggregation. */
export function extractAnswerScalars(
  value: unknown,
  questionType: string
): string[] {
  value = parseJsonValue(value);
  if (value === null || value === undefined) return [];

  if (questionType === "open_text") {
    const text =
      typeof value === "object" &&
      value !== null &&
      "text" in (value as object)
        ? String((value as { text: unknown }).text)
        : String(value);
    return text.trim() ? [text.trim()] : [];
  }

  if (questionType === "rating" || questionType === "nps") {
    const score =
      typeof value === "object" &&
      value !== null &&
      "score" in (value as object)
        ? Number((value as { score: unknown }).score)
        : Number(value);
    return Number.isFinite(score) ? [String(score)] : [];
  }

  if (
    questionType === "multiple_choice" ||
    questionType === "checkbox" ||
    questionType === "dropdown"
  ) {
    const choice =
      typeof value === "object" &&
      value !== null &&
      "choice" in (value as object)
        ? (value as { choice: unknown }).choice
        : value;
    if (Array.isArray(choice)) {
      return choice.map(String);
    }
    return choice != null ? [String(choice)] : [];
  }

  const display = formatAnswerDisplay(value);
  return display === "—" ? [] : [display];
}

const STOP_WORDS = new Set([
  "a",
  "an",
  "the",
  "and",
  "or",
  "but",
  "in",
  "on",
  "at",
  "to",
  "for",
  "of",
  "is",
  "it",
  "was",
  "were",
  "be",
  "been",
  "are",
  "this",
  "that",
  "with",
  "as",
  "by",
  "from",
  "our",
  "your",
  "we",
  "you",
  "they",
  "i",
  "my",
  "so",
  "very",
  "just",
  "not",
  "no",
  "yes",
]);

/** Tokenize open-text answers into word frequencies. */
export function tokenizeWords(texts: string[], limit = 24) {
  const counts = new Map<string, number>();

  for (const text of texts) {
    const tokens = text
      .toLowerCase()
      .replace(/[^a-z0-9\s'-]/g, " ")
      .split(/\s+/)
      .filter((w) => w.length > 2 && !STOP_WORDS.has(w));

    for (const word of tokens) {
      counts.set(word, (counts.get(word) ?? 0) + 1);
    }
  }

  return Array.from(counts.entries())
    .sort((a, b) => b[1] - a[1])
    .slice(0, limit)
    .map(([word, count]) => ({ word, count }));
}
