import { expect, tap } from '@git.zone/tstest/tapbundle';
import { FrontierSiliconClient, FrontierSiliconMapper } from '../../ts/integrations/frontier_silicon/index.js';

const valueResponse = (tagArg: 'c8_array' | 'u8' | 'u32' | 's32', valueArg: string | number): string => `<fsapiResponse><status>FS_OK</status><value><${tagArg}>${valueArg}</${tagArg}></value></fsapiResponse>`;
const okResponse = '<fsapiResponse><status>FS_OK</status></fsapiResponse>';
const listResponse = (itemsArg: string): string => `<fsapiResponse><status>FS_OK</status>${itemsArg}<listend>1</listend></fsapiResponse>`;
const field = (nameArg: string, tagArg: 'c8_array' | 'u8', valueArg: string | number): string => `<field name="${nameArg}"><${tagArg}>${valueArg}</${tagArg}></field>`;
const item = (keyArg: string, fieldsArg: string): string => `<item key="${keyArg}">${fieldsArg}</item>`;

tap.test('reads local FSAPI snapshot and maps entities', async () => {
  const originalFetch = globalThis.fetch;
  const requests: URL[] = [];
  const responses: Record<string, string> = {
    'GET/netRemote.sys.info.friendlyName': valueResponse('c8_array', 'Kitchen Radio'),
    'GET/netRemote.sys.info.radioId': valueResponse('c8_array', 'radio-uuid'),
    'GET/netRemote.sys.info.version': valueResponse('c8_array', 'ir-mmi-FS2026'),
    'GET/netRemote.sys.power': valueResponse('u8', 1),
    'GET/netRemote.sys.mode': valueResponse('u32', 0),
    'GET/netRemote.sys.caps.volumeSteps': valueResponse('u8', 41),
    'GET/netRemote.sys.net.wlan.interfaceEnable': valueResponse('u8', 1),
    'GET/netRemote.sys.net.wlan.macAddress': valueResponse('c8_array', '00:11:22:33:44:55'),
    'GET/netRemote.sys.net.wlan.rssi': valueResponse('u8', 75),
    'GET/netRemote.play.status': valueResponse('u8', 2),
    'GET/netRemote.sys.audio.volume': valueResponse('u8', 20),
    'GET/netRemote.sys.audio.mute': valueResponse('u8', 0),
    'GET/netRemote.play.info.name': valueResponse('c8_array', 'BBC 6 Music'),
    'GET/netRemote.play.info.text': valueResponse('c8_array', 'Example Show'),
    'GET/netRemote.play.info.artist': valueResponse('c8_array', 'Example Artist'),
    'GET/netRemote.play.info.album': valueResponse('c8_array', 'Example Album'),
    'GET/netRemote.play.info.graphicUri': valueResponse('c8_array', 'http://radio.example/cover.jpg'),
    'GET/netRemote.play.info.duration': valueResponse('u32', 180000),
    'GET/netRemote.play.position': valueResponse('u32', 30000),
    'GET/netRemote.play.repeat': valueResponse('u8', 1),
    'GET/netRemote.play.shuffle': valueResponse('u8', 0),
    'GET/netRemote.sys.audio.eqpreset': valueResponse('u8', 1),
    'LIST_GET_NEXT/netRemote.sys.caps.validModes/-1': listResponse(item('0', field('id', 'c8_array', 'ir') + field('label', 'c8_array', 'Internet Radio')) + item('1', field('id', 'c8_array', 'fm') + field('label', 'c8_array', 'FM'))),
    'LIST_GET_NEXT/netRemote.sys.caps.eqPresets/-1': listResponse(item('0', field('label', 'c8_array', 'Flat')) + item('1', field('label', 'c8_array', 'Rock'))),
    'LIST_GET_NEXT/netRemote.nav.presets/-1': listResponse(item('0', field('name', 'c8_array', 'BBC 6 Music') + field('type', 'u8', 1))),
    'SET/netRemote.sys.power': okResponse,
  };

  globalThis.fetch = (async (urlArg: URL | RequestInfo, initArg?: RequestInit) => {
    void initArg;
    const url = new URL(String(urlArg));
    requests.push(url);
    const path = url.pathname.replace(/^\/fsapi\//, '');
    return new Response(responses[path] || '<fsapiResponse><status>FS_NODE_DOES_NOT_EXIST</status></fsapiResponse>', { status: 200 });
  }) as typeof globalThis.fetch;

  try {
    const client = new FrontierSiliconClient({ webfsapiUrl: 'http://radio.local/fsapi', pin: '1234' });
    const snapshot = await client.getSnapshot();
    expect(snapshot.online).toBeTrue();
    expect(snapshot.device.name).toEqual('Kitchen Radio');
    expect(snapshot.device.radioId).toEqual('radio-uuid');
    expect(snapshot.player.playState).toEqual('playing');
    expect(snapshot.player.volume).toEqual(20);
    expect(snapshot.player.maxVolume).toEqual(40);
    expect(snapshot.player.source).toEqual('Internet Radio');
    expect(snapshot.player.soundMode?.label).toEqual('Rock');
    expect(snapshot.presets[0].name).toEqual('BBC 6 Music');

    const entities = FrontierSiliconMapper.toEntities(snapshot);
    const mediaPlayer = entities.find((entityArg) => entityArg.id === 'media_player.kitchen_radio');
    expect(mediaPlayer?.state).toEqual('playing');
    expect(mediaPlayer?.attributes?.volumeLevel).toEqual(0.5);
    expect(mediaPlayer?.attributes?.mediaDuration).toEqual(180);
    expect(mediaPlayer?.attributes?.mediaPosition).toEqual(30);

    await client.execute({ command: 'set_power', powered: false });
    const setPower = requests.find((requestArg) => requestArg.pathname.endsWith('/SET/netRemote.sys.power'));
    expect(setPower?.searchParams.get('value')).toEqual('0');
  } finally {
    globalThis.fetch = originalFetch;
  }
});

export default tap.start();
