import { afterEach, describe, it } from 'node:test';
import { strict as assert } from 'node:assert';
import * as fs from 'node:fs';
import * as os from 'node:os';
import * as path from 'node:path';
import { runMxCli, parseLastJson, assertExitCode } from '../helpers/cli-harness.js';
import { createMatrixPackage } from '../helpers/package-fixtures.js';

describe('FP-30 mx outdated/update-fork', () => {
  const tempDirs: string[] = [];

  afterEach(() => {
    while (tempDirs.length > 0) {
      const dir = tempDirs.pop();
      if (dir) {
        fs.rmSync(dir, { recursive: true, force: true });
      }
    }
  });

  it('reports outdated forks and updates fork upstream version metadata', async () => {
    const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-outdated-'));
    tempDirs.push(root);
    const workspaceDir = path.join(root, 'workspace');
    fs.mkdirSync(workspaceDir, { recursive: true });

    const packagesDir = path.join(root, '.matrix', 'packages');
    const registryDir = path.join(root, '.matrix', 'registry');
    const credentialsFile = path.join(root, '.matrix', 'credentials.json');

    const upstreamV1 = createMatrixPackage(path.join(root, 'upstream-v1'), {
      packageName: '@matrix/filesystem',
      version: '1.0.0',
      componentType: 'FolderProjection',
      mount: 'fs',
    });
    const upstreamV12 = createMatrixPackage(path.join(root, 'upstream-v12'), {
      packageName: '@matrix/filesystem',
      version: '1.2.0',
      componentType: 'FolderProjection',
      mount: 'fs',
    });

    const loginResult = await runMxCli([
      'node',
      'mx',
      'login',
      '--username',
      'alice',
      '--token',
      'token-xyz',
      '--credentials-file',
      credentialsFile,
      '--json',
    ], { cwd: workspaceDir });
    assertExitCode(loginResult, 0);

    for (const pkg of [upstreamV1, upstreamV12]) {
      const publishResult = await runMxCli([
        'node',
        'mx',
        'publish',
        '--registry-dir',
        registryDir,
        '--credentials-file',
        credentialsFile,
        '--json',
      ], { cwd: pkg.packageDir });
      assertExitCode(publishResult, 0);
    }

    const installOrigin = await runMxCli([
      'node',
      'mx',
      'install',
      '@matrix/filesystem@1.0.0',
      '--packages-dir',
      packagesDir,
      '--registry-dir',
      registryDir,
      '--json',
    ], { cwd: workspaceDir });
    assertExitCode(installOrigin, 0);

    const forkResult = await runMxCli([
      'node',
      'mx',
      'fork',
      '@matrix/filesystem',
      '--name',
      '@alice/filesystem',
      '--packages-dir',
      packagesDir,
      '--forked-by',
      'alice',
      '--json',
    ], { cwd: workspaceDir });
    assertExitCode(forkResult, 0);

    const outdatedResult = await runMxCli([
      'node',
      'mx',
      'outdated',
      '--packages-dir',
      packagesDir,
      '--registry-dir',
      registryDir,
      '--json',
    ], { cwd: workspaceDir });
    assertExitCode(outdatedResult, 0);
    const outdatedPayload = parseLastJson(outdatedResult.logs) as Array<{
      packageName: string;
      status: string;
      latestOriginVersion: string | null;
    }>;
    const forkEntry = outdatedPayload.find((entry) => entry.packageName === '@alice/filesystem');
    assert.ok(forkEntry);
    assert.equal(forkEntry?.status, 'outdated');
    assert.equal(forkEntry?.latestOriginVersion, '1.2.0');

    const updateResult = await runMxCli([
      'node',
      'mx',
      'update-fork',
      '@alice/filesystem',
      '--packages-dir',
      packagesDir,
      '--registry-dir',
      registryDir,
      '--json',
    ], { cwd: workspaceDir });
    assertExitCode(updateResult, 0);
    const updatePayload = parseLastJson(updateResult.logs) as {
      updated: boolean;
      previousOriginVersion: string;
      nextOriginVersion: string;
    };
    assert.equal(updatePayload.updated, true);
    assert.equal(updatePayload.previousOriginVersion, '1.0.0');
    assert.equal(updatePayload.nextOriginVersion, '1.2.0');
  });
});
