import { existsSync } from 'node:fs';
import { homedir } from 'node:os';
import { join, resolve } from 'node:path';

/**
 * Overridable resolution inputs (tests inject tmp homes; production reads
 * the environment and the real home directory).
 */
export interface BrainHomeOptions {
  /** Explicit brain home; defaults to `MOSAIC_BRAIN_HOME`. */
  readonly envBrainHome?: string;
  /**
   * Canonical homes used for adoption. Defaults derive from the real
   * `homedir()`: `{ brain: ~/.mosaic, configDefault: ~/.config/mosaic }`.
   */
  readonly homes?: { readonly brain: string; readonly configDefault: string };
}

/**
 * Brain-home resolution — the three-tree fleet split (stack canon
 * `docs/STRUCTURE-CANON.md` §2, first carried by the USC estate brain):
 *
 *   config home (~/.config/mosaic)  framework templates + dispatch state:
 *                                   fleet/roles (baseline), fleet/roster.yaml,
 *                                   fleet/run (heartbeats), fleet/services
 *   brain home  (~/.mosaic)         user-owned fleet state, committed:
 *                                   fleet/agents/<seat>.env.*, fleet/roles.local,
 *                                   fleet/profiles working copies
 *
 * Resolution order:
 *   1. `MOSAIC_BRAIN_HOME` env (explicit, always wins)
 *   2. canonical `~/.mosaic` — adopted ONLY when mosaicHome is the real
 *      default config home AND `~/.mosaic/fleet/agents` exists. Custom
 *      `--mosaic-home` values (tests, sandboxes, canaries) never trigger
 *      adoption, keeping them hermetic and deterministic.
 *   3. mosaicHome itself (legacy single-tree behavior).
 */
export function resolveBrainHome(mosaicHome: string, options: BrainHomeOptions = {}): string {
  const explicit = options.envBrainHome ?? process.env['MOSAIC_BRAIN_HOME'];
  if (explicit !== undefined && explicit.trim() !== '') {
    return explicit;
  }
  const homes = options.homes ?? {
    brain: join(homedir(), '.mosaic'),
    configDefault: join(homedir(), '.config', 'mosaic'),
  };
  if (resolve(mosaicHome) !== resolve(homes.configDefault)) {
    return mosaicHome;
  }
  return existsSync(join(homes.brain, 'fleet', 'agents')) ? homes.brain : mosaicHome;
}

/** True when fleet state resolves somewhere other than the config home. */
export function brainHomeIsActive(mosaicHome: string, options: BrainHomeOptions = {}): boolean {
  return resolve(resolveBrainHome(mosaicHome, options)) !== resolve(mosaicHome);
}

/** Fleet state root (brain home when active, else the config home). */
export function fleetStateDir(mosaicHome: string, options: BrainHomeOptions = {}): string {
  return join(resolveBrainHome(mosaicHome, options), 'fleet');
}

/** Seat launch envs — `<brainHome>/fleet/agents` when a brain is active. */
export function fleetAgentEnvDir(mosaicHome: string, options: BrainHomeOptions = {}): string {
  return join(fleetStateDir(mosaicHome, options), 'agents');
}

/** PRESERVE-protected persona override layer — `<brainHome>/fleet/roles.local`. */
export function fleetRolesLocalDir(mosaicHome: string, options: BrainHomeOptions = {}): string {
  return join(fleetStateDir(mosaicHome, options), 'roles.local');
}

/** System-type profiles (user working copies) — `<brainHome>/fleet/profiles`. */
export function fleetProfilesDir(mosaicHome: string, options: BrainHomeOptions = {}): string {
  return join(fleetStateDir(mosaicHome, options), 'profiles');
}
