#!/usr/bin/python3
"""
Extract subscriber preferences using UUID
"""
import sys
from typing import Any, Dict, Tuple

import pymysql.cursors
import os
import configparser
import logging
import argparse

parser = argparse.ArgumentParser(
    prog="Subscriber Info Extactor",
    description="Extract subscriber preferences by UUID",
)

parser.add_argument("-u", "--uuid", dest="uuid")
args = parser.parse_args()
cmdargs = vars(args)
luuid = cmdargs["uuid"]

config = configparser.ConfigParser()
config.read("/etc/mysql/sipwise_extra.cnf")
mysql_user = config["client"]["user"]
mysql_password = config["client"]["password"]

my_port = 3306
BOOLEAN_TYPE = "boolean"
INT_TYPE = "int"
FLOAT_TYPE = "float"
STRING_TYPE = "str"
LIST_TYPE = "list"
DICT_TYPE = "dict"
keep_cdr_days = 120
step_days = 4


# From stackoverflow
def get_env_vars(
    env_file=".env",
    set_environ=True,
    ignore_not_found_error=False,
    exclude_override=(),
):
    """
    Set env vars from a file
    :param env_file:
    :param set_environ:
    :param ignore_not_found_error: ignore not found error
    :param exclude_override: if parameter found in this list, don't overwrite
                             environment
    :return: list of tuples, env vars
    """
    env_vars = []
    try:
        with open(env_file) as f:
            for line in f:
                line = line.replace("\n", "")
                if not line or line.startswith("#"):
                    continue
                # Remove leading `export `
                if line.lower().startswith("export "):
                    key, value = (
                        line.replace("export ", "", 1).strip().split("=", 1)
                    )
                else:
                    try:
                        key, value = line.strip().split("=", 1)
                    except ValueError:
                        logging.error(
                            f"envar_utils.get_env_vars error parsing line: "
                            f"'{line}'"
                        )
                        raise
                if set_environ and key not in exclude_override:
                    os.environ[key] = value
                if key in exclude_override:
                    env_vars.append({"name": key, "value": os.getenv(key)})
                else:
                    env_vars.append({"name": key, "value": value})
    except FileNotFoundError:
        if not ignore_not_found_error:
            raise

    return env_vars


def fetch_query_results(
    node, db_user, db_password, db_name, sqlstate, port
) -> Tuple[[str]:[str]]:
    """
    Queries the specified database.

    :param node: The ngcp_node type.
    :param db_user: The database user.
    :param db_password: The database password.
    :param db_name: The database name.
    :param sqlstate: The SQL state.
    :param port: The port.
    :returns: The response from the query.
    """
    try:
        connection = pymysql.connect(
            host=node,
            user=db_user,
            password=db_password,
            db=db_name,
            charset="utf8mb4",
            cursorclass=pymysql.cursors.DictCursor,
            autocommit=True,
            port=port,
        )
    except pymysql.Error as e:
        print(
            "could not close connection error pymysql %d: %s"
            % (e.args[0], e.args[1])
        )
        sys.exit(1)

    finally:
        with connection.cursor() as cursor:
            for state in sqlstate:
                cursor.execute(state)
            result = cursor.fetchall()
            connection.close()
            return result


