export interface CanvasArtifact {
  id: string;
  type: string;
  title?: string;
  content: unknown;
  metadata?: Record<string, unknown>;
  createdAt: number;
  updatedAt: number;
}

interface CanvasPutInput {
  id?: string;
  type: string;
  title?: string;
  content: unknown;
  metadata?: Record<string, unknown>;
}

/**
 * Ephemeral in-memory canvas store keyed by sessionId.
 * Intended as a gateway runtime foundation for A2UI/canvas surfaces.
 */
export class CanvasStore {
  private readonly sessions = new Map<string, Map<string, CanvasArtifact>>();

  constructor(private readonly maxArtifactsPerSession = 200) {}

  list(sessionId: string): CanvasArtifact[] {
    const entries = this.sessions.get(sessionId);
    if (!entries) {
      return [];
    }
    return Array.from(entries.values()).sort((a, b) => b.updatedAt - a.updatedAt);
  }

  get(sessionId: string, artifactId: string): CanvasArtifact | undefined {
    return this.sessions.get(sessionId)?.get(artifactId);
  }

  put(sessionId: string, input: CanvasPutInput): CanvasArtifact {
    const id = sanitizeArtifactId(input.id);
    const now = Date.now();
    let entries = this.sessions.get(sessionId);
    if (!entries) {
      entries = new Map();
      this.sessions.set(sessionId, entries);
    }

    const existing = entries.get(id);
    const artifact: CanvasArtifact = {
      id,
      type: input.type.trim(),
      title: input.title?.trim() || undefined,
      content: input.content,
      metadata: input.metadata,
      createdAt: existing?.createdAt ?? now,
      updatedAt: now,
    };
    entries.set(id, artifact);

    if (entries.size > this.maxArtifactsPerSession) {
      const oldest = Array.from(entries.values()).sort((a, b) => a.updatedAt - b.updatedAt)[0];
      if (oldest) {
        entries.delete(oldest.id);
      }
    }
    return artifact;
  }

  delete(sessionId: string, artifactId: string): boolean {
    const entries = this.sessions.get(sessionId);
    if (!entries) {
      return false;
    }
    const removed = entries.delete(artifactId);
    if (entries.size === 0) {
      this.sessions.delete(sessionId);
    }
    return removed;
  }

  clear(sessionId: string): number {
    const entries = this.sessions.get(sessionId);
    if (!entries) {
      return 0;
    }
    const count = entries.size;
    this.sessions.delete(sessionId);
    return count;
  }
}

function sanitizeArtifactId(raw?: string): string {
  const value = (raw ?? '').trim();
  if (value) {
    return value.slice(0, 128);
  }
  return `art_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
}
