# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Module for LocalAgentProcess."""
import argparse
from concurrent import futures
import configparser
import enum
import importlib
import json
import os
import shutil
import signal
import sys
import threading
import time
import traceback
from typing import Any, Dict, List, Optional, Tuple

import gazoo_device

from local_agent import errors
from local_agent import ams_client
from local_agent import suite_session_manager
from local_agent import version
from local_agent import logger as logger_module
from local_agent.translation_layer import translation_layer


logger = logger_module.get_logger()

# ========================= Constants / Configs ========================= #
VERSION_FLAGS = {"-v", "-version", "--version"}
APP_ENGINE_DATA_SIZE_LIMIT = 31 * 1048576  # 31 MB
APP_ENGINE_DATA_SIZE_LIMIT_HUMAN_READABLE = '31 MB'
DEFAULT_ARTIFACTS_DIR = '/tmp/local_agent_artifacts'
AUTH_FILE = os.path.expanduser('~/.config/google/matter_local_agent_auth.json')
DEFAULT_USER_CONFIG = os.path.expanduser(
    '~/.config/google/local_agent_config.ini')
_START_TEST_SUITE_METHOD = 'startTestSuite'
_END_TEST_SUITE_METHOD = 'endTestSuite'
_COMMISSION_TO_GOOGLE_FABRIC_METHOD = 'commissionToGoogleFabric'
_USER_CONFIG_ROOT_KEY = 'ServerConfig'
_USER_CONFIG_AMS_HOST = 'AMS_HOST'
_USER_CONFIG_AMS_PORT = 'AMS_PORT'
_USER_CONFIG_AMS_SCHEME = 'AMS_SCHEME'
_USER_CONFIG_ARTIFACTS_DIR = 'ARTIFACTS_DIR'
_USER_CONFIG_MATTER_DEVICE_CONTROLLERS = 'MatterDeviceControllerPackages'
_EAP_AMS_HOST = 'matter-test-suite-eap.withgoogle.com'
_EAP_AMS_PORT = None
_EAP_AMS_SCHEME = 'https'
# ======================================================================= #


class RpcRequestType(enum.Enum):
    """RPC request type enum."""
    START_TEST_SUITE = enum.auto()
    END_TEST_SUITE = enum.auto()
    DEVICE_QUERY_CONTROL = enum.auto()
    COMMISSION_TO_GOOGLE_FABRIC = enum.auto()


# ======================== Module level functions ========================== #
def rpc_request_type(method: str) -> RpcRequestType:
    """RPC request type selector.

    Args:
        method: JSON-RPC request method.

    Returns:
        Request type.
    """
    if method == _START_TEST_SUITE_METHOD:
        return RpcRequestType.START_TEST_SUITE
    elif method == _END_TEST_SUITE_METHOD:
        return RpcRequestType.END_TEST_SUITE
    elif method == _COMMISSION_TO_GOOGLE_FABRIC_METHOD:
        return RpcRequestType.COMMISSION_TO_GOOGLE_FABRIC
    else:
        return RpcRequestType.DEVICE_QUERY_CONTROL
# ========================================================================== #


