import type { DevToolbarIssue } from "../types.ts";

export type DevToolbarIssueListener = (issues: DevToolbarIssue[]) => void;

export interface DevToolbarCollector {
  add(issue: DevToolbarIssue): void;
  addMany(issues: DevToolbarIssue[]): void;
  clear(scope?: string): void;
  getIssues(pathname?: string): DevToolbarIssue[];
  subscribe(listener: DevToolbarIssueListener): () => void;
}

export function createDevToolbarCollector(): DevToolbarCollector {
  const issues = new Map<string, DevToolbarIssue>();
  const listeners = new Set<DevToolbarIssueListener>();
  const emit = () => {
    const snapshot = [...issues.values()].sort((a, b) => b.createdAt - a.createdAt);
    for (const listener of listeners) listener(snapshot);
  };
  return {
    add(issue) {
      issues.set(issue.fingerprint, issue);
      emit();
    },
    addMany(next) {
      for (const issue of next) issues.set(issue.fingerprint, issue);
      emit();
    },
    clear(scope) {
      if (!scope) issues.clear();
      else
        for (const [key, issue] of issues) {
          const pathname =
            typeof issue.metadata?.pathname === "string" ? issue.metadata.pathname : undefined;
          if (pathname === scope || issue.source?.file === scope || issue.category === scope)
            issues.delete(key);
        }
      emit();
    },
    getIssues(pathname) {
      const values = [...issues.values()];
      if (!pathname) return values;
      return values.filter(
        (issue) => !issue.metadata?.pathname || issue.metadata.pathname === pathname,
      );
    },
    subscribe(listener) {
      listeners.add(listener);
      return () => listeners.delete(listener);
    },
  };
}
