#! /usr/bin/env python3
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
# Copyright © 2020 Dominik Fleischmann dominik.fleischmann@canonical.com

"""Operator Charm main library."""
# Load modules from lib directory
import logging

import setuppath  # noqa:F401
from ops.charm import CharmBase
from ops.framework import StoredState
from ops.main import main
from ops.model import ActiveStatus, MaintenanceStatus


class SquidK8SCharm(CharmBase):
    """Class reprisenting this Operator charm."""

    state = StoredState()

    def __init__(self, *args):
        """Initialize charm and configure states and events to observe."""
        super().__init__(*args)
        # -- standard hook observation
        self.framework.observe(self.on.install, self.on_install)
        self.framework.observe(self.on.start, self.on_start)
        self.framework.observe(self.on.config_changed, self.on_config_changed)
#        self.framework.observe(self.on.addconfig_action, self)
        # -- initialize states --
        self.state.set_default(installed=False)
        self.state.set_default(configured=False)
        self.state.set_default(started=False)

    def make_pod_spec(self):
        config = self.framework.model.config
        ports = [{"name": "squid", "containerPort": config["port"], "protocol": "TCP"}]

        spec = {
            "containers": [{
                "name": self.framework.model.app.name,
                "image": config["image"],
                "ports": ports,
            }],
        }

        return spec

    def _apply_spec(self, spec):
        # Only apply the spec if this unit is a leader
        if self.framework.model.unit.is_leader():
            self.framework.model.pod.set_spec(spec)
            self.state.spec = spec

    def on_install(self, event):
        """Handle install state."""
        self.unit.status = MaintenanceStatus("Installing charm software")
        # Perform install tasks
        self.unit.status = MaintenanceStatus("Install complete")
        logging.info("Install of software complete")
        self.state.installed = True

    def on_config_changed(self, event):
        """Handle config changed."""

        if not self.state.installed:
            logging.warning("Config changed called before install complete, deferring event: {}.".format(event.handle))
            self._defer_once(event)

            return

        if self.state.started:
            # Stop if necessary for reconfig
            logging.info("Stopping for configuration, event handle: {}".format(event.handle))
        # Configure the software
        logging.info("Configuring")
        self.state.configured = True

    def on_start(self, event):
        """Handle start state."""

        if not self.state.configured:
            logging.warning("Start called before configuration complete, deferring event: {}".format(event.handle))
            self._defer_once(event)

            return
        self.unit.status = MaintenanceStatus("Applying pod spec")
        # Start software
        new_pod_spec = self.make_pod_spec()
        self._apply_spec(new_pod_spec)

        self.unit.status = ActiveStatus("Unit is ready")
        self.state.started = True
        logging.info("Started")

    def _defer_once(self, event):
        """Defer the given event, but only once."""
        notice_count = 0
        handle = str(event.handle)

        for event_path, _, _ in self.framework._storage.notices(None):
            if event_path.startswith(handle.split('[')[0]):
                notice_count += 1
                logging.debug("Found event: {} x {}".format(event_path, notice_count))

        if notice_count > 1:
            logging.debug("Not deferring {} notice count of {}".format(handle, notice_count))
        else:
            logging.debug("Deferring {} notice count of {}".format(handle, notice_count))
            event.defer()

    def on_addconfig_action(self, event):
        """Handle the example_action action."""
        event.log("Hello from the example action.")
        event.set_results({"success": "true"})


if __name__ == "__main__":
    from ops.main import main
    main(SquidK8SCharm)