class LocalAgentProcess:
    """Local Agent Process.

    A continuously running process which constantly sends GET
    requests to the Agent Management Service for incoming RPC
    requests.
    """

    _REPORT_INFO_INTERVAL_SECONDS = 30
    _REPORT_INFO_THREAD_TERMINATION_WAIT_SECONDS = 10
    _POLL_RPC_COOL_DOWN_SECONDS = 1
    _POLL_RPC_THREAD_TERMINATION_WAIT_SECONDS = 10
    _MAIN_THREAD_KEEP_ALIVE_COOLDOWN_SECONDS = 1

    _MAX_WORKERS_FOR_RPC_EXECUTION_THREAD_POOL = 5

    # Status for local agent, defined in the AMS.
    # Note that we don't need 'OFFLINE' status because that is determined by
    # the AMS.
    _STATUS_RUNNING = 'RUNNING'
    _STATUS_IDLE = 'IDLE'

    def __init__(self, client: ams_client.AmsClient, artifacts_dir: str):
        """Initializes local agent.

        Args:
            client: The AmsClient instance.
            artifacts_dir: Artifacts directory.
        """
        self._ams_client = client
        self._artifacts_dir = artifacts_dir

        # Threads
        self._termination_event = threading.Event()
        self._rpc_polling_thread = None
        self._info_reporting_thread = None
        self._rpc_execution_thread_pool = futures.ThreadPoolExecutor(
            max_workers=self._MAX_WORKERS_FOR_RPC_EXECUTION_THREAD_POOL)

        # Store IDs of running Futures.
        self._rpc_execution_future_ids = set()

        # Translation Layer
        self._translator = translation_layer.TranslationLayer(client)

        # Suite session manager
        self._suite_mgr = suite_session_manager.SuiteSessionManager(
            artifacts_fn=self._compress_artifacts_and_upload,
            artifact_root_dir=artifacts_dir,
            create_devices_fn=self._translator.create_devices,
            close_devices_fn=self._translator.close_devices)

    def run(self) -> None:
        """Runs the local agent, starting polling JSON-RPC and reporting info.

        We start two threads, one of polling JSON-RPC from AMS and the other
        for reporting info to AMS.
        """
        if not self._setup_credentials():
            logger.warning('Local Agent linking failed, exit the process.')
            return
        logger.info('Local Agent is linked successfully.')

        # Register termination signal handler
        signal.signal(signal.SIGINT, self._terminate)

        self._translator.start(termination_event=self._termination_event)
        self._suite_mgr.start(termination_event=self._termination_event)
        self._start_info_reporting_thread()
        self._start_rpc_polling_thread()
        while not self._termination_event.is_set():
            # If any top level thread is dead, terminate the local agent.
            if self._terminate_if_thread_not_running(
                self._info_reporting_thread):
                break
            if self._terminate_if_thread_not_running(
                self._rpc_polling_thread):
                break

            time.sleep(self._MAIN_THREAD_KEEP_ALIVE_COOLDOWN_SECONDS)

    def _terminate_if_thread_not_running(
        self, target_thread: Optional[threading.Thread]) -> bool:
        """Terminates local agent if the target thread is not running.

        Args:
            target_thread: The thread to check running.

        Returns:
            True if termination procedure initiated, i.e., the thread is not
            running.
        """
        if target_thread is None or not target_thread.is_alive():
            logger.error('Thread is dead or not even started.')
            self._terminate(None, None)
            return True
        return False

    def _start_info_reporting_thread(self) -> None:
        """Starts the _report_info job in a thread."""
        if self._info_reporting_thread is None:
            self._info_reporting_thread = threading.Thread(
                target=self._report_info, name='Info-reporting-thread')
        if not self._info_reporting_thread.is_alive():
            self._info_reporting_thread.start()

    def _start_rpc_polling_thread(self) -> None:
        """Starts the _poll_rpc job in a thread."""
        if self._rpc_polling_thread is None:
            self._rpc_polling_thread = threading.Thread(
                target=self._poll_rpc, name='RPC-polling-thread')
        if not self._rpc_polling_thread.is_alive():
            self._rpc_polling_thread.start()

    def _start_rpc_execution_thread(self, rpc_request: Dict[str, Any]) -> None:
        """Submits a _execute_rpc job to RPC execution thread pool."""
        future = self._rpc_execution_thread_pool.submit(self._execute_rpc,
                                                        rpc_request)
        self._rpc_execution_future_ids.add(id(future))
        future.add_done_callback(self._callback_for_rpc_execution_complete)

    def _report_info(self) -> None:
        """Reports local agent information back to AMS periodically.

        Note that this method contains an infinite loop, and is designed to be
        run in a separate thread, instead of the main thread.
        Typically we should not invoke this method directly, and instead we
        use _start_info_reporting_thread method.

        The information being reported includes:
        - The devices connected to this local agent.
        - The version of this local agent.
        - GDM version in use.
        - The status of this local agent.
        """
        while True:
            logger.info('Reporting status to AMS.')

            devices = self._translator.detect_devices()
            status = (self._STATUS_RUNNING if self._rpc_execution_future_ids
                      else self._STATUS_IDLE)
            local_agent_info = {
                'devices': devices,
                'gdmVersion': gazoo_device.__version__,
                'status': status,
                'version': version.__version__,
            }
            try:
                self._ams_client.report_info(local_agent_info)
            except errors.ApiTimeoutError:
                logger.warning('Report info API timed out.')
            except errors.ApiError as e:
                logger.warning('Report status failed. %s', e)
            except errors.UnlinkedError:
                logger.warning('The local agent is unlinked.')
                self._clean_up_and_terminate_agent(remove_auth_file=True)
                break

            if self._termination_event.wait(self._REPORT_INFO_INTERVAL_SECONDS):
                break

        logger.info('Stopped reporting info because stop event is set.')

    def _poll_rpc(self) -> None:
        """Polls AMS for JSON-RPC requests.

        Note that this method contains an infinite loop, and is designed to be
        run in a separate thread, instead of the main thread.
        """
        while not self._termination_event.is_set():
            logger.info('Polling JSON-RPC requests from AMS.')

            try:
                rpc_request = self._ams_client.get_rpc_request_from_ams()
            except errors.ApiTimeoutError:
                logger.warning('Get RPC request API timed out.')
                rpc_request = None
            except errors.ApiError as e:
                logger.warning(f'Failed to get RPC request from AMS: {e}')
                rpc_request = None
            except errors.UnlinkedError:
                logger.warning('The local agent is unlinked.')
                self._clean_up_and_terminate_agent(remove_auth_file=True)
                break

            if rpc_request is not None:
                try:
                    self._ams_client.remove_rpc_request_from_ams(rpc_request)
                except (errors.ApiTimeoutError, errors.ApiError):
                    logger.exception(
                        'Failed to remove JSON-RPC request from AMS.'
                        'Terminating the local agent process.')
                    self._clean_up_and_terminate_agent()
                    break
                self._start_rpc_execution_thread(rpc_request)

            time.sleep(self._POLL_RPC_COOL_DOWN_SECONDS)
        logger.info('Stopped polling RPC because stop event is set.')

    def _execute_rpc(self, rpc_request: Dict[str, Any]) -> None:
        """Executes the JSON-RPC request, and sends result back to AMS."""
        rpc_id = rpc_request.get('id')
        logger.info(f'Executing JSON-RPC: {rpc_id}')

        rpc_response = self._handle_rpc_request(rpc_request)

        if self._translator.is_rpc_timeout(rpc_id):
            logger.warning(f'RPC {rpc_id} has timed out, ignoring response.')
        else:
            try:
                self._ams_client.send_rpc_response(rpc_response)
            except (errors.ApiTimeoutError, errors.ApiError):
                logger.exception('Failed to send JSON-RPC response to AMS.')

    def _handle_rpc_request(
        self, rpc_request: Dict[str, Any]) -> Dict[str, Any]:
        """Handles the JSON-RPC request and returns the response.

        Args:
            rpc_request: JSON-RPC request.

        Returns:
            JSON-RPC response.
        """
        req_type = rpc_request_type(rpc_request['method'])

        try:
            if req_type == RpcRequestType.START_TEST_SUITE:
                resp = self._suite_mgr.start_test_suite(rpc_request)

            elif req_type == RpcRequestType.END_TEST_SUITE:
                resp = self._suite_mgr.end_test_suite(rpc_request)

            elif req_type == RpcRequestType.DEVICE_QUERY_CONTROL:
                resp = self._translator.dispatch_to_cmd_handler(rpc_request)

            elif req_type == RpcRequestType.COMMISSION_TO_GOOGLE_FABRIC:
                resp = self._translator.commission_to_google_fabric(rpc_request)

            else:
                raise errors.InvalidRPCError(
                    f'Invalid RPC request type {req_type}.')

        except Exception as e:
            logger.exception('Error when handling JSON-RPC.')
            err_resp = {'id': rpc_request['id'], 'jsonrpc': '2.0'}
            err_code = getattr(e, 'err_code', errors.DEFAULT_ERROR_CODE)
            stack_trace = traceback.format_exc()
            err_msg = stack_trace if err_code == errors.DEFAULT_ERROR_CODE else str(e)
            err_resp['error'] = {'code': err_code, 'message': err_msg}
            return err_resp

        return resp

    def _callback_for_rpc_execution_complete(self,
                                             future: futures.Future) -> None:
        """Callback function when an RPC execution is complete.

        What this callback does:
        1) We remove the id(future) from the self._rpc_execution_future_ids.
        2) We log the exception if there is one.

        This callback should be registered to an RPC execution future object
        using Future.add_done_callback() instead of being called directly.

        Args:
            future: The Future object when we submit an RPC execution job to
              the ThreadPoolExecutor.
        """
        future_id = id(future)
        self._rpc_execution_future_ids.remove(future_id)
        exc = future.exception()
        if exc is not None:
            logger.error('RPC execution encounters exception: %s', exc)

    def _terminate(self, sig_num, frame) -> None:
        """Termination procedure for local agent. A signal handler.

        We set the termination event and stop the 2 top-level threads:
        info-reporting and rpc-polling. Also shutdown the ThreadPoolExecutor
        for RPC execution.

        Args:
          sig_num: Signal number passed to a signal handler. See:
            https://docs.python.org/3/library/signal.html#signal.signal
          frame: Current stack frame passed to a signal hanlder. See:
            https://docs.python.org/3/library/signal.html#signal.signal
        """
        del sig_num, frame  # Unused.

        logger.warning('Terminating local agent process.')

        self._clean_up_and_terminate_agent()

        thread_and_wait_time = (
            (self._rpc_polling_thread,
             self._POLL_RPC_THREAD_TERMINATION_WAIT_SECONDS),
            (self._info_reporting_thread,
             self._REPORT_INFO_THREAD_TERMINATION_WAIT_SECONDS))

        for thread, wait_time in thread_and_wait_time:
            if thread is None:
                # The thread wasn't even created. Skipping.
                continue
            logger.info(f'Waiting for thead {thread.name} to stop. '
                        f'(Timeout = {wait_time} seconds)')
            thread.join(timeout=wait_time)
            if thread.is_alive():
                logger.error('Thread %s still alive after waiting %s seconds.',
                             thread.name, wait_time)

        self._rpc_execution_thread_pool.shutdown(wait=False)

        logger.warning('Local agent process terminated.')

    def _read_auths(self) -> Tuple[str, str]:
        """Read agent auths from local config.

        Reads the stored agent_id and agent_secret locally.

        Returns:
            Tuple of agent_id and agent_secret.
        """
        with open(AUTH_FILE, 'r') as fstream:
            auths = json.load(fstream)
        return auths['agent_id'], auths['agent_secret']

    def _write_auths(self, agent_id: str, agent_secret: str) -> None:
        """Writes agent auths into local config.

        Stores the agent_id and agent_secret into the credential auth file
        locally.

        Args:
            agent_id: local agent id.
            agent_secret: local agent secret.
        """
        with open(AUTH_FILE, 'w') as fstream:
            auths = {'agent_id': agent_id, 'agent_secret': agent_secret}
            json.dump(auths, fstream)

    def _setup_credentials(self) -> bool:
        """Sets up credentials.

        Read credentials from a local auth file. If credentials not available
        or expired, start the register process.

        Returns:
            True if credentials are set up successfully. False otherwise.
        """
        credentials_set_up = False
        try:
            agent_id, agent_secret = self._read_auths()
            self._ams_client.set_local_agent_credentials(
                local_agent_id=agent_id,
                local_agent_secret=agent_secret)
            credentials_set_up = True
        except (
            FileNotFoundError, errors.CredentialsError, errors.UnlinkedError):
            logger.info('Start the linking process')
            while True:
                try:
                    linking_code = input('Linking Code:')
                    agent_id, agent_secret = self._ams_client.register(
                        linking_code=linking_code)
                    self._write_auths(agent_id, agent_secret)
                    credentials_set_up = True
                    break
                except errors.CredentialsError as e:
                    # We don't use logger.exception here in order not to
                    # overwhelm the user interface.
                    logger.warning(
                        'Invalid linking code. Please retry. (%s)', e)
                except errors.ApiTimeoutError as e:
                    logger.warning(
                        'Register API timed out. Please retry. (%s)', e)
                except errors.ApiError as e:
                    logger.warning(
                        'Agent registration failed. Please retry. (%s)', e)
                except KeyboardInterrupt:
                    break
        return credentials_set_up

    def _compress_artifacts_and_upload(
        self,
        test_suite_id: str,
        test_result_id: Optional[str] = None) -> None:
        """Compresses the artifacts and uploads if needed.

        Compresses the artifact directory, and uploads the artifacts
        to AMS if the test result ID is provided.

        Args:
            test_suite_id: Test suite ID.
            test_result_id: Test result ID.

        Raises:
            RuntimeError: Uploading fails.
        """
        logger.info(f'Compressing artifacts for {test_suite_id}')

        test_suite_dir = os.path.join(self._artifacts_dir, test_suite_id)

        # remove logging handler
        local_agent_log = os.path.join(
            self._artifacts_dir, test_suite_id, 'local_agent.log')
        logger_module.remove_file_handler(local_agent_log)

        # compress the artifacts directory and remove it after the compression
        shutil.make_archive(test_suite_dir, 'gztar', test_suite_dir)
        shutil.rmtree(test_suite_dir)

        if test_result_id is not None:
            logger.info(f'Uploading artifacts for {test_suite_id}')

            # check against file size limit.
            artifacts_name = test_suite_dir + '.tar.gz'
            if os.stat(artifacts_name).st_size >= APP_ENGINE_DATA_SIZE_LIMIT:
                raise RuntimeError(
                    f'The file size of {artifacts_name} is larger than '
                    f'{APP_ENGINE_DATA_SIZE_LIMIT_HUMAN_READABLE}.')

            # upload the artifact
            try:
                self._ams_client.upload_artifact(artifacts_name,
                                                 test_result_id=test_result_id)
            except (errors.ApiTimeoutError, errors.ApiError):
                logger.exception('Failed to upload artifact.')

    def _clean_up_and_terminate_agent(
        self, remove_auth_file: bool = False) -> None:
        """Cleanup method for local agent.

        Cleans up suite session and sets the terminate event.
        Removes the auth file if remove_auth_file is true.

        Args:
            remove_auth_file: To remove the auth file or not.
        """
        if remove_auth_file:
            if os.path.exists(AUTH_FILE):
                os.remove(AUTH_FILE)
        self._suite_mgr.clean_up()
        self._termination_event.set()


