"""Kubernetes deployment controller"""
from io import StringIO

from kubernetes.client import (
    V1Container,
    V1ContainerPort,
    V1Deployment,
    V1DeploymentSpec,
    V1EnvVar,
    V1EnvVarSource,
    V1LabelSelector,
    V1ObjectMeta,
    V1PodSpec,
    V1PodTemplateSpec,
    V1Secret,
    V1SecretKeySelector,
    V1Service,
    V1ServicePort,
    V1ServiceSpec,
)
from yaml import dump_all

from passbook import __version__
from passbook.outposts.controllers.base import BaseController


class KubernetesController(BaseController):
    """Manage deployment of outpost in kubernetes"""

    image_base = "beryju/passbook"

    def run(self):
        """Called by scheduled task to reconcile deployment/service/etc"""
        # TODO

    def get_static_deployment(self) -> str:
        with StringIO() as _str:
            dump_all(
                [
                    self.get_deployment_secret(),
                    self.get_deployment(),
                    self.get_service(),
                ],
                stream=_str,
                default_flow_style=False,
            )
            return _str.getvalue()

    def get_object_meta(self, **kwargs) -> V1ObjectMeta:
        """Get common object metadata"""
        return V1ObjectMeta(
            namespace="self.instance.namespace",
            labels={
                "app.kubernetes.io/name": f"passbook-{self.outpost.type.lower()}",
                "app.kubernetes.io/instance": self.outpost.name,
                "app.kubernetes.io/version": __version__,
                "app.kubernetes.io/managed-by": "passbook.beryju.org",
                "passbook.beryju.org/outpost/uuid": self.outpost.uuid.hex,
            },
            **kwargs,
        )

    def get_deployment_secret(self) -> V1Secret:
        """Get secret with token and passbook host"""
        return V1Secret(
            metadata=self.get_object_meta(
                name=f"passbook-outpost-{self.outpost.name}-api"
            ),
            data={
                "passbook_host": self.outpost.config.passbook_host,
                "passbook_host_insecure": str(
                    self.outpost.config.passbook_host_insecure
                ),
                "token": self.outpost.token.token_uuid.hex,
            },
        )

    def get_service(self) -> V1Service:
        """Get service object for outpost based on ports defined"""
        meta = self.get_object_meta(name=f"passbook-outpost-{self.outpost.name}")
        ports = []
        for port_name, port in self.deployment_ports.items():
            ports.append(V1ServicePort(name=port_name, port=port))
        return V1Service(
            metadata=meta,
            spec=V1ServiceSpec(ports=ports, selector=meta.labels, type="ClusterIP"),
        )

    def get_deployment(self) -> V1Deployment:
        """Get deployment object for outpost"""
        # Generate V1ContainerPort objects
        container_ports = []
        for port_name, port in self.deployment_ports.items():
            container_ports.append(V1ContainerPort(container_port=port, name=port_name))
        meta = self.get_object_meta(name=f"passbook-outpost-{self.outpost.name}")
        return V1Deployment(
            metadata=meta,
            spec=V1DeploymentSpec(
                replicas=1,
                selector=V1LabelSelector(match_labels=meta.labels),
                template=V1PodTemplateSpec(
                    metadata=V1ObjectMeta(labels=meta.labels),
                    spec=V1PodSpec(
                        containers=[
                            V1Container(
                                name=self.outpost.type,
                                image=f"{self.image_base}-{self.outpost.type}:{__version__}",
                                ports=container_ports,
                                env=[
                                    V1EnvVar(
                                        name="PASSBOOK_HOST",
                                        value_from=V1EnvVarSource(
                                            secret_key_ref=V1SecretKeySelector(
                                                name=f"passbook-outpost-{self.outpost.name}-api",
                                                key="passbook_host",
                                            )
                                        ),
                                    ),
                                    V1EnvVar(
                                        name="PASSBOOK_TOKEN",
                                        value_from=V1EnvVarSource(
                                            secret_key_ref=V1SecretKeySelector(
                                                name=f"passbook-outpost-{self.outpost.name}-api",
                                                key="token",
                                            )
                                        ),
                                    ),
                                    V1EnvVar(
                                        name="PASSBOOK_INSECURE",
                                        value_from=V1EnvVarSource(
                                            secret_key_ref=V1SecretKeySelector(
                                                name=f"passbook-outpost-{self.outpost.name}-api",
                                                key="passbook_host_insecure",
                                            )
                                        ),
                                    ),
                                ],
                            )
                        ]
                    ),
                ),
            ),
        )