from __future__ import annotations
import subprocess as sps
import webbrowser as wbr
from typing import Union, List, Dict, Iterable, Optional
from types import ModuleType

from vit3l.types import OptionsDictT
import vit3l.chrome as chm
import vit3l.electron as ele
import vit3l.edge as edge
import vit3l.msIE as ie
#import vit3l.firefox as ffx      TODO
#import vit3l.safari as saf       TODO

_browser_paths: Dict[str, str] = {}
_browser_modules: Dict[str, ModuleType] = {'chrome':   chm,
                                           'electron': ele,
                                           'edge': edge,
                                           'msie':ie}


def _build_url_from_dict(page: Dict[str, str], options: OptionsDictT) -> str:
    scheme = page.get('scheme', 'http')
    host = page.get('host', 'localhost')
    port = page.get('port', options["port"])
    path = page.get('path', '')
    if not isinstance(port, (int, str)):
        raise TypeError("'port' option must be an integer")
    return '%s://%s:%d/%s' % (scheme, host, int(port), path)


def _build_url_from_string(page: str, options: OptionsDictT) -> str:
    if not isinstance(options['port'], (int, str)):
        raise TypeError("'port' option must be an integer")
    base_url = 'http://%s:%d/' % (options['host'], int(options['port']))
    return base_url + page


def _build_urls(start_pages: Iterable[Union[str, Dict[str, str]]], options: OptionsDictT) -> List[str]:
    urls: List[str] = []

    for page in start_pages:
        if isinstance(page, dict):
            url = _build_url_from_dict(page, options)
        else:
            # Check if it's already a full URL (external URL mode)
            if page.startswith(('http://', 'https://')):
                url = page
            else:
                url = _build_url_from_string(page, options)
        urls.append(url)

    return urls


def open(start_pages: Iterable[Union[str, Dict[str, str]]], options: OptionsDictT) -> None:
    # Build full URLs for starting pages (including host and port)
    start_urls = _build_urls(start_pages, options)
    
    mode = options.get('mode')
    if not isinstance(mode, (str, type(None))) and mode is not False:
        raise TypeError("'mode' option must by either a string, False, or None")
    if mode is None or mode is False:
        # Don't open a browser
        pass
    elif mode == 'custom':
        # Just run whatever command the user provided
        if not isinstance(options['cmdline_args'], list):
            raise TypeError("'cmdline_args' option must be of type List[str]")
        sps.Popen(options['cmdline_args'],
                  stdout=sps.PIPE, stderr=sps.PIPE, stdin=sps.PIPE)
    elif mode in _browser_modules:
        # Run with a specific browser
        browser_module = _browser_modules[mode]
        path = _browser_paths.get(mode)
        if path is None:
            # Don't know this browser's path, try and find it ourselves
            path = browser_module.find_path()
            _browser_paths[mode] = path

        if path is not None:
            browser_module.run(path, options, start_urls)
        else:
            raise EnvironmentError("Can't find %s installation" % browser_module.name)
    else:
        # Fall back to system default browser
        for url in start_urls:
            wbr.open(url)


def set_path(browser_name: str, path: str) -> None:
    _browser_paths[browser_name] = path


def get_path(browser_name: str) -> Optional[str]:
    return _browser_paths.get(browser_name)