def read_config() -> Tuple[Dict[str, Any], List[Tuple[str, str]]]:
    """Reads user data from configuration file.

    The config file should be in YAML format. User can specify the path to
    their config file using command line argument. If not provided, we use the
    default path, DEFAULT_USER_CONFIG.

    The configuration file is not required. An empty dict is returned when
    there's no such config file.

    Raises:
        RuntimeError: If unable to parse the config file as YAML.

    Returns:
        User configuration data for AMS and extension Matter device controllers.
    """
    parser = argparse.ArgumentParser()
    parser.add_argument('-u', '--user_config', type=str, required=False,
                        default=DEFAULT_USER_CONFIG,
                        help='Local Agent user config file.')
    args, leftover = parser.parse_known_args(sys.argv[1:])
    sys.argv[1:] = leftover

    if not os.path.exists(args.user_config):
        return {}, {}

    config = configparser.ConfigParser(allow_no_value=True)
    config.read(args.user_config)

    if _USER_CONFIG_ROOT_KEY not in config:
        raise ValueError(
            f'Invalid config file, no section {_USER_CONFIG_ROOT_KEY}.'
            'Please refer to example_config.ini for reference.')

    matter_controllers_config = (
        config.items(_USER_CONFIG_MATTER_DEVICE_CONTROLLERS)
        if _USER_CONFIG_MATTER_DEVICE_CONTROLLERS in config else [])


    return config[_USER_CONFIG_ROOT_KEY], matter_controllers_config


