import socket
import sys
import aiohttp
import os
from aiohttp import ClientSession
from injector import Module, provider, singleton, multiprovider
from typing import List

from backup.config import Config, Startable, Setting
from backup.drive import DriveSource
from backup.ha import HaSource, HaUpdater, AddonStopper
from backup.model import BackupDestination, BackupSource, Scyncer
from backup.util import Resolver
from backup.model import Coordinator, Precache, DestinationPrecache
from backup.worker import Trigger
from backup.watcher import Watcher
from backup.ui import UiServer, Restarter
from backup.logger import getLogger
from backup.debug import DebugServer
from .debugworker import DebugWorker
from .tracing_session import TracingSession
logger = getLogger(__name__)


class BaseModule(Module):
    '''
    A module shared between tests and main
    '''
    def __init__(self, override_dns=True):
        self._override_dns = override_dns

    @multiprovider
    @singleton
    def getTriggers(self, coord: Coordinator, ha: HaSource, drive: DriveSource, watcher: Watcher, server: UiServer) -> List[Trigger]:
        return [coord, ha, drive, watcher, server]

    @provider
    @singleton
    def getDrive(self, drive: DriveSource) -> BackupDestination:
        return drive

    @provider
    @singleton
    def getHa(self, ha: HaSource) -> BackupSource:
        return ha

    @provider
    @singleton
    def getPrecache(self, cache: DestinationPrecache) -> Precache:
        return cache

    @multiprovider
    @singleton
    def getStartables(self, debug_server: DebugServer, ha_updater: HaUpdater, debugger: DebugWorker, ha_source: HaSource,
                      server: UiServer, restarter: Restarter, syncer: Scyncer, watcher: Watcher, stopper: AddonStopper, precache: Precache) -> List[Startable]:
        # Order here matters, since its the order in which components of the addon are initialized.
        return [debug_server, ha_updater, debugger, ha_source, server, restarter, syncer, watcher, stopper, precache]

    @provider
    @singleton
    def getSession(self, resolver: Resolver, config: Config) -> ClientSession:
        conn = None
        if self._override_dns:
            conn = aiohttp.TCPConnector(resolver=resolver, family=socket.AF_INET)
        return TracingSession(config, connector=conn)


class MainModule(Module):
    @provider
    @singleton
    def getConfig(self) -> Config:
        alt_config = None
        index = 1
        for arg in sys.argv[1:]:
            if arg == "--config":
                alt_config = sys.argv[index + 1]
                break
            index += 1

        if alt_config:
            config = Config.withFileOverrides(alt_config)
        elif "PYTEST_CURRENT_TEST" in os.environ:
            config = Config()
        else:
            config = Config.fromFile(Setting.CONFIG_FILE_PATH.default())
        logger.overrideLevel(config.get(Setting.CONSOLE_LOG_LEVEL), config.get(Setting.LOG_LEVEL))
        return config
