#!/usr/bin/env python3
"""This module contains SpaceEngineersCollector and SpaceEngineersExporter classes."""

import logging
import time

from se_exporter.client.vrage import VRageAPI
from se_exporter.models.base import Base
from prometheus_client import Summary, start_wsgi_server
from prometheus_client.core import REGISTRY, GaugeMetricFamily

logger = logging.getLogger(__name__)


class SpaceEngineersCollector(Base):
    """This object represents a metrics collector for Space Engineers Server."""
    def __init__(self, vrage_client: VRageAPI = None):
        self.vrage_client = vrage_client
        self.summary = Summary(
            "se_request_processing",
            "Time spent collecting SE server data"
        )

    def collect(self) -> GaugeMetricFamily:
        """Collect Space Engineers metrics from VRage API and convert to prometheus format."""
        logger.debug(f"Starting collect SE metrics...")

        with self.summary.time():
            prometheus_metrics = {
                "players": GaugeMetricFamily(
                    "players_count",
                    "Number of online players on the server",
                    labels=["server", "world"]
                ),
                "is_ready": GaugeMetricFamily(
                    "server_is_ready",
                    "The server is ready to connect players",
                    labels=["server", "world"]
                ),
                "player_ping": GaugeMetricFamily(
                    "player_ping",
                    "Just players ping",
                    labels=["server", "world", "player_name", "player_id", "faction"]
                ),
                "planets": GaugeMetricFamily(
                    "planets_count",
                    "Number of planets in the game world",
                    labels=["server", "world"]
                ),
                "sim_speed": GaugeMetricFamily(
                    "simulation_speed",
                    "Currnet simulation speed in the game world",
                    labels=["server", "world"]
                ),
                "simulation_cpu_load": GaugeMetricFamily(
                    "simulation_cpu_load",
                    "CPU load generated by the simulation",
                    labels=["server", "world"]
                ),
                "total_time": GaugeMetricFamily(
                    "server_game_uptime_seconds",
                    "Time during which the server is ready to play",
                    labels=["server", "world"]
                ),
                "used_pcu": GaugeMetricFamily(
                    "total_pcu_used",
                    "Number of total used PCU on the server",
                    labels=["server", "world"]
                ),
                "pirate_used_pcu": GaugeMetricFamily(
                    "pirate_total_pcu_used",
                    "Number of total used PCU by Pirates on the server",
                    labels=["server", "world"]
                ),
                "grids": GaugeMetricFamily(
                    "total_grids",
                    "Count of total grids on the game world",
                    labels=["server", "world"]
                ),
                "asteroids": GaugeMetricFamily(
                    "total_asteroids",
                    "Count of total asteroids on the game world",
                    labels=["server", "world"]
                ),
                "floating_objects": GaugeMetricFamily(
                    "total_floating_objects",
                    "Count of total floating objects on the game world",
                    labels=["server", "world"]
                ),
                "characters": GaugeMetricFamily(
                    "characters_count",
                    "Count of total characters (including disconnected, but are on the server) on the game world",
                    labels=["server", "world"]
                ),
                "banned_players": GaugeMetricFamily(
                    "total_banned_players",
                    "Count of total banned players on the game world",
                    labels=["server", "world"]
                ),
                "kicked_players": GaugeMetricFamily(
                    "total_kicked_players",
                    "Count of total kicked players on the game world",
                    labels=["server", "world"]
                )
            }

            for m in self.vrage_client.metrics():
                if m.name not in prometheus_metrics.keys():
                    if m.name != "version":
                        logger.info(f"Unhandled metric received, {m}")
                    continue

                pm = prometheus_metrics[m.name]
                if m.name == "player_ping":
                    pm.add_metric(
                        [m.server, m.world, m.player_name, m.player_id, m.faction],
                        m.value
                    )
                else:
                    pm.add_metric(
                        [m.server, m.world],
                        m.value
                    )

            for _, metric in prometheus_metrics.items():
                yield metric

        logger.debug(f"SE metrics collection finished")


class SpaceEngineersExporter(Base):
    """This object represents a metrics exporter from Space Engineers Server.
    Register the Space Engineers metrics collector and create WSGI application.
    """
    def __init__(self, vrage_client: VRageAPI = None):
        self.client = vrage_client

    def run(self, addr: str = "0.0.0.0", port: int = 9122) -> None:
        """Register the collector and run WSGI server."""
        REGISTRY.register(
            SpaceEngineersCollector(
                vrage_client=self.client,
            )
        )
        logger.debug("The collector's registration was successful, starting web server...")

        start_wsgi_server(port, addr=addr)
        logger.info(f"Serving the app on {addr}:{port}")

        while True:
            time.sleep(0.5)