def register_extension_controllers(
    matter_controllers_config: List[Tuple[str, str]]) -> None:
    """Registers partner extension Matter device controllers in GDM.

    Args:
        matter_controllers_config: List of controllers to be registered.
    """
    for controller_package_name, _ in matter_controllers_config:
        controller = importlib.import_module(controller_package_name)
        gazoo_device.register(controller)


def exit_if_query_module_versions() -> None:
    """Exits the process if querying the Local Agent and GDM versions."""
    if VERSION_FLAGS & set(sys.argv):
        la_version = f'\n******* Local Agent version {version.__version__} *******'
        gdm_version = f'\n******* GDM version {gazoo_device.__version__} *******'
        logger.info(la_version + gdm_version)
        sys.exit(0)


def main() -> None:
    """Main entry of Local Agent."""
    exit_if_query_module_versions()

    user_config, matter_controllers_config = read_config()

    ams_host = user_config.get(_USER_CONFIG_AMS_HOST, _EAP_AMS_HOST)
    ams_port = user_config.get(_USER_CONFIG_AMS_PORT, _EAP_AMS_PORT)
    ams_scheme = user_config.get(_USER_CONFIG_AMS_SCHEME, _EAP_AMS_SCHEME)
    artifacts_dir = (
        user_config.get(_USER_CONFIG_ARTIFACTS_DIR, DEFAULT_ARTIFACTS_DIR))

    register_extension_controllers(matter_controllers_config)

    client = ams_client.AmsClient(host=ams_host,
                                  port=ams_port,
                                  scheme=ams_scheme)
    proc = LocalAgentProcess(client=client, artifacts_dir=artifacts_dir)
    proc.run()
