"""Snapcast client."""
import logging


_LOGGER = logging.getLogger(__name__)


# pylint: disable=too-many-public-methods
class Snapclient():
    """Represents a snapclient."""

    def __init__(self, server, data):
        """Initialize."""
        self._server = server
        self._snapshot = None
        self._last_seen = None
        self._callback_func = None
        self.update(data)

    def update(self, data):
        """Update client."""
        self._client = data

    @property
    def identifier(self):
        """Get identifier."""
        return self._client.get('id')

    @property
    def group(self):
        """Get group."""
        for group in self._server.groups:
            if self.identifier in group.clients:
                return group
        return None

    @property
    def friendly_name(self):
        """Get friendly name."""
        if len(self._client.get('config').get('name')):
            return self._client.get('config').get('name')
        return self._client.get('host').get('name')

    @property
    def version(self):
        """Version."""
        return self._client.get('snapclient').get('version')

    @property
    def connected(self):
        """Connected or not."""
        return self._client.get('connected')

    @property
    def name(self):
        """Name."""
        return self._client.get('config').get('name')

    async def set_name(self, name):
        """Set a client name."""
        if not name:
            name = ''
        self._client['config']['name'] = name
        await self._server.client_name(self.identifier, name)

    @property
    def latency(self):
        """Latency."""
        return self._client.get('config').get('latency')

    async def set_latency(self, latency):
        """Set client latency."""
        self._client['config']['latency'] = latency
        await self._server.client_latency(self.identifier, latency)

    @property
    def muted(self):
        """Muted or not."""
        return self._client.get('config').get('volume').get('muted')

    async def set_muted(self, status):
        """Set client mute status."""
        new_volume = self._client['config']['volume']
        new_volume['muted'] = status
        self._client['config']['volume']['muted'] = status
        await self._server.client_volume(self.identifier, new_volume)
        _LOGGER.debug('set muted to %s on %s', status, self.friendly_name)

    @property
    def volume(self):
        """Volume percent."""
        return self._client.get('config').get('volume').get('percent')

    async def set_volume(self, percent, update_group=True):
        """Set client volume percent."""
        if percent not in range(0, 101):
            raise ValueError('Volume percent out of range')
        new_volume = self._client['config']['volume']
        new_volume['percent'] = percent
        self._client['config']['volume']['percent'] = percent
        await self._server.client_volume(self.identifier, new_volume)
        if update_group:
            self._server.group(self.group.identifier).callback()
        _LOGGER.debug('set volume to %s on %s', percent, self.friendly_name)

    def groups_available(self):
        """Get available group objects."""
        return list(self._server.groups)

    def update_volume(self, data):
        """Update volume."""
        self._client['config']['volume'] = data['volume']
        _LOGGER.debug('updated volume on %s', self.friendly_name)
        self._server.group(self.group.identifier).callback()
        self.callback()

    def update_name(self, data):
        """Update name."""
        self._client['config']['name'] = data['name']
        _LOGGER.debug('updated name on %s', self.friendly_name)
        self.callback()

    def update_latency(self, data):
        """Update latency."""
        self._client['config']['latency'] = data['latency']
        _LOGGER.debug('updated latency on %s', self.friendly_name)
        self.callback()

    def update_connected(self, status):
        """Update connected."""
        self._client['connected'] = status
        _LOGGER.debug('updated connected status to %s on %s', status, self.friendly_name)
        self.callback()

    def snapshot(self):
        """Snapshot current state."""
        self._snapshot = {
            'name': self.name,
            'volume': self.volume,
            'muted': self.muted,
            'latency': self.latency
        }
        _LOGGER.debug('took snapshot of current state of %s', self.friendly_name)

    async def restore(self):
        """Restore snapshotted state."""
        if not self._snapshot:
            return
        await self.set_name(self._snapshot['name'])
        await self.set_volume(self._snapshot['volume'])
        await self.set_muted(self._snapshot['muted'])
        await self.set_latency(self._snapshot['latency'])
        self.callback()
        _LOGGER.debug('restored snapshot of state of %s', self.friendly_name)

    def callback(self):
        """Run callback."""
        if self._callback_func and callable(self._callback_func):
            self._callback_func(self)

    def set_callback(self, func):
        """Set callback function."""
        self._callback_func = func

    def __repr__(self):
        """Return string representation."""
        return f'Snapclient {self.version} ({self.friendly_name}, {self.identifier})'
