import { createServer, type Socket } from 'node:net';
import { expect, tap } from '@git.zone/tstest/tapbundle';
import { DenonClient } from '../../ts/integrations/denon/index.js';

tap.test('reads Denon telnet state and sends control commands', async () => {
  const commands: string[] = [];
  const server = createServer((socketArg) => {
    let buffer = '';
    socketArg.setEncoding('ascii');
    socketArg.on('data', (chunkArg) => {
      buffer += String(chunkArg);
      const parts = buffer.split('\r');
      buffer = parts.pop() || '';
      for (const part of parts) {
        handleCommand(part.trim(), socketArg, commands);
      }
    });
  });

  await new Promise<void>((resolve) => server.listen(0, '127.0.0.1', resolve));
  try {
    const address = server.address();
    const port = typeof address === 'object' && address ? address.port : 0;
    const client = new DenonClient({ host: '127.0.0.1', port, timeoutMs: 500, responseIdleMs: 50 });
    const snapshot = await client.getSnapshot();
    await client.execute({ command: 'set_volume', volumeLevel: 0.5 });
    await client.execute({ command: 'select_source', source: 'TV' });

    expect(snapshot.online).toBeTrue();
    expect(snapshot.receiverInfo.name).toEqual('Living Room Denon');
    expect(snapshot.state.state).toEqual('playing');
    expect(snapshot.state.volume).toEqual(27);
    expect(snapshot.state.volumeLevel).toEqual(0.45);
    expect(snapshot.state.muted).toBeFalse();
    expect(snapshot.state.sourceName).toEqual('Media server');
    expect(snapshot.state.mediaTitle).toContain('Track One');
    expect(commands.includes('MV30')).toBeTrue();
    expect(commands.includes('SITV')).toBeTrue();
  } finally {
    await new Promise<void>((resolve, reject) => server.close((errorArg) => errorArg ? reject(errorArg) : resolve()));
  }
});

const handleCommand = (commandArg: string, socketArg: Socket, commandsArg: string[]): void => {
  commandsArg.push(commandArg);
  const responses: Record<string, string[]> = {
    'NSFRN ?': ['NSFRN Living Room Denon'],
    'SSFUN ?': ['SSFUNCD CD', 'SSFUNSERVER Media server', 'SSFUNTV TV'],
    'SSSOD ?': ['SSSODV.AUX DEL'],
    'PW?': ['PWON'],
    'MV?': ['MVMAX 60', 'MV27'],
    'MU?': ['MUOFF'],
    'SI?': ['SISERVER'],
    NSE: ['NSE0Track One', 'NSE1XArtist One', 'NSE2XAlbum One'],
  };
  for (const response of responses[commandArg] || []) {
    socketArg.write(`${response}\r`, 'ascii');
  }
};

export default tap.start();