def get_subscriber_preferences(
    db_user: str, db_password: str, port: int, db_node: str, uuid: str
) -> Dict[str, Any]:
    """
    Fetch all subscriber preferences for a user with a specific UUID`.

    :param db_user: The database user.
    :param db_password: The database password.
    :param port: The database port.
    :param uuid: The UUID string.
    :returns: The compiled subscriber preferences.
    """
    skip_sql = (
        "select id,domain_id,username "
        "from voip_subscribers "
        'where uuid = "%s"' % uuid,
    )
    user_response = fetch_query_results(
        node=db_node,
        db_user=db_user,
        db_password=db_password,
        db_name="provisioning",
        sqlstate=skip_sql,
        port=port,
    )
    response = {}
    if len(user_response) > 0:
        for uuid_match in user_response:
            if "id" in uuid_match:
                response[uuid] = uuid_match
                selection_sql = (
                    "select a.attribute,"
                    " v.value from provisioning.voip_usr_preferences v,"
                    " provisioning.voip_preferences a  "
                    "where v.subscriber_id=%s and v.attribute_id=a.id;"
                    % uuid_match["id"],
                )
                preferences_response = fetch_query_results(
                    node=db_node,
                    db_user=db_user,
                    db_password=db_password,
                    db_name="provisioning",
                    sqlstate=selection_sql,
                    port=port,
                )
                _location_preferences = {}
                if len(preferences_response) > 0:
                    for preference in preferences_response:
                        attr = preference["attribute"]
                        value = preference["value"]
                        _location_preferences[attr] = value
                response[uuid]["preferences"] = _location_preferences
                domain_id = uuid_match["domain_id"]
                selection_sql_domain = (
                    "select u.domain_id,"
                    " u.attribute_id,"
                    " p.attribute,"
                    " u.value from voip_dom_preferences u,"
                    " voip_preferences p where "
                    "u.attribute_id=p.id and u.domain_id=%s;" % domain_id,
                )
                _domain_preferences = {}
                sql_domain_preferences = fetch_query_results(
                    node=db_node,
                    db_user=db_user,
                    db_password=db_password,
                    db_name="provisioning",
                    sqlstate=selection_sql_domain,
                    port=port,
                )
                if len(sql_domain_preferences) > 0:
                    for preference in sql_domain_preferences:
                        attr = preference["attribute"]
                        value = preference["value"]
                        _domain_preferences[attr] = value
                response[uuid]["dompreferences"] = _domain_preferences
                sql_domain_name = (
                    "select domain "
                    "from voip_domains "
                    "where id = %s;" % domain_id,
                )
                domain_name = fetch_query_results(
                    node=db_node,
                    db_user=db_user,
                    db_password=db_password,
                    db_name="provisioning",
                    sqlstate=sql_domain_name,
                    port=port,
                )
                if len(domain_name) > 0:
                    domain_iname = domain_name[0]["domain"]
                    response[uuid]["domaininame"] = domain_iname
    else:
        print(f"Given UUID: {uuid} is not valid, exiting")
        sys.exit(1)

    return response


needed_info = get_env_vars(
    env_file="/etc/default/ngcp-roles",
    set_environ=False,
    ignore_not_found_error=False,
)
cluster_nodes = []
ngcp_node = "sp"
for iter_item in needed_info:
    if iter_item["name"] == "NGCP_HOSTNAME":
        ngcp_self = iter_item["value"].strip('"')
        cluster_nodes.append(ngcp_self)
    if iter_item["name"] == "NGCP_PEERNAME":
        ngcp_peer = iter_item["value"].strip('"')
        cluster_nodes.append(ngcp_peer)
    if iter_item["name"] == "NGCP_TYPE":
        ngcp_type = iter_item["value"].strip('"')
        if ngcp_type == "carrier":
            ngcp_node = "db01"

subscriber_preferences_response = get_subscriber_preferences(
    db_user=mysql_user,
    db_password=mysql_password,
    port=my_port,
    db_node=ngcp_node,
    uuid="%s" % luuid,
)


def colorize_text(text: str, condition: bool, color: str) -> str:
    """
    Colorizes a message if certain condition is met.

    Changes the color of the message if condition is met. Otherwise
    it defaults to white.

    :param text: The text to colorize.
    :param condition: The condition to format the text.
    :param color: The ANSI 256‑color value.
    :returns: The colorized text.
    """
    if condition:
        return f"\033[38;5;{color}m{text}\033[0m"
    else:
        return f"{text}"


for user in subscriber_preferences_response:
    user_prefs_response = subscriber_preferences_response[user]
    print("=" * 90)
    print(f"Information about preferences for UUID: {user}")
    print(f"Username: {user_prefs_response['username']}")
    print(f"Served by domain: {user_prefs_response['domainname']}")
    print("=" * 90)
    if ("preferences" and "dompreferences") in user_prefs_response:
        subscriber_preferences = user_prefs_response["preferences"]
        domain_preferences = user_prefs_response["dompreferences"]
        all_keys = sorted(
            set(subscriber_preferences.keys()) | set(domain_preferences.keys())
        )
        # Print table header
        print(f"{'Preference':<30} {'Domain':<30} {'Subscriber':<30}")
        print("=" * 90)
        # Print values
        for key in all_keys:
            domain_value = domain_preferences.get(key, "-")
            subscriber_value = subscriber_preferences.get(key, "-")
            colorization_condition = (
                subscriber_value != domain_value
                and subscriber_value != "-"
                and domain_value != "-"
            )
            domain_color = "202"
            subscriber_color = "37"
            colorized_domain_value = colorize_text(
                domain_value, colorization_condition, domain_color
            )
            colorized_subscriber_value = colorize_text(
                subscriber_value, colorization_condition, subscriber_color
            )
            indent = 45 if colorization_condition else 30
            print(
                f"{key:<30} {colorized_domain_value:<{indent}} "
                f"{colorized_subscriber_value:{indent}}"
            )
