import { expect, tap } from '@git.zone/tstest/tapbundle';
import { DlnaDmsClient, DlnaDmsIntegration } from '../../ts/integrations/dlna_dms/index.js';

const descriptionXml = `<?xml version="1.0"?>
<root>
  <device>
    <deviceType>urn:schemas-upnp-org:device:MediaServer:1</deviceType>
    <friendlyName>Fixture Media Server</friendlyName>
    <manufacturer>Example</manufacturer>
    <modelName>DMS Fixture</modelName>
    <UDN>uuid:fixture-server</UDN>
    <serviceList>
      <service>
        <serviceType>urn:schemas-upnp-org:service:ContentDirectory:1</serviceType>
        <serviceId>urn:upnp-org:serviceId:ContentDirectory</serviceId>
        <controlURL>/ContentDirectory/control</controlURL>
      </service>
      <service>
        <serviceType>urn:schemas-upnp-org:service:ConnectionManager:1</serviceType>
        <serviceId>urn:upnp-org:serviceId:ConnectionManager</serviceId>
        <controlURL>/ConnectionManager/control</controlURL>
      </service>
    </serviceList>
  </device>
</root>`;

const rootDidl = `<DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/"><container id="0" parentID="-1" childCount="2"><dc:title>Fixture Media Server</dc:title><upnp:class>object.container</upnp:class></container></DIDL-Lite>`;
const childrenDidl = `<DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/"><container id="music" parentID="0" childCount="12"><dc:title>Music</dc:title><upnp:class>object.container.album.musicAlbum</upnp:class></container><item id="track-1" parentID="0"><dc:title>Track One</dc:title><upnp:class>object.item.audioItem.musicTrack</upnp:class><res protocolInfo="http-get:*:audio/mpeg:*">/media/track.mp3</res></item></DIDL-Lite>`;

const soapEnvelope = (actionArg: string, bodyArg: string): string => `<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><u:${actionArg}Response xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1">${bodyArg}</u:${actionArg}Response></s:Body></s:Envelope>`;

tap.test('refreshes a live DLNA DMS snapshot from native UPnP responses', async () => {
  const originalFetch = globalThis.fetch;
  const requests: string[] = [];
  globalThis.fetch = (async (inputArg: RequestInfo | URL, initArg?: RequestInit) => {
    const url = String(inputArg);
    requests.push(`${initArg?.method || 'GET'} ${url}`);
    if (url.endsWith('/rootDesc.xml')) {
      return new Response(descriptionXml, { status: 200 });
    }
    const body = String(initArg?.body || '');
    if (body.includes('GetSystemUpdateID')) {
      return new Response(soapEnvelope('GetSystemUpdateID', '<SystemUpdateID>11</SystemUpdateID>'), { status: 200 });
    }
    if (body.includes('GetSearchCapabilities')) {
      return new Response(soapEnvelope('GetSearchCapabilities', '<SearchCaps>dc:title</SearchCaps>'), { status: 200 });
    }
    if (body.includes('GetSortCapabilities')) {
      return new Response(soapEnvelope('GetSortCapabilities', '<SortCaps>dc:title</SortCaps>'), { status: 200 });
    }
    if (body.includes('GetProtocolInfo')) {
      return new Response(soapEnvelope('GetProtocolInfo', '<Source>http-get:*:audio/mpeg:*</Source><Sink></Sink>'), { status: 200 });
    }
    if (body.includes('GetCurrentConnectionIDs')) {
      return new Response(soapEnvelope('GetCurrentConnectionIDs', '<ConnectionIDs>0</ConnectionIDs>'), { status: 200 });
    }
    if (body.includes('BrowseMetadata')) {
      return new Response(soapEnvelope('Browse', `<Result>${escapeXml(rootDidl)}</Result><NumberReturned>1</NumberReturned><TotalMatches>1</TotalMatches><UpdateID>11</UpdateID>`), { status: 200 });
    }
    if (body.includes('BrowseDirectChildren')) {
      return new Response(soapEnvelope('Browse', `<Result>${escapeXml(childrenDidl)}</Result><NumberReturned>2</NumberReturned><TotalMatches>2</TotalMatches><UpdateID>11</UpdateID>`), { status: 200 });
    }
    return new Response('', { status: 404 });
  }) as typeof globalThis.fetch;

  try {
    const client = new DlnaDmsClient({ location: 'http://192.168.1.60:8200/rootDesc.xml' });
    const snapshot = await client.refresh();
    expect(snapshot.online).toBeTrue();
    expect(snapshot.source).toEqual('upnp');
    expect(snapshot.device.friendlyName).toEqual('Fixture Media Server');
    expect(snapshot.status.systemUpdateId).toEqual(11);
    expect(snapshot.libraries[0].title).toEqual('Music');
    expect(snapshot.contentDirectory.children[1].canPlay).toBeTrue();
    expect(snapshot.contentDirectory.children[1].resources[0].uri).toEqual('http://192.168.1.60:8200/media/track.mp3');
    expect(requests.some((requestArg) => requestArg.includes('/ContentDirectory/control'))).toBeTrue();
  } finally {
    globalThis.fetch = originalFetch;
  }
});

tap.test('does not report live UPnP success without endpoint, snapshot, or client', async () => {
  const runtime = await new DlnaDmsIntegration().setup({}, {});
  const result = await runtime.callService!({ domain: 'dlna_dms', service: 'refresh', target: {} });
  expect(result.success).toBeFalse();
  const snapshot = result.data as { online: boolean; source: string; error?: string };
  expect(snapshot.online).toBeFalse();
  expect(snapshot.source).toEqual('runtime');
  expect(snapshot.error).toContain('requires a device description URL');
  await runtime.destroy();
});

const escapeXml = (valueArg: string): string => valueArg.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&apos;');

export default tap.start();
