/**
 * Memory Card — Cross-module data interchange format.
 *
 * Any module can export items as Memory Cards; any module can import/reference them.
 * Think of it as a universal "clip" format for data flowing between rSpace modules.
 */

import type { DocumentId } from './document';

// ============================================================================
// TYPES
// ============================================================================

/**
 * Core Memory Card — the universal interchange unit.
 */
export interface MemoryCard {
  /** Unique ID (UUID v4 or module-specific) */
  id: string;
  /** Semantic type */
  type: MemoryCardType | string;
  /** Human-readable title */
  title: string;
  /** Optional body text (markdown) */
  body?: string;
  /** Source provenance */
  source: {
    module: string;
    docId: DocumentId;
    itemId?: string;
  };
  /** Freeform tags for filtering/grouping */
  tags: string[];
  /** Unix timestamp (ms) */
  createdAt: number;
  /** Module-specific structured data */
  data?: Record<string, unknown>;
}

/**
 * Well-known card types. Modules can extend with custom strings.
 */
export type MemoryCardType =
  | 'note'
  | 'task'
  | 'event'
  | 'link'
  | 'file'
  | 'vote'
  | 'transaction'
  | 'trip'
  | 'contact'
  | 'shape'
  | 'book'
  | 'product'
  | 'post';

// ============================================================================
// HELPERS
// ============================================================================

/**
 * Create a Memory Card with defaults.
 */
export function createCard(
  fields: Pick<MemoryCard, 'type' | 'title' | 'source'> & Partial<MemoryCard>
): MemoryCard {
  return {
    id: fields.id ?? generateId(),
    type: fields.type,
    title: fields.title,
    body: fields.body,
    source: fields.source,
    tags: fields.tags ?? [],
    createdAt: fields.createdAt ?? Date.now(),
    data: fields.data,
  };
}

/**
 * Filter cards by type.
 */
export function filterByType(cards: MemoryCard[], type: string): MemoryCard[] {
  return cards.filter((c) => c.type === type);
}

/**
 * Filter cards by tag (any match).
 */
export function filterByTag(cards: MemoryCard[], tag: string): MemoryCard[] {
  return cards.filter((c) => c.tags.includes(tag));
}

/**
 * Filter cards by source module.
 */
export function filterByModule(cards: MemoryCard[], module: string): MemoryCard[] {
  return cards.filter((c) => c.source.module === module);
}

/**
 * Sort cards by creation time (newest first).
 */
export function sortByNewest(cards: MemoryCard[]): MemoryCard[] {
  return [...cards].sort((a, b) => b.createdAt - a.createdAt);
}

/**
 * Search cards by title/body text (case-insensitive substring match).
 */
export function searchCards(cards: MemoryCard[], query: string): MemoryCard[] {
  const q = query.toLowerCase();
  return cards.filter(
    (c) =>
      c.title.toLowerCase().includes(q) ||
      (c.body && c.body.toLowerCase().includes(q))
  );
}

// ============================================================================
// CARD EXPORTER INTERFACE
// ============================================================================

/**
 * Modules implement this to export their data as Memory Cards.
 */
export interface CardExporter {
  module: string;
  /** Export all items from a document as cards */
  exportCards(docId: DocumentId, doc: any): MemoryCard[];
  /** Export a single item as a card */
  exportCard?(docId: DocumentId, doc: any, itemId: string): MemoryCard | null;
}

/**
 * Registry of card exporters.
 */
const exporters = new Map<string, CardExporter>();

export function registerExporter(exporter: CardExporter): void {
  exporters.set(exporter.module, exporter);
}

export function getExporter(module: string): CardExporter | undefined {
  return exporters.get(module);
}

export function getAllExporters(): CardExporter[] {
  return Array.from(exporters.values());
}

// ============================================================================
// UTILITIES
// ============================================================================

function generateId(): string {
  // crypto.randomUUID() is available in all modern browsers and Bun
  if (typeof crypto !== 'undefined' && crypto.randomUUID) {
    return crypto.randomUUID();
  }
  // Fallback
  return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
}
