package com.fabledsword.minstrel.player.output.upnp

import okhttp3.HttpUrl.Companion.toHttpUrl
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertNull

/**
 * Unit tests for the UPnP device-description pull-parser.
 *
 * Android's stock `XmlPullParserFactory.newInstance()` resolves to a
 * real impl on-device but resolves to the android.jar stub class on
 * JVM unit tests. kxml2 is added as a testImplementation dep so
 * `XmlPullParserFactory.newInstance()` finds it via service-provider
 * lookup on the test classpath; the tests run unconditionally.
 */
class DeviceDescriptionTest {

    private val base = "http://192.168.1.50:1400/xml/device_description.xml".toHttpUrl()

    @Test
    fun `parses Sonos-shaped description`() {
        val xml = """
            <?xml version="1.0"?>
            <root xmlns="urn:schemas-upnp-org:device-1-0">
              <device>
                <deviceType>urn:schemas-upnp-org:device:MediaRenderer:1</deviceType>
                <friendlyName>Living Room</friendlyName>
                <manufacturer>Sonos, Inc.</manufacturer>
                <modelName>Sonos One</modelName>
                <UDN>uuid:RINCON_ABC</UDN>
                <serviceList>
                  <service>
                    <serviceType>urn:schemas-upnp-org:service:AVTransport:1</serviceType>
                    <controlURL>/MediaRenderer/AVTransport/Control</controlURL>
                  </service>
                  <service>
                    <serviceType>urn:schemas-upnp-org:service:RenderingControl:1</serviceType>
                    <controlURL>/MediaRenderer/RenderingControl/Control</controlURL>
                  </service>
                </serviceList>
              </device>
            </root>
        """.trimIndent()

        val desc = DeviceDescription.parse(xml, base)
        assertNotNull(desc)
        assertEquals("Living Room", desc.friendlyName)
        assertEquals("Sonos, Inc.", desc.manufacturer)
        assertEquals("Sonos One", desc.modelName)
        assertEquals("uuid:RINCON_ABC", desc.udn)
        assertEquals(
            "http://192.168.1.50:1400/MediaRenderer/AVTransport/Control",
            desc.avTransportControlUrl.toString(),
        )
        assertEquals(
            "http://192.168.1.50:1400/MediaRenderer/RenderingControl/Control",
            desc.renderingControlUrl?.toString(),
        )
        assertNull(desc.zoneGroupTopologyControlUrl)
    }

    @Test
    fun `drops device with no AVTransport service`() {
        val xml = """
            <?xml version="1.0"?>
            <root xmlns="urn:schemas-upnp-org:device-1-0">
              <device>
                <friendlyName>Stub TV</friendlyName>
                <UDN>uuid:STUB</UDN>
                <serviceList>
                  <service>
                    <serviceType>urn:schemas-upnp-org:service:ConnectionManager:1</serviceType>
                    <controlURL>/cm</controlURL>
                  </service>
                </serviceList>
              </device>
            </root>
        """.trimIndent()

        assertNull(DeviceDescription.parse(xml, base))
    }

    @Test
    fun `parses ZoneGroupTopology control URL when present`() {
        val xml = """
            <?xml version="1.0"?>
            <root xmlns="urn:schemas-upnp-org:device-1-0">
              <device>
                <UDN>uuid:RINCON_XYZ</UDN>
                <friendlyName>Office</friendlyName>
                <manufacturer>Sonos, Inc.</manufacturer>
                <modelName>Sonos One</modelName>
                <serviceList>
                  <service>
                    <serviceType>urn:schemas-upnp-org:service:AVTransport:1</serviceType>
                    <controlURL>/MediaRenderer/AVTransport/Control</controlURL>
                  </service>
                  <service>
                    <serviceType>urn:schemas-upnp-org:service:ZoneGroupTopology:1</serviceType>
                    <controlURL>/ZoneGroupTopology/Control</controlURL>
                  </service>
                </serviceList>
              </device>
            </root>
        """.trimIndent()
        val desc = DeviceDescription.parse(xml, base)
        assertNotNull(desc)
        assertEquals(
            "http://192.168.1.50:1400/ZoneGroupTopology/Control",
            desc.zoneGroupTopologyControlUrl?.toString(),
        )
    }

    @Test
    fun `handles missing optional fields`() {
        val xml = """
            <?xml version="1.0"?>
            <root>
              <device>
                <UDN>uuid:MIN</UDN>
                <serviceList>
                  <service>
                    <serviceType>urn:schemas-upnp-org:service:AVTransport:1</serviceType>
                    <controlURL>/avt</controlURL>
                  </service>
                </serviceList>
              </device>
            </root>
        """.trimIndent()

        val desc = DeviceDescription.parse(xml, base)
        assertNotNull(desc)
        assertEquals("", desc.friendlyName)
        assertEquals("", desc.manufacturer)
        assertEquals("", desc.modelName)
        assertNull(desc.renderingControlUrl)
    }
}
