# Copyright 2021 The Pigweed Authors
#
# 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
#
#     https://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.
"""Pigweed Console entry point."""

import argparse
import inspect
import logging
from pathlib import Path
import sys
from typing import Optional, Dict

import pw_cli.log
import pw_cli.argument_types

import pw_console
import pw_console.python_logging
import pw_console.test_mode
from pw_console.log_store import LogStore
from pw_console.plugins.calc_pane import CalcPane
from pw_console.plugins.clock_pane import ClockPane
from pw_console.plugins.twenty48_pane import Twenty48Pane

_LOG = logging.getLogger(__package__)
_ROOT_LOG = logging.getLogger('')


# TODO(tonymd): Remove this when no downstream projects are using it.
def create_temp_log_file():
    return pw_console.python_logging.create_temp_log_file()


def _build_argument_parser() -> argparse.ArgumentParser:
    """Setup argparse."""
    parser = argparse.ArgumentParser(prog="python -m pw_console",
                                     description=__doc__)

    parser.add_argument('-l',
                        '--loglevel',
                        type=pw_cli.argument_types.log_level,
                        default=logging.DEBUG,
                        help='Set the log level'
                        '(debug, info, warning, error, critical)')

    parser.add_argument('--logfile', help='Pigweed Console log file.')

    parser.add_argument('--test-mode',
                        action='store_true',
                        help='Enable fake log messages for testing purposes.')
    parser.add_argument('--config-file',
                        type=Path,
                        help='Path to a pw_console yaml config file.')
    parser.add_argument('--console-debug-log-file',
                        help='Log file to send console debug messages to.')

    return parser


def main() -> int:
    """Pigweed Console."""

    parser = _build_argument_parser()
    args = parser.parse_args()

    if not args.logfile:
        # Create a temp logfile to prevent logs from appearing over stdout. This
        # would corrupt the prompt toolkit UI.
        args.logfile = pw_console.python_logging.create_temp_log_file()

    pw_cli.log.install(level=args.loglevel,
                       use_color=True,
                       hide_timestamp=False,
                       log_file=args.logfile)

    if args.console_debug_log_file:
        pw_cli.log.install(level=logging.DEBUG,
                           use_color=True,
                           hide_timestamp=False,
                           log_file=args.console_debug_log_file,
                           logger=logging.getLogger('pw_console'))

    global_vars = None
    default_loggers = {}
    if args.test_mode:
        root_log_store = LogStore()
        _ROOT_LOG.addHandler(root_log_store)
        _ROOT_LOG.debug('pw_console test-mode starting...')

        fake_logger = logging.getLogger(
            pw_console.test_mode.FAKE_DEVICE_LOGGER_NAME)
        default_loggers = {
            # Don't include pw_console package logs (_LOG) in the log pane UI.
            # Add the fake logger for test_mode.
            'Fake Device': [fake_logger],
            'PwConsole Debug': [logging.getLogger('pw_console')],
            'All Logs': root_log_store,
        }
        # Give access to adding log messages from the repl via: `LOG.warning()`
        global_vars = dict(LOG=fake_logger)

    help_text = None
    app_title = None
    if args.test_mode:
        app_title = 'Console Test Mode'
        help_text = inspect.cleandoc("""
            Welcome to the Pigweed Console Test Mode!

            Example commands:

              rpcs.pw.rpc.EchoService.Echo(msg='hello!')

              LOG.warning('Message appears console log window.')
        """)

    console = pw_console.PwConsoleEmbed(
        global_vars=global_vars,
        loggers=default_loggers,
        test_mode=args.test_mode,
        help_text=help_text,
        app_title=app_title,
        config_file_path=args.config_file,
    )

    overriden_window_config: Optional[Dict] = None
    # Add example plugins and log panes used to validate behavior in the Pigweed
    # Console manual test procedure: https://pigweed.dev/pw_console/testing.html
    if args.test_mode:
        fake_logger.propagate = False
        console.setup_python_logging(loggers_with_no_propagation=[fake_logger])

        _ROOT_LOG.debug('pw_console.PwConsoleEmbed init complete')
        _ROOT_LOG.debug('Adding plugins...')
        console.add_window_plugin(ClockPane())
        console.add_window_plugin(CalcPane())
        console.add_floating_window_plugin(
            Twenty48Pane(include_resize_handle=False), left=4)
        _ROOT_LOG.debug('Starting prompt_toolkit full-screen application...')

        overriden_window_config = {
            'Split 1 stacked': {
                'Fake Device': None,
                'Fake Keys': {
                    'duplicate_of': 'Fake Device',
                    'filters': {
                        'keys': {
                            'regex': '[^ ]+'
                        },
                    },
                },
                'Fake USB': {
                    'duplicate_of': 'Fake Device',
                    'filters': {
                        'module': {
                            'regex': 'USB'
                        },
                    },
                },
            },
            'Split 2 tabbed': {
                'Python Repl': None,
                'All Logs': None,
                'PwConsole Debug': None,
                'Calculator': None,
                'Clock': None,
            },
        }

    console.embed(override_window_config=overriden_window_config)

    if args.logfile:
        print(f'Logs saved to: {args.logfile}')

    return 0


if __name__ == '__main__':
    sys.exit(main())
