import logging
from typing import Union, Callable
import os
import signal
import sys

from osclib import Address
from patcher.patcher import Patcher
from patcher.bases import EventHandler
from nsm_client import NsmServer

from .check_internal import IS_INTERNAL
from .engine import Engine


if IS_INTERNAL:
    _logger = logging.getLogger(__name__)
else:
    _logger = logging.getLogger()
    _log_handler = logging.StreamHandler()
    _log_handler.setFormatter(logging.Formatter(
        f"%(levelname)s:%(name)s - %(message)s"))
    _logger.addHandler(_log_handler)


def internal_prepare(
        *func_args: str, nsm_url='') -> \
            int | tuple[Callable, Callable, bool, None]:
    '''Prepare the client, return an integer in case of error,
    otherwise the start_func and the stop_func.'''
    # set log level with exec arguments
    if len(func_args) > 0:
        log_dict = {logging.INFO: '', logging.DEBUG: ''}
        read_level = 0

        for func_arg in func_args:
            match func_args:
                case '-log'|'--log':
                    read_level = logging.INFO
                    continue
                case '-dbg'|'--dbg':
                    read_level = logging.DEBUG
                    continue
            
            if read_level == 0:
                continue
            
            log_dict[read_level] = func_arg

        for lvl, modules in log_dict.items():
            for module in modules.split(':'):
                if module:
                    mod_logger = logging.getLogger(module)
                    mod_logger.setLevel(lvl)

    if not nsm_url:
        _logger.error('Could not register as NSM client.')
        return 1

    try:
        daemon_address = Address(nsm_url)
    except:
        _logger.error('NSM_URL seems to be invalid.')
        return 1

    event_handler = EventHandler()
    engine = Engine(event_handler)

    if not engine.init():
        return 2

    nsm_server = NsmServer(
        daemon_address, total_fake=IS_INTERNAL)
    patcher = Patcher(engine, nsm_server, _logger)
    return patcher.run_loop, patcher.stop, True, None

def run():
    ret = internal_prepare(*sys.argv[1:], nsm_url=os.getenv('NSM_URL', ''))
    if isinstance(ret, int):
        sys.exit(ret)

    start_func, stop_func, stop_with_jack, none = ret

    signal.signal(signal.SIGINT, stop_func)
    signal.signal(signal.SIGTERM, stop_func)

    start_func(stop_with_jack=True)

