import test from 'node:test';
import assert from 'node:assert/strict';
import {
  extensionConfigsMatch,
  extensionsNeedingRefresh,
  reconcileAgentSession,
} from './session-reconcile.mjs';

test('extensionConfigsMatch compares available_tools', () => {
  const sessionExt = { name: 'developer', available_tools: ['write', 'edit'] };
  const desired = { name: 'developer', available_tools: ['write', 'edit', 'shell', 'tree'] };
  assert.equal(extensionConfigsMatch(sessionExt, desired), false);
  assert.equal(
    extensionConfigsMatch(
      { name: 'developer', available_tools: ['shell', 'tree', 'write', 'edit'] },
      desired,
    ),
    true,
  );
});

test('extensionsNeedingRefresh upgrades stale developer tools', () => {
  const current = [
    { name: 'developer', available_tools: ['write', 'edit'] },
    { name: 'skills', available_tools: [] },
  ];
  const desired = [
    { name: 'developer', available_tools: ['write', 'edit', 'shell', 'tree'] },
    { name: 'skills', available_tools: [] },
  ];
  const { toRemove, toAdd } = extensionsNeedingRefresh(current, desired);
  assert.deepEqual(toRemove, ['developer']);
  assert.equal(toAdd.length, 1);
  assert.equal(toAdd[0].name, 'developer');
  assert.deepEqual(toAdd[0].available_tools, ['write', 'edit', 'shell', 'tree']);
});

test('extensionsNeedingRefresh adds missing extensions', () => {
  const { toRemove, toAdd } = extensionsNeedingRefresh(
    [{ name: 'developer', available_tools: ['write', 'edit'] }],
    [
      { name: 'developer', available_tools: ['write', 'edit'] },
      { name: 'summon', available_tools: ['load_skill'] },
    ],
  );
  assert.deepEqual(toRemove, []);
  assert.equal(toAdd.length, 1);
  assert.equal(toAdd[0].name, 'summon');
});

test('reconcileAgentSession tolerates invalid working directory during resume sync without restart', async () => {
  const calls = [];
  const apiFetch = async (pathname) => {
    calls.push(pathname);
    if (pathname === '/sessions/session-1') {
      return {
        ok: true,
        text: async () => JSON.stringify({ working_dir: '/stale/workspace' }),
      };
    }
    if (pathname === '/agent/update_working_dir') {
      return {
        ok: false,
        status: 400,
        text: async () => 'Invalid directory path',
      };
    }
    if (pathname === '/sessions/session-1/extensions') {
      return {
        ok: true,
        text: async () => JSON.stringify({ extensions: [] }),
      };
    }
    if (pathname === '/agent/restart') {
      return {
        ok: true,
        text: async () => JSON.stringify({ ok: true }),
      };
    }
    throw new Error(`unexpected path: ${pathname}`);
  };

  await reconcileAgentSession(apiFetch, 'session-1', {
    workingDir: '/valid/workspace',
    sessionPolicy: { extensionOverrides: [] },
    tolerateInvalidWorkingDir: true,
  });

  assert.deepEqual(calls, [
    '/sessions/session-1',
    '/agent/update_working_dir',
    '/sessions/session-1/extensions',
  ]);
});

test('reconcileAgentSession skips restart when extensions already match', async () => {
  const calls = [];
  const apiFetch = async (pathname) => {
    calls.push(pathname);
    if (pathname === '/sessions/session-1') {
      return {
        ok: true,
        text: async () => JSON.stringify({ working_dir: '/valid/workspace' }),
      };
    }
    if (pathname === '/sessions/session-1/extensions') {
      return {
        ok: true,
        text: async () =>
          JSON.stringify({
            extensions: [{ name: 'skills', available_tools: [] }],
          }),
      };
    }
    if (pathname === '/agent/restart') {
      return {
        ok: true,
        text: async () => JSON.stringify({ ok: true }),
      };
    }
    throw new Error(`unexpected path: ${pathname}`);
  };

  await reconcileAgentSession(apiFetch, 'session-1', {
    workingDir: '/valid/workspace',
    sessionPolicy: { extensionOverrides: [{ name: 'skills', available_tools: [] }] },
  });

  assert.deepEqual(calls, ['/sessions/session-1', '/sessions/session-1/extensions']);
});

test('reconcileAgentSession restarts after adding missing extensions', async () => {
  const calls = [];
  const apiFetch = async (pathname) => {
    calls.push(pathname);
    if (pathname === '/sessions/session-1') {
      return {
        ok: true,
        text: async () => JSON.stringify({ working_dir: '/valid/workspace' }),
      };
    }
    if (pathname === '/sessions/session-1/extensions') {
      return {
        ok: true,
        text: async () => JSON.stringify({ extensions: [] }),
      };
    }
    if (pathname === '/agent/add_extension' || pathname === '/agent/restart') {
      return {
        ok: true,
        text: async () => JSON.stringify({ ok: true }),
      };
    }
    throw new Error(`unexpected path: ${pathname}`);
  };

  await reconcileAgentSession(apiFetch, 'session-1', {
    workingDir: '/valid/workspace',
    sessionPolicy: { extensionOverrides: [{ name: 'skills', available_tools: [] }] },
  });

  assert.deepEqual(calls, [
    '/sessions/session-1',
    '/sessions/session-1/extensions',
    '/agent/add_extension',
    '/agent/restart',
  ]);
});
