"""
This example:

1. Connects to the current model
2. Resets it
3. Deploys two charms and relates them
4. Waits for units to be idle, then exits

"""
import asyncio
import logging

from juju.model import Model, ModelObserver
from juju import loop


class MyRemoveObserver(ModelObserver):
    async def on_change(self, delta, old, new, model):
        if delta.type == 'remove':
            assert(new.latest() == new)
            assert(new.next() is None)
            assert(new.dead)
            assert(new.current)
            assert(new.connected)
            assert(new.previous().dead)
            assert(not new.previous().current)
            assert(not new.previous().connected)


class MyModelObserver(ModelObserver):
    _shutting_down = False

    async def on_change(self, delta, old, new, model):
        if model.units and model.all_units_idle() and not self._shutting_down:
            self._shutting_down = True
            logging.debug('All units idle, disconnecting')
            await model.reset(force=True)
            await model.disconnect()


async def main():
    model = Model()
    # connect to current model with current user, per Juju CLI
    await model.connect()

    try:
        model.add_observer(MyRemoveObserver())
        await model.reset(force=True)
        model.add_observer(MyModelObserver())

        ubuntu_app = await model.deploy(
            'ubuntu',
            application_name='ubuntu',
            series='trusty',
            channel='stable',
        )
        ubuntu_app.on_change(asyncio.coroutine(
            lambda delta, old_app, new_app, model:
                print('App changed: {}'.format(new_app.entity_id))
        ))
        ubuntu_app.on_remove(asyncio.coroutine(
            lambda delta, old_app, new_app, model:
                print('App removed: {}'.format(old_app.entity_id))
        ))
        ubuntu_app.on_unit_add(asyncio.coroutine(
            lambda delta, old_unit, new_unit, model:
                print('Unit added: {}'.format(new_unit.entity_id))
        ))
        ubuntu_app.on_unit_remove(asyncio.coroutine(
            lambda delta, old_unit, new_unit, model:
                print('Unit removed: {}'.format(old_unit.entity_id))
        ))
        unit_a, unit_b = await ubuntu_app.add_units(count=2)
        unit_a.on_change(asyncio.coroutine(
            lambda delta, old_unit, new_unit, model:
                print('Unit changed: {}'.format(new_unit.entity_id))
        ))
        await model.deploy(
            'nrpe',
            application_name='nrpe',
            series='trusty',
            channel='stable',
            # subordinates must be deployed without units
            num_units=0,
        )
        my_relation = await model.add_relation(
            'ubuntu',
            'nrpe',
        )
        my_relation.on_remove(asyncio.coroutine(
            lambda delta, old_rel, new_rel, model:
                print('Relation removed: {}'.format(old_rel.endpoints))
        ))
    finally:
        await model.disconnect()


if __name__ == '__main__':
    logging.basicConfig(level=logging.INFO)
    ws_logger = logging.getLogger('websockets.protocol')
    ws_logger.setLevel(logging.INFO)
    loop.run(main())
