import assert from 'node:assert/strict';
import { execFile } from 'node:child_process';
import { mkdtemp, mkdir, writeFile, readFile, rm, realpath, symlink } from 'node:fs/promises';
import { promisify } from 'node:util';
import { join } from 'node:path';
import * as Effect from 'effect/Effect';
import * as Layer from 'effect/Layer';
import * as ManagedRuntime from 'effect/ManagedRuntime';
import * as Schema from 'effect/Schema';
import * as NodeServices from '@effect/platform-node/NodeServices';
import { EnvironmentId, VcsListRefsResult } from '/home/ubuntu/wt/worktree-git-11b/packages/contracts/src/index.ts';
import * as GitVcsDriver from '/home/ubuntu/wt/worktree-git-11b/apps/server/src/vcs/GitVcsDriver.ts';
import * as ServerConfig from '/home/ubuntu/wt/worktree-git-11b/apps/server/src/config.ts';
import { checkoutNewTaskBranch } from '/home/ubuntu/wt/worktree-git-11b/apps/mobile/src/features/threads/checkout-new-task-branch.ts';
import { settlePromise, squashAtomCommandFailure } from '/home/ubuntu/wt/worktree-git-11b/packages/client-runtime/src/state/runtime.ts';

const exec = promisify(execFile);
const temporary = await realpath(await mkdtemp('/tmp/20825-headless-'));
const cwd = join(temporary, 'repo');
const held = join(temporary, 'held');
const git = async (...args) => (await exec('git', ['-C', cwd, ...args])).stdout.trim();
const branch = { name: 'feature/a', current: false, isDefault: false, worktreePath: null };
const environmentId = EnvironmentId.make('20825-disposable-proof');
const makeRuntime = () => ManagedRuntime.make(GitVcsDriver.layer.pipe(
  Layer.provide(ServerConfig.layerTest(temporary, { prefix: '20825-proof-state-' })),
  Layer.provideMerge(NodeServices.layer),
));
let runtime = makeRuntime();
const service = async (f) => runtime.runPromise(Effect.flatMap(GitVcsDriver.GitVcsDriver, f));
const decode = Schema.decodeUnknownSync(VcsListRefsResult);
const output = [];
let switches = 0;
const readRefs = ({ input }) => settlePromise(async () => decode(JSON.parse(JSON.stringify(await service(driver => driver.listRefs(input))))));
const switchRef = ({ input }) => settlePromise(async () => {
  switches++;
  return service(driver => driver.switchRef(input));
});
async function select(name, selected, projectCwd, expected, refs = readRefs) {
  const result = await checkoutNewTaskBranch({ branch: selected, project: { environmentId, workspaceRoot: projectCwd }, workspaceMode: 'local', readRefs: refs, switchRef });
  assert.equal(result._tag, expected);
  if (expected === 'Failure') {
    const message = String(squashAtomCommandFailure(result));
    assert.match(message, /subdirectory|repository root/);
    output.push({ scenario: name, outcome: 'rejected', message });
  } else {
    output.push({ scenario: name, outcome: 'selected', branch: result.value.name, worktreePath: result.value.worktreePath });
  }
  return result;
}
try {
  await exec('git', ['init', '-b', 'main', cwd]);
  await git('config', 'user.name', 'Disposable proof');
  await git('config', 'user.email', 'proof@example.invalid');
  await mkdir(join(cwd, 'packages/app'), { recursive: true });
  await writeFile(join(cwd, 'packages/app/file.txt'), 'main\n');
  await git('add', '.'); await git('commit', '-m', 'main');
  await git('checkout', '-b', branch.name);
  await writeFile(join(cwd, 'packages/app/file.txt'), 'feature\n');
  await git('commit', '-am', 'feature'); await git('checkout', 'main');
  for (const remote of ['origin', 'team/upstream']) {
    const bare = join(temporary, remote.replaceAll('/', '-') + '.git');
    await exec('git', ['init', '--bare', bare]);
    await git('remote', 'add', remote, bare);
    await git('push', remote, 'feature/a:refs/heads/feature/a');
  }
  await git('branch', '--set-upstream-to=team/upstream/feature/a', branch.name);
  await git('worktree', 'add', held, branch.name);
  const rootHistorical = await select('root project, historical branch', branch, cwd, 'Success');
  assert.equal(rootHistorical.value.worktreePath, held);
  const rootPicker = await select('root project, direct picker', { ...branch, worktreePath: held }, cwd, 'Success');
  assert.equal(rootPicker.value.worktreePath, held);
  const remoteBranch = { ...branch, isRemote: true, remoteName: 'team/upstream', name: 'team/upstream/feature/a' };
  const remote = await select('matching slash-containing remote', remoteBranch, cwd, 'Success');
  assert.equal(remote.value.worktreePath, held);
  const alias = join(temporary, 'alias');
  await symlink(cwd, alias, 'dir');
  const aliased = await select('symlinked root project, direct picker', { ...branch, worktreePath: held }, alias, 'Success');
  assert.equal(aliased.value.worktreePath, held);
  for (const direct of [false, true]) {
    await select('nested project, ' + (direct ? 'picker' : 'historical'), { ...branch, worktreePath: direct ? held : null }, join(cwd, 'packages/app'), 'Failure');
  }
  await select('older server missing root metadata', branch, cwd, 'Failure', request => readRefs(request).then(result => {
    if (result._tag !== 'Success') return result;
    const { isAtRepositoryRoot, ...value } = result.value;
    return { ...result, value };
  }));
  const current = await select('nested project, already-current historical branch', { ...branch, name: 'main' }, join(cwd, 'packages/app'), 'Success');
  assert.equal(current.value.worktreePath, null);
  assert.equal(switches, 0);
  assert.equal(await git('branch', '--show-current'), 'main');
  assert.equal(await readFile(join(cwd, 'packages/app/file.txt'), 'utf8'), 'main\n');
  assert.equal(await readFile(join(held, 'packages/app/file.txt'), 'utf8'), 'feature\n');
  await git('push', '--force', 'team/upstream', 'main:refs/heads/feature/a');
  await git('branch', '--set-upstream-to=origin/feature/a', branch.name);
  // This is a separate static fixture phase, outside the server's refresh coalescing window.
  await runtime.dispose();
  runtime = makeRuntime();
  const mismatch = await select('different upstream uses actual server switchRef', remoteBranch, cwd, 'Success');
  assert.equal(mismatch.value.worktreePath, null);
  assert.equal(switches, 1);
  assert.equal(await git('rev-parse', 'HEAD'), await git('rev-parse', 'team/upstream/feature/a'));
  assert.equal(await readFile(join(held, 'packages/app/file.txt'), 'utf8'), 'feature\n');
  await exec('git', ['-C', held, 'checkout', '-b', 'other-branch']);
  await runtime.dispose();
  runtime = makeRuntime();
  const stale = await select('free historical branch clears its previous worktree path', { ...branch, worktreePath: held }, cwd, 'Success');
  assert.equal(stale.value.worktreePath, null);
  assert.equal(switches, 2);
  assert.equal(await git('branch', '--show-current'), 'feature/a');
  assert.equal(await readFile(join(cwd, 'packages/app/file.txt'), 'utf8'), 'feature\n');
  assert.equal((await exec('git', ['-C', held, 'branch', '--show-current'])).stdout.trim(), 'other-branch');
  console.log(JSON.stringify({ head: (await exec('git', ['rev-parse', 'HEAD'], { cwd: '/home/ubuntu/wt/worktree-git-11b' })).stdout.trim(), transport: 'in-process real GitVcsDriver -> JSON and VcsListRefsResult schema -> production mobile helper', uiVerified: false, scenarios: output, assertions: 'all passed; reused/rejected paths never switched original checkout; mismatched-remote and free-branch fallbacks used real switchRef; held worktree contents unchanged' }, null, 2));
} finally {
  await runtime.dispose();
  await rm(temporary, { recursive: true, force: true });
}
