#!/usr/bin/env python3

"""Display if a given host is inactive from metrics.

This script finds hosts that didn't transmit in influxdb a usage_user value from the cpu
measurement in a given period (default 2 minutes).
It is assumed that every host normally sends a usage_user value in a cpu measurement.
"""

import argparse
import subprocess
import sys
from typing import Tuple


def main():
    """Read eeid and hostname, then query influxdb two times:

    First, get the hosts for the given cst_id, then get active hosts.
    Return WARNING if host is inactive.
    Return CRITICAL if host was not found, or any other error.
    """

    args = handle_args()
    checker = CheckMetrics(args)
    checker.run()


def handle_args() -> argparse.Namespace:
    """Parse args and return them to main"""

    parser = argparse.ArgumentParser()
    parser.add_argument(
        "-e",
        "--eeid",
        required=True,
        help="Eeid assigned to host to check",
    )
    parser.add_argument(
        "-H",
        "--host",
        required=True,
        help="Host to check activity for",
    )
    parser.add_argument(
        "-u",
        "--user",
        default="admin",
        help="Influxdb user",
    )
    parser.add_argument(
        "-p",
        "--passwd",
        help="Influxdb password",
    )
    parser.add_argument(
        "-i",
        "--inactive_minutes",
        type=int,
        default=2,
        help="Number of minutes to consider a host inactive, (default=2)",
    )

    return parser.parse_args()


class CheckMetrics:
    """Class to hold the methods and elements to check"""

    def __init__(self, args: argparse.Namespace) -> None:
        self.user: str = args.user
        if args.passwd:
            self.passwd: str = args.passwd
        else:
            with open("/etc/influxdb/.eemonitoring", encoding="utf8") as auth_file:
                self.passwd = auth_file.read().replace("\n", "")
        self.inactive_minutes: int = args.inactive_minutes
        self.eeid = args.eeid
        self.cst_id: str = get_cst_id(args.eeid)
        self.host: str = clean_host(args.host, args.eeid)

    def run(self):
        """Find present and active hosts, exit according to status"""

        present_hosts = self.get_present_hosts_from_influxdb()
        if self.host.lower() not in present_hosts:
            print(f"CRITICAL - Host {self.host} not found for {self.eeid}")
            sys.exit(2)
        active_hosts = self.get_active_hosts_from_influxdb()
        if self.host.lower() not in active_hosts:
            print(f"WARNING - {self.eeid}: {self.host} is inactive")
            sys.exit(1)

        print(f"OK - {self.eeid}: {self.host} is active")

    def get_present_hosts_from_influxdb(self) -> Tuple[str, ...]:
        """Query influxdb to get all hosts present for a given cst_id."""

        command = (
            f"influx -database {self.cst_id} -precision rfc3339 "
            f"-username '{self.user}' -password '{self.passwd}' "
            "-execute 'show tag values from cpu with key = host' -format csv"
        )
        command_run = subprocess.run(command, capture_output=True, check=False, shell=True)
        if command_run.returncode != 0:
            print(f"CRITICAL - {command_run.stderr.decode()}")
            sys.exit(2)

        return tuple(
            line.split(",")[2].lower()
            for line in command_run.stdout.decode().split("\n")[1:]
            if line
        )

    def get_active_hosts_from_influxdb(self) -> Tuple[str, ...]:
        """Query influxdb to get active hosts for a given cst_id."""

        command = (
            rf"influx -database {self.cst_id} -precision rfc3339 "
            f"-username '{self.user}' -password '{self.passwd}' "
            "-execute 'select count(usage_user) "
            f"from cpu where time > now() - {self.inactive_minutes}m "
            "group by host' -format csv"
        )
        command_run = subprocess.run(command, capture_output=True, check=False, shell=True)
        if command_run.returncode != 0:
            print(f"CRITICAL - {command_run.stderr.decode()}")
            sys.exit(2)

        return tuple(
            "".join(item.split("=")[1] for item in line.split(",") if "host=" in item).lower()
            for line in command_run.stdout.decode().split("\n")
            if line and not line.startswith("name")
        )


def get_cst_id(eeid: str) -> str:
    """Compute a cst_id from the given eeid"""

    if eeid == "ee":
        return "eeservers"
    return f"cst_{eeid}"


def clean_host(host: str, eeid: str) -> str:
    """Remove leading prefix if it exists"""

    if host.startswith("ee-"):
        return host[len("ee-") :]
    if host.startswith(f"{eeid}-"):
        return host[len(f"{eeid}-") :]
    return host


if __name__ == "__main__":
    main()
