import { expect, tap } from '@git.zone/tstest/tapbundle';
import { CiscoIosConfigFlow, CiscoIosMapper, createCiscoIosDiscoveryDescriptor, type ICiscoIosSnapshot } from '../../ts/integrations/cisco_ios/index.js';

const arpOutput = `Protocol  Address          Age (min)  Hardware Addr   Type   Interface
Internet  10.10.11.20      0          001d.ec02.07ab  ARPA   Vlan1
`;

const snapshot: ICiscoIosSnapshot = CiscoIosMapper.toSnapshot({ host: '192.168.1.1', name: 'Core Router', username: 'admin', arpOutput });

tap.test('matches explicit DHCP and manual Cisco IOS candidates', async () => {
  const descriptor = createCiscoIosDiscoveryDescriptor();
  const dhcpMatcher = descriptor.getMatchers().find((matcherArg) => matcherArg.id === 'cisco-ios-dhcp-explicit-match');
  const manualMatcher = descriptor.getMatchers().find((matcherArg) => matcherArg.id === 'cisco-ios-manual-match');
  const validator = descriptor.getValidators().find((validatorArg) => validatorArg.id === 'cisco-ios-candidate-validator');

  const dhcp = await dhcpMatcher?.matches({ integrationDomain: 'cisco_ios', ipAddress: '192.168.1.1', hostname: 'core-router', manufacturer: 'Cisco' }, {});
  const manual = await manualMatcher?.matches({ host: '192.168.1.1', username: 'admin', arpOutput }, {});
  const validated = manual?.candidate ? await validator?.validate(manual.candidate, {}) : undefined;

  expect(dhcp?.matched).toBeTrue();
  expect(dhcp?.candidate?.port).toEqual(22);
  expect(dhcp?.candidate?.metadata?.discoveryProtocol).toEqual('dhcp-explicit');
  expect(manual?.matched).toBeTrue();
  expect(manual?.confidence).toEqual('certain');
  expect(manual?.candidate?.metadata?.arpOutput).toEqual(arpOutput);
  expect(validated?.matched).toBeTrue();
});

tap.test('builds Cisco IOS config flow output and validates inputs', async () => {
  const flow = new CiscoIosConfigFlow();
  const step = await flow.start({ source: 'manual', integrationDomain: 'cisco_ios', host: '192.168.1.1', name: 'Core Router' }, {});

  const done = await step.submit?.({ username: 'admin', password: 'secret', port: '2222', presentAgeMinutes: '2' });
  expect(done?.kind).toEqual('done');
  expect(done?.config?.host).toEqual('192.168.1.1');
  expect(done?.config?.username).toEqual('admin');
  expect(done?.config?.password).toEqual('secret');
  expect(done?.config?.port).toEqual(2222);
  expect(done?.config?.presentAgeMinutes).toEqual(2);

  const missingUsername = await step.submit?.({});
  expect(missingUsername?.kind).toEqual('error');
  expect(missingUsername?.error || '').toContain('username');

  const arpDone = await flow.start({ source: 'manual', integrationDomain: 'cisco_ios', metadata: { arpOutput } }, {}).then((arpStep) => arpStep.submit?.({}));
  expect(arpDone?.kind).toEqual('done');
  expect(arpDone?.config?.arpOutput).toEqual(arpOutput);

  const snapshotDone = await step.submit?.({ snapshotJson: JSON.stringify(snapshot) });
  expect(snapshotDone?.kind).toEqual('done');
  expect(snapshotDone?.config?.snapshot?.trackedDevices.length).toEqual(1);

  const invalidSnapshot = await step.submit?.({ username: 'admin', snapshotJson: '{"connected":true}' });
  expect(invalidSnapshot?.kind).toEqual('error');
});

export default tap.start();
