#!/usr/bin/python3

##
# @file
# @ingroup rtctk_clients_serviceDiscoveryCli
#
# @brief Entry point for the rtctkServiceDiscoveryClient command line utility.
#
# @copyright
#   SPDX-FileCopyrightText: 2023-2025 European Southern Observatory (ESO) @n
#   SPDX-License-Identifier: LGPL-3.0-only

"""
This is the entry point for the service discovery command line utility.
"""

import click
import sys
import os
from rtctk.framework import ServiceDiscovery  # pylint: disable=E0611,E0401
from rtctk.framework import Uri  # pylint: disable=E0611,E0401
from rtctk.framework import RtctkException  # pylint: disable=E0611,E0401
from rtctk.framework import setup_cpp_logging  # pylint: disable=E0611,E0401
from rtctk.common.cli.config import CommonConfigurationParameters  # pylint: disable=E0611,E0401
from elt.log import CiiLogManager  # pylint: disable=E0611,E0401
import enum


class ServicesForCommonType(str, enum.Enum):
    """
    Enumeration of common services available in the Service Discovery.
    """

    # FIXME: Need to cleanup the naming convention.  # pylint: disable=W0511
    rtr = "rtr"  # pylint: disable=C0103
    psr = "psr"  # pylint: disable=C0103
    oldb = "oldb"  # pylint: disable=C0103
    rr = "rr"  # pylint: disable=C0103
    ps = "ps"  # pylint: disable=C0103

    def __repr__(self):
        """
        Return a string representation of the enumeration to provide better CLI error messages.
        """
        return f"'{super().__str__()}'"


# Prevent Doxygen from trying to produce API documentation for the click CLI handling methods.
# The docstring comments will not be appropriate. Click's formatting tags can clash with Doxygen.
# And these methods anyway do not form part of the API.
## @cond __doxygen_ignore__


def _get_consule_address():
    return os.environ.get("CONSUL_HTTP_ADDR", "http://127.0.0.1:8500").split("http://")[-1]


@click.command()
@click.argument(
    "component",
    type=str,
)
@click.argument(
    "service",
    type=click.Choice(ServicesForCommonType),
)
@click.option(
    "--service-discovery-endpoint",
    "--sde",
    "-s",
    default=f"consul://{_get_consule_address()}",
    type=str,
    help="Service Discovery Endpoint, the URI used to identify the ServiceDiscovery to use. "
    "Defaults to CONSUL_HTTP_ADDR environment variable or localhost if not specified.",
    show_default=True,
)
@click.option(
    "--service-type",
    default=f"rtctk_component",
    type=str,
    help="Type of service e.g. RTC Tk component (=rtctk_component)",
    show_default=True,
)
def sdc(component: str, service: str, service_discovery_endpoint: str, service_type: str):
    """Queries the RTC Service Discovery for endpoints.
    This tool is intended to help developers who need the endpoints
    while developing scripts.

    \b
    COMPONENT: must be the string "services" or an RTC component name e.g.: "rtc_sup".

    \b
    SERVICE: if COMPONENT is set to "services", SERVICE should be one of the following:
      - "rtr" prints the Runtime Repository
      - "psr" prints the Persistent Repository
      - "oldb" prints the OLDB URI to the RTC application

    \b
      for any other component names:
      - "rr" prints the Request-Reply URI
      - "ps" prints the Publish Subscribe URI
      - "oldb" prints the OLDB URI prefix to the RTC component

    \b
    Returns:
      0 when successfully executed.
      2 when arguments or options are not correct.
      11 when service is not recognized.
      12 when errors are returned when accessing "services" component.
      13 when errors are returned when accessing the values for an RTC component.
    """

    # Note: the \b tag in the above docstring makes the word that follows it bold in the Doxygen
    # output. It should not be added before "Returns", which causes a warning in Doxygen. The
    # "Returns" will already be bold.

    # Get the default log level.
    log_level = CommonConfigurationParameters().log_level

    setup_cpp_logging("rtctkServiceDiscovery", getattr(CiiLogManager.logging, str(log_level)), True)
    sd = ServiceDiscovery(Uri(service_discovery_endpoint))
    if component == "services":
        if service == "rtr":
            try:
                print(sd.get_runtime_repo_endpoint().string())
            except Exception as e:
                print(e)
                sys.exit(12)
        elif service == "psr":
            try:
                print(sd.get_persistent_repo_endpoint().string())
            except Exception as e:
                print(e)
                sys.exit(12)
        elif service == "oldb":
            try:
                print(sd.get_oldb_endpoint().string())
            except Exception as e:
                print(e)
                sys.exit(12)
        else:
            print("Service '{}' not recognized".format(service))
            sys.exit(1)
    else:
        if service == "rr":
            try:
                print(sd.get_req_rep_endpoint(component, service_type, True).string())
            except Exception as e:
                print(e)
                sys.exit(13)
        elif service == "ps":
            try:
                print(sd.get_pub_sub_endpoint(component).string())
            except Exception as e:
                print(e)
                sys.exit(13)
        elif service == "oldb":
            try:
                oldb = sd.get_oldb_endpoint().string()
                ret = ""
                if oldb[-1] == "/":
                    ret = oldb + component
                else:
                    ret = oldb + "/" + component
                print(ret)
            except Exception as e:
                print(e)
                sys.exit(13)
        else:
            print("Service '{}' not recognized.".format(service))
            sys.exit(11)
    sys.exit(0)


## @endcond

if __name__ == "__main__":
    sdc()  # pylint: disable=E1120
