import { expect, tap } from '@git.zone/tstest/tapbundle';
import { PrusaLinkConfigFlow, PrusaLinkMapper, createPrusaLinkDiscoveryDescriptor, type IPrusaLinkRawData } from '../../ts/integrations/prusalink/index.js';

tap.test('matches PrusaLink HTTP API candidates and creates config flow output', async () => {
  const descriptor = createPrusaLinkDiscoveryDescriptor();
  const httpMatcher = descriptor.getMatchers().find((matcherArg) => matcherArg.id === 'prusalink-http-match');
  const result = await httpMatcher!.matches({ url: 'http://mk4.local/api/version', name: 'PrusaLink MK4' }, {});

  expect(result.matched).toBeTrue();
  expect(result.candidate?.integrationDomain).toEqual('prusalink');
  expect(result.candidate?.host).toEqual('mk4.local');
  expect(result.candidate?.port).toEqual(80);

  const done = await (await new PrusaLinkConfigFlow().start(result.candidate!, {})).submit!({ password: 'secret' });
  expect(done.kind).toEqual('done');
  expect(done.config?.host).toEqual('mk4.local');
  expect(done.config?.port).toEqual(80);
  expect(done.config?.username).toEqual('maker');
  expect(done.config?.password).toEqual('secret');
});

tap.test('matches manual snapshot entries without requiring live HTTP credentials', async () => {
  const rawData: Partial<IPrusaLinkRawData> = {
    version: { api: '2.0.0', printer: 'Original Prusa MINI', hostname: 'mini' },
    status: { printer: { state: 'PAUSED' } },
    job: { id: 12, state: 'PAUSED', progress: 12 },
  };
  const snapshot = PrusaLinkMapper.toSnapshot({ config: { name: 'Manual Mini' }, rawData, online: true, source: 'manual' });
  const descriptor = createPrusaLinkDiscoveryDescriptor();
  const manualMatcher = descriptor.getMatchers().find((matcherArg) => matcherArg.id === 'prusalink-manual-match');
  const match = await manualMatcher!.matches({ name: 'Manual Prusa', snapshot }, {});

  expect(match.matched).toBeTrue();
  expect(match.candidate?.metadata?.snapshot).toEqual(snapshot);
  const validation = await descriptor.getValidators()[0].validate(match.candidate!, {});
  expect(validation.matched).toBeTrue();

  const done = await (await new PrusaLinkConfigFlow().start(match.candidate!, {})).submit!({});
  expect(done.kind).toEqual('done');
  expect(done.config?.snapshot?.telemetry.state).toEqual('paused');
});

tap.test('rejects unsupported PrusaLink API versions when version data is present', async () => {
  const descriptor = createPrusaLinkDiscoveryDescriptor();
  const candidate = {
    source: 'manual' as const,
    integrationDomain: 'prusalink',
    host: 'old-prusa.local',
    metadata: {
      prusalink: true,
      rawData: { version: { api: '1.0.0', printer: 'Original Prusa MINI' } },
    },
  };
  const validation = await descriptor.getValidators()[0].validate(candidate, {});
  expect(validation.matched).toBeTrue();

  const done = await (await new PrusaLinkConfigFlow().start(candidate, {})).submit!({ password: 'secret' });
  expect(done.kind).toEqual('error');
  expect(done.error).toContain('API v2');
});

tap.test('rejects candidates without PrusaLink hints or usable data', async () => {
  const descriptor = createPrusaLinkDiscoveryDescriptor();
  const matcher = descriptor.getMatchers().find((matcherArg) => matcherArg.id === 'prusalink-manual-match');
  const result = await matcher!.matches({ name: 'Generic service' }, {});
  expect(result.matched).toBeFalse();

  const validation = await descriptor.getValidators()[0].validate({ source: 'manual', name: 'PrusaLink without host' }, {});
  expect(validation.matched).toBeFalse();
});

export default tap.start();
