import argparse
import json

from web_stream_downloader.config import Config


class ConfigReader(object):
    """Configuration for the web stream downloader"""

    @staticmethod
    def read_from_args_and_file():
        """Build config from command line arguments or/and config file.
        Options obtained from arguments have priority over options obtained from config file.

        :rtype: web_stream_downloader.config.Config
        """
        parser = argparse.ArgumentParser()
        parser.add_argument(
            '-p', '--password', dest='password', help='web rpc agent`s authentication password'
        )
        parser.add_argument(
            '-l', '--local-path', dest='local_path', help='where to copy on local server'
        )
        parser.add_argument(
            '-r', '--remote-path', dest='remote_path', help='where to copy from remote server'
        )
        parser.add_argument(
            '-u', '--stream-url', dest='stream_url', help='URL of stream'
        )
        parser.add_argument(
            '-e', '--exclude', action='append', dest='exclude', help='define paths to exclude'
        )
        parser.add_argument(
            '-c', '--config-file', type=argparse.FileType('r'), dest='config_file',
            help='configuration file in json format'
        )
        # SSL validation options - in the same format as in "curl" utility
        parser.add_argument(
            '-k', '--insecure', dest='insecure', action='store_true', help='allow insecure SSL connections'
        )
        parser.add_argument(
            '-a', '--cacert', dest='cacert', help='CA certificate file/bundle to verify SSL connections'
        )
        args = parser.parse_args()
        config = Config(
            password=args.password,
            local_path=args.local_path,
            remote_path=args.remote_path,
            excludes=args.exclude,
            stream_url=args.stream_url,
            ssl_verify_certificates=False if args.insecure else None,
            ssl_ca_bundle=args.cacert
        )
        if args.config_file is not None:
            file_config = ConfigReader().read_from_file_object(args.config_file)
            config = ConfigReader().merge_configs(file_config, config)
        return config

    @staticmethod
    def read_from_file_object(config_file_object):
        """Build config from config file.

        :rtype: web_stream_downloader.config.Config
        """
        data = json.load(config_file_object)
        password = data.get('password', None)
        local_path = data.get('local_path', None)
        remote_path = data.get('remote_path', None)
        stream_url = data.get('stream_url', None)
        excludes = data.get('exclude', None)
        insecure = data.get('insecure', None)
        cacert = data.get('cacert', None)
        return Config(
            password=password,
            local_path=local_path.encode('utf-8') if local_path is not None else None,
            remote_path=remote_path.encode('utf-8') if remote_path is not None else None,
            excludes=excludes,
            stream_url=stream_url,
            ssl_verify_certificates=not insecure,
            ssl_ca_bundle=cacert,
        )

    @staticmethod
    def merge_configs(old_config, new_config):
        """Merge 2 configs with priority of new_config.

        :rtype: web_stream_downloader.config.Config
        """
        if new_config.ssl_verify_certificates is not None:
            ssl_verify_certificates = new_config.ssl_verify_certificates
        else:
            if old_config.ssl_verify_certificates is not None:
                ssl_verify_certificates = old_config.ssl_verify_certificates
            else:
                ssl_verify_certificates = True

        return Config(
            password=new_config.password if new_config.password is not None else old_config.password,
            local_path=new_config.local_path if new_config.local_path is not None else old_config.local_path,
            remote_path=new_config.remote_path if new_config.remote_path is not None else old_config.remote_path,
            excludes=new_config.excludes if new_config.excludes is not None else old_config.excludes,
            stream_url=new_config.stream_url if new_config.stream_url is not None else old_config.stream_url,
            ssl_verify_certificates=ssl_verify_certificates,
            ssl_ca_bundle=(
                new_config.ssl_ca_bundle is not None
                if new_config.ssl_ca_bundle else
                old_config.ssl_ca_bundle
            )
        )
