import os
import platform
import sys
import time

from conf.config import BotConfig
from core.aochat.mmdb_parser import MMDBParser
from core.bot_status import BotStatus
from core.db import DB
from core.dict_object import DictObject
from core.functions import merge_dicts
from core.logger import Logger
from core.registry import Registry
from core.upgrade import run_upgrades

import faulthandler
faulthandler.enable()

def get_config_from_env():
    config_obj = DictObject()
    for k, v in os.environ.items():
        if k.startswith("IGNCORE_"):
            keys = k[7:].lower().split("_")
            temp_config = config_obj
            for key in keys[:-1]:
                key = key.replace("-", "_")
                # create key if it doesn't already exist
                if key not in temp_config:
                    temp_config[key] = DictObject()
                temp_config = temp_config.get(key)
            logger.debug(f"overriding config value from env var '{k}'")
            if v.lower() == "true":
                v = True
            elif v.lower() == "false":
                v = False
            temp_config[keys[-1].replace("-", "_")] = v
    return config_obj


try:
    # load logging configuration
    import conf.logging_settings
    Registry.logger = Logger("core.registry")
    bot = "config"
    if len(sys.argv) > 1:
        bot = f"{sys.argv[1]}"
    else:
        print("Unknown bot specified. Please edit your ##botname##.start.sh accordingly to the instructions found in the README.")
        exit(0)
    logger = Logger("core.bootstrap")
    logger.info("Starting Bot...")
    mod = __import__(f'conf.{bot}', fromlist=['BotConfig'])
    config: BotConfig = getattr(mod, 'BotConfig')
    if sys.version_info < (3, 9):
        logger.warning("Versions lower then Python3.9 are not supported.")
        exit(-1)

    # load config values from env vars
    env_config = get_config_from_env()
    if env_config:
        # converts dicts to lists
        if "slaves" in env_config and isinstance(env_config.slaves, dict):
            env_config.slaves = list(env_config.slaves.values())

        if "module_paths" in env_config and isinstance(env_config.module_paths, dict):
            env_config.module_paths = list(env_config.module_paths.values())

        config = merge_dicts(config, env_config)
        logger.info("Reading config from env vars")
    else:
        pass
    # ensure dimension is integer
    if isinstance(config.server.dimension, str):
        config.server.dimension = int(config.server.dimension)

    if platform.system() == "Windows":
        os.system(f"title {config.character}.{config.server.dimension:d}")

    # paths to search for instances: core + module_paths
    paths = ["core"]
    paths.extend(config.module_paths)
    # load instances
    logger.debug("Loading instances")
    Registry.load_instances(paths)
    Registry.inject_all(paths)

    # configure database
    db = Registry.get_instance("db")
    if config.database.type == "mariadb":
        if config.database.port in [0, ""]:
            config.database.port = 3306
        db.connect_mariadb(config.database.host, config.database.port, config.database.username,
                           config.database.password,
                           config.database.name)
        if hasattr(config, "shared_db"):
            if config.shared_db.port in [0, ""]:
                config.shared_db.port = 3306
            db.shared = DB()
            db.shared.connect_mariadb(config.shared_db.host, config.shared_db.port, config.shared_db.username,
                                      config.shared_db.password, config.shared_db.name)
        else:
            db.shared = db
    else:
        raise Exception(f"Unknown database type '{config.database.type}'")

    # run db upgrade scripts
    run_upgrades()

    # finish initializing bot and modules, and then connect
    bot = Registry.get_instance("bot")
    bot.init(config, Registry, MMDBParser("text.mdb"))

    if not bot.connect(config):
        bot.disconnect()
        time.sleep(5)
        exit(3)
    else:
        status = bot.run()
        bot.disconnect()
        exit(status.value)

except KeyboardInterrupt:
    # noinspection PyUnboundLocalVariable
    if bot:
        # noinspection PyUnboundLocalVariable
        bot.status = BotStatus.SHUTDOWN
    # exit(0)
except Exception as e:
    logger = Logger("bootstrap")
    logger.error("", e)
    exit(4)
