import argparse
import base64
import json
import sys

import requests
import yaml


class GLPIClient:
    api_url = "https://glpi.{domain}/api.php/v1"
    ca_cert = "/etc/ssl/certs/{domain}-cacert.pem"

    def __init__(self):
        self.parse_args()
        self.read_credentials()

    def add_options(self, parser):
        """
        Override this method in child classes.
        """

    def parse_args(self):
        parser = argparse.ArgumentParser()
        self.add_options(parser)

        self.args = parser.parse_args()

    def read_credentials(self):
        with open("/etc/fuss-server/fuss-server.yaml") as fp:
            fuss_conf = yaml.safe_load(fp)
        try:
            self.domain = fuss_conf["domain"]
            self.pwd = fuss_conf["pass"]
        except KeyError as e:
            print(
                "Error loading fuss-server configuration:",
                e,
                file=sys.stderr,
            )
            sys.exit(1)
        self.api_url = self.api_url.format(domain=self.domain)
        self.ca_cert = self.ca_cert.format(domain=self.domain)

    def get_token(self):
        credentials = base64.b64encode(f"glpi:{self.pwd}".encode()).decode()
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Basic {credentials}",
        }

        r = requests.get(
            f"{self.api_url}/initSession",
            verify=self.ca_cert,
            headers=headers,
        )

        if r.status_code == 200:
            self.token = json.loads(r.content)["session_token"]
            self.headers = {
                "Content-Type": "application/json",
                "Session-Token": self.token,
            }
        else:
            print(r.status_code, r.reason, file=sys.stderr)
            print(r.content, file=sys.stderr)

    def discover_computer_search_codes(self):
        url = f"{self.api_url}/listSearchOptions/Computer"
        r = requests.get(
            url,
            verify=self.ca_cert,
            headers=self.headers,
        )
        options = json.loads(r.content)

        self.computer_search_fields = {}
        for k, v in options.items():
            try:
                uid = v.get("uid")
                name = v.get("name")
            except AttributeError:
                continue
            if uid == "Computer.name":
                self.computer_search_fields["name"] = k
            elif uid == "Computer.id":
                self.computer_search_fields["id"] = k
            elif uid == "Computer.NetworkPort.mac":
                self.computer_search_fields["mac"] = k
            elif uid == "Computer.Group_Item.Group.completename" \
                    and name == "Group":
                self.computer_search_fields["group"] = k
            elif uid == "Computer.Location.completename" \
                    and name == "Location":
                self.computer_search_fields["location"] = k

    def discover_location_search_codes(self):
        url = f"{self.api_url}/listSearchOptions/Location"
        r = requests.get(
            url,
            verify=self.ca_cert,
            headers=self.headers,
        )
        options = json.loads(r.content)

        self.location_search_fields = {}
        for k, v in options.items():
            try:
                uid = v.get("uid")
                name = v.get("name")
            except AttributeError:
                continue
            if uid == "Location.name":
                self.location_search_fields["name"] = k
            elif uid == "Location.room":
                self.location_search_fields["room"] = k
            elif uid == "Location.completename":
                self.location_search_fields["completename"] = k
