import { redactBrowserText } from "../redact";
import type { ActivitySkippedEntry, ActivitySkipReason } from "./types";

const MAX_COLLECTED = 500;
const MAX_EXCERPT_CHARS = 240;

const REASON_TEXT: Record<ActivitySkipReason, string> = {
  "unreadable-file": "the file could not be read",
  "unparseable-json": "the record is not valid JSON",
  "not-an-object": "the record parsed to a value that is not a JSON object",
  "unsupported-schema": "the record declares a schema this reader does not understand",
  "missing-fields": "the record is missing a field this reader requires",
  "invalid-timestamp": "the record's timestamp is not a parseable date",
};

export interface SkipLocation {
  path: string;
  line?: number;
}

export interface SkipCollector {
  /** Exact number of skipped records, independent of how many were collected. */
  readonly count: number;
  readonly entries: ActivitySkippedEntry[];
  readonly truncated: boolean;
  record(reason: ActivitySkipReason, where: SkipLocation, raw?: string, detail?: string): void;
}

function excerptOf(raw: string | undefined): string | undefined {
  if (raw === undefined) return undefined;
  const collapsed = raw.replace(/\s+/g, " ").trim();
  if (collapsed.length === 0) return undefined;
  const redacted = redactBrowserText(collapsed);
  return redacted.length <= MAX_EXCERPT_CHARS ? redacted : `${redacted.slice(0, MAX_EXCERPT_CHARS)}…`;
}

export function createSkipCollector(sourceId: string, collect = false, max = MAX_COLLECTED): SkipCollector {
  const entries: ActivitySkippedEntry[] = [];
  let count = 0;
  let truncated = false;

  return {
    get count() {
      return count;
    },
    entries,
    get truncated() {
      return truncated;
    },
    record(reason, where, raw, detail) {
      count += 1;
      if (!collect) return;
      if (entries.length >= max) {
        truncated = true;
        return;
      }

      const excerpt = excerptOf(raw);
      const entry: ActivitySkippedEntry = {
        id: `${sourceId}:skip:${count}`,
        reason,
        explanation: detail === undefined ? REASON_TEXT[reason] : `${REASON_TEXT[reason]} — ${detail}`,
        path: where.path,
        ...(where.line === undefined ? {} : { line: where.line }),
        ...(excerpt === undefined ? {} : { excerpt }),
      };
      entries.push(entry);
    },
  };
}
