// Starry Night design tokens for the Agentic Memory dashboard

export const colors = {
  bg: '#070d1c',
  bgRaised: '#0c1628',
  bgSunken: '#050a16',
  panel: 'rgba(12, 22, 40, 0.72)',
  panelHi: 'rgba(20, 34, 58, 0.85)',
  fg: '#c8dde8',
  fgDim: '#8ba4b8',
  fgFaint: '#5e7387',
  border: 'rgba(90, 173, 175, 0.18)',
  borderHi: 'rgba(90, 173, 175, 0.42)',
  borderDim: 'rgba(200, 221, 232, 0.08)',
  teal: '#5aadaf',
  blue: '#5b8ab8',
  olive: '#b8c84a',
  mint: '#62c4bc',
  rust: '#c87a4a',
} as const;

// ── Namespace config ──
// Loaded from dashboard/public/namespace-config.json (generated by `make build-skills`
// from skills-registry.yaml). Fallback defaults ensure the dashboard works before
// the first build.

export interface NamespaceEntry {
  badge: string;   // CORE, OS, SKILL, LEGACY
  color: string;   // color key name
  skill?: string;  // originating skill name
}

// Color names → hex values
const COLOR_HEX: Record<string, string> = {
  teal: colors.teal,
  blue: colors.blue,
  olive: colors.olive,
  mint: colors.mint,
  rust: colors.rust,
};

// Mutable registry — populated by loadNamespaceConfig() from namespace-config.json
// (generated by `make build-skills` from skills-registry.yaml).
// No fallback — if the file is missing, the dashboard will error.
let _nsConfig: Record<string, NamespaceEntry> = {};
let _nsLoaded = false;

/** Load namespace config from the generated JSON. Call once at app init.
 *  Throws if the file is missing or malformed — no silent fallbacks. */
export async function loadNamespaceConfig(): Promise<void> {
  if (_nsLoaded) return;
  const res = await fetch('/namespace-config.json');
  if (!res.ok) {
    throw new Error(
      `Failed to load /namespace-config.json (HTTP ${res.status}). ` +
      `Run 'make build-skills' to generate it from skills-registry.yaml.`
    );
  }
  _nsConfig = await res.json();
  _nsLoaded = true;
}

/** Get the full namespace registry (for iteration). */
export function getNamespaceConfig(): Record<string, NamespaceEntry> {
  return _nsConfig;
}

// ── Derived lookups (always read from _nsConfig) ──

export function getNamespace(typeName: string): string {
  // Match longest prefix first (handles multi-segment prefixes)
  // Most prefixes are short (2-6 chars), so simple iteration is fine
  const knownPrefixes = Object.keys(_nsConfig);
  for (const prefix of knownPrefixes) {
    if (typeName.startsWith(prefix + '-')) return prefix;
  }
  return 'unknown';
}

export function getNamespaceColor(namespace: string): string {
  const entry = _nsConfig[namespace];
  if (!entry) return colors.fgFaint;
  return COLOR_HEX[entry.color] ?? colors.fgDim;
}

export function getNamespaceColorRgba(namespace: string, alpha: number): string {
  const hex = getNamespaceColor(namespace);
  const r = parseInt(hex.slice(1, 3), 16);
  const g = parseInt(hex.slice(3, 5), 16);
  const b = parseInt(hex.slice(5, 7), 16);
  return `rgba(${r}, ${g}, ${b}, ${alpha})`;
}

export function getNamespaceBadge(namespace: string): string {
  return _nsConfig[namespace]?.badge ?? 'LEGACY';
}

// Backward-compat exports used by existing components
export const namespaceBadges: Record<string, string> = new Proxy({} as Record<string, string>, {
  get(_target, prop: string) {
    return _nsConfig[prop]?.badge ?? 'LEGACY';
  },
  ownKeys() {
    return Object.keys(_nsConfig);
  },
  getOwnPropertyDescriptor(_target, prop: string) {
    if (prop in _nsConfig) return { configurable: true, enumerable: true, value: _nsConfig[prop].badge };
    return undefined;
  },
});

export const namespaceColors: Record<string, string> = new Proxy({} as Record<string, string>, {
  get(_target, prop: string) {
    return getNamespaceColor(prop as string);
  },
});

// ── Utility functions ──

export function stripPrefix(typeName: string): string {
  const ns = getNamespace(typeName);
  if (ns === 'unknown') return typeName;
  return typeName.slice(ns.length + 1);
}

export function formatRelativeDate(isoDate: string): string {
  const now = new Date();
  const date = new Date(isoDate);
  const diffMs = now.getTime() - date.getTime();
  const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
  if (diffDays === 0) return 'today';
  if (diffDays === 1) return '1d ago';
  if (diffDays < 30) return `${diffDays}d ago`;
  if (diffDays < 365) return `${Math.floor(diffDays / 30)}mo ago`;
  return `${Math.floor(diffDays / 365)}y ago`;
}

export function formatShortDate(isoDate: string): string {
  const date = new Date(isoDate);
  return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
}

export function formatTime(isoDate: string): string {
  const date = new Date(isoDate);
  return date.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' });
}

export function formatMonthYear(isoDate: string): string {
  const date = new Date(isoDate);
  return date.toLocaleDateString('en-US', { month: 'long', year: 'numeric' });
}
