import { mkdir, mkdtemp, rm } from 'node:fs/promises';
import { homedir, tmpdir } from 'node:os';
import { join } from 'node:path';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import {
  brainHomeIsActive,
  fleetAgentEnvDir,
  fleetProfilesDir,
  fleetRolesLocalDir,
  fleetStateDir,
  resolveBrainHome,
  type BrainHomeOptions,
} from './brain-home.js';

describe('fleet brain-home resolution', (): void => {
  let cleanup: string | undefined;

  const savedBrainEnv = process.env['MOSAIC_BRAIN_HOME'];

  beforeEach((): void => {
    delete process.env['MOSAIC_BRAIN_HOME'];
  });

  afterEach(async (): Promise<void> => {
    if (savedBrainEnv === undefined) {
      delete process.env['MOSAIC_BRAIN_HOME'];
    } else {
      process.env['MOSAIC_BRAIN_HOME'] = savedBrainEnv;
    }
    if (cleanup !== undefined) {
      await rm(cleanup, { recursive: true, force: true });
      cleanup = undefined;
    }
  });

  async function makeTmp(): Promise<string> {
    const root = await mkdtemp(join(tmpdir(), 'mosaic-brain-home-'));
    cleanup = root;
    return root;
  }

  it('MOSAIC_BRAIN_HOME env wins over every other signal', (): void => {
    process.env['MOSAIC_BRAIN_HOME'] = '/explicit/brain';
    expect(resolveBrainHome('/any/mosaic-home')).toBe('/explicit/brain');
    expect(fleetAgentEnvDir('/any/mosaic-home')).toBe('/explicit/brain/fleet/agents');
    expect(brainHomeIsActive('/any/mosaic-home')).toBe(true);
  });

  it('injected envBrainHome wins identically (test seam)', (): void => {
    const opts: BrainHomeOptions = { envBrainHome: '/injected/brain' };
    expect(resolveBrainHome('/any/mosaic-home', opts)).toBe('/injected/brain');
    expect(fleetAgentEnvDir('/any/mosaic-home', opts)).toBe('/injected/brain/fleet/agents');
  });

  it('a non-default mosaicHome never adopts the canonical brain (hermetic legacy)', (): void => {
    const mosaicHome = '/tmp/not-the-default-config-home';
    expect(resolveBrainHome(mosaicHome)).toBe(mosaicHome);
    expect(brainHomeIsActive(mosaicHome)).toBe(false);
    expect(fleetAgentEnvDir(mosaicHome)).toBe(join(mosaicHome, 'fleet', 'agents'));
  });

  it('the default config home adopts the brain when it carries fleet/agents', async (): Promise<void> => {
    const root = await makeTmp();
    const brain = join(root, 'brain');
    await mkdir(join(brain, 'fleet', 'agents'), { recursive: true });
    const configHome = join(root, 'config', 'mosaic');
    const opts: BrainHomeOptions = { homes: { brain, configDefault: configHome } };

    expect(resolveBrainHome(configHome, opts)).toBe(brain);
    expect(fleetAgentEnvDir(configHome, opts)).toBe(join(brain, 'fleet', 'agents'));
    expect(fleetRolesLocalDir(configHome, opts)).toBe(join(brain, 'fleet', 'roles.local'));
    expect(fleetProfilesDir(configHome, opts)).toBe(join(brain, 'fleet', 'profiles'));
    expect(fleetStateDir(configHome, opts)).toBe(join(brain, 'fleet'));
    expect(brainHomeIsActive(configHome, opts)).toBe(true);
  });

  it('the default config home stays legacy when no brain exists', async (): Promise<void> => {
    const root = await makeTmp();
    const configHome = join(root, 'config', 'mosaic');
    const opts: BrainHomeOptions = {
      homes: { brain: join(root, 'brain'), configDefault: configHome },
    };

    expect(resolveBrainHome(configHome, opts)).toBe(configHome);
    expect(brainHomeIsActive(configHome, opts)).toBe(false);
  });

  it('an empty MOSAIC_BRAIN_HOME is ignored, not treated as set', (): void => {
    process.env['MOSAIC_BRAIN_HOME'] = '   ';
    expect(resolveBrainHome('/tmp/legacy-home')).toBe('/tmp/legacy-home');
  });

  it('adoption requires fleet/agents specifically, not any brain content', async (): Promise<void> => {
    const root = await makeTmp();
    const brain = join(root, 'brain');
    await mkdir(join(brain, 'fleet'), { recursive: true }); // fleet without agents
    const configHome = join(root, 'config', 'mosaic');
    const opts: BrainHomeOptions = { homes: { brain, configDefault: configHome } };

    expect(resolveBrainHome(configHome, opts)).toBe(configHome);
  });

  it('real-home control: a host brain is adopted only through the default home', (): void => {
    // Control on the un-injected path: this host carries ~/.mosaic/fleet/agents,
    // so the default config home resolves to the brain or legacy — both valid
    // canonical endpoints — while a non-default home never adopts.
    const defaultHome = join(homedir(), '.config', 'mosaic');
    const resolved = resolveBrainHome(defaultHome);
    expect([defaultHome, join(homedir(), '.mosaic')]).toContain(resolved);
    expect(resolveBrainHome(join(homedir(), 'elsewhere', 'mosaic'))).toBe(
      join(homedir(), 'elsewhere', 'mosaic'),
    );
  });
});
