/**
 * SubprojectRegistry - Maps composite project IDs to their split data.
 *
 * When multiple sessions in the same encoded directory have different `cwd` values,
 * they are split into separate "subprojects". Each subproject gets a composite ID
 * of the form `{encodedDir}::{sha256(cwd).slice(0,8)}`.
 *
 * This singleton registry tracks:
 * - Which base directory a composite ID maps to
 * - Which cwd each subproject represents
 * - Which session IDs belong to each subproject
 */

import * as crypto from 'crypto';

interface SubprojectEntry {
  baseDir: string;
  cwd: string;
  sessionIds: Set<string>;
}

class SubprojectRegistryImpl {
  private readonly entries = new Map<string, SubprojectEntry>();

  /**
   * Register a subproject and return its composite ID.
   *
   * @param baseDir - The encoded directory name (e.g., "-Users-name-project")
   * @param cwd - The actual working directory for this subproject
   * @param sessionIds - Session IDs belonging to this subproject
   * @returns Composite ID in the form `{baseDir}::{hash}`
   */
  register(baseDir: string, cwd: string, sessionIds: string[]): string {
    const hash = crypto.createHash('sha256').update(cwd).digest('hex').slice(0, 8);
    const compositeId = `${baseDir}::${hash}`;
    this.entries.set(compositeId, {
      baseDir,
      cwd,
      sessionIds: new Set(sessionIds),
    });
    return compositeId;
  }

  /**
   * Extract the base directory from any project ID (composite or plain).
   * For composite IDs (`{encoded}::{hash}`), returns the encoded part.
   * For plain IDs, returns the ID as-is.
   */
  getBaseDir(projectId: string): string {
    const sep = projectId.indexOf('::');
    if (sep !== -1) {
      return projectId.slice(0, sep);
    }
    return projectId;
  }

  /**
   * Check if a project ID is a composite (split) ID.
   */
  isComposite(projectId: string): boolean {
    return projectId.includes('::');
  }

  /**
   * Get the session ID filter set for a composite project ID.
   * Returns null for plain (non-composite) IDs.
   */
  getSessionFilter(projectId: string): Set<string> | null {
    const entry = this.entries.get(projectId);
    return entry?.sessionIds ?? null;
  }

  /**
   * Get the cwd for a composite project ID.
   * Returns null for plain (non-composite) IDs.
   */
  getCwd(projectId: string): string | null {
    const entry = this.entries.get(projectId);
    return entry?.cwd ?? null;
  }

  /**
   * Get the full entry for a composite project ID.
   */
  getEntry(projectId: string): SubprojectEntry | undefined {
    return this.entries.get(projectId);
  }

  /**
   * Clear all registered subprojects. Called at the start of a full re-scan.
   */
  clear(): void {
    this.entries.clear();
  }
}

/** Module-level singleton */
export const subprojectRegistry = new SubprojectRegistryImpl();
