"""Discovery module.

This module uses async_upnp_client to discover devices supporting the
urn:schemas-sony-com:service:ScalarWebAPI:1 service used by this library.
"""

import logging
from xml import etree

import attr
from async_upnp_client.aiohttp import AiohttpRequester
from async_upnp_client.client_factory import UpnpFactory
from async_upnp_client.search import async_search

_LOGGER = logging.getLogger(__name__)


@attr.s
class DiscoveredDevice:
    """Container for discovered device information."""

    name = attr.ib()
    model_number = attr.ib()
    udn = attr.ib()
    services = attr.ib()
    upnp_location = attr.ib()
    endpoint = attr.ib()
    version = attr.ib()
    upnp_services = attr.ib()


class Discover:
    """Implementation of UPnP discoverer for supported devices."""

    @staticmethod
    async def discover(timeout, debug=0, callback=None, source_address=None):
        """Discover supported devices."""
        ST = "urn:schemas-sony-com:service:ScalarWebAPI:1"
        _LOGGER.info("Discovering for %s seconds" % timeout)

        async def parse_device(device):
            requester = AiohttpRequester()
            factory = UpnpFactory(requester)

            url = device["location"]
            try:
                device = await factory.async_create_device(url)
            except Exception as ex:
                _LOGGER.error(
                    "Unable to download the device description file from %s: %s",
                    url,
                    ex,
                )
                return

            if debug > 0:
                print(etree.ElementTree.tostring(device.xml).decode())

            NS = {"av": "urn:schemas-sony-com:av"}

            info = device.xml.find(".//av:X_ScalarWebAPI_DeviceInfo", NS)
            if not info:
                _LOGGER.error("Unable to find X_ScalaerWebAPI_DeviceInfo")
                return

            endpoint = info.find(".//av:X_ScalarWebAPI_BaseURL", NS).text
            version = info.find(".//av:X_ScalarWebAPI_Version", NS).text
            services = [
                x.text for x in info.findall(".//av:X_ScalarWebAPI_ServiceType", NS)
            ]

            dev = DiscoveredDevice(
                name=device.name,
                model_number=device.model_number,
                udn=device.udn,
                endpoint=endpoint,
                version=version,
                services=services,
                upnp_services=list(device.services.keys()),
                upnp_location=url,
            )

            _LOGGER.debug("Discovered: %s" % dev)

            if callback is not None:
                await callback(dev)

        if source_address is not None:
            source_address = (source_address, 0)

        await async_search(
            timeout=timeout,
            search_target=ST,
            async_callback=parse_device,
            source=source_address,
        )
