import glob
import os
import warnings

from authentic2 import logger

ETC_DIR = '/etc/authentic2/'

# Add the XForwardedForMiddleware
MIDDLEWARE = ('authentic2.middleware.XForwardedForMiddleware',) + MIDDLEWARE

# Debian defaults
DEBUG = False

MEDIA_ROOT = '/var/lib/authentic2/media'
STATIC_ROOT = '/var/lib/authentic2/collectstatic/'
STATICFILES_DIRS = ('/var/lib/authentic2/static',)
TEMPLATES[0]['DIRS'] = ['/var/lib/authentic2/templates'] + TEMPLATES[0]['DIRS']
LOCALE_PATHS = ('/var/lib/authentic2/locale',) + LOCALE_PATHS

ADMINS = (('root', 'root@localhost'),)

if os.path.exists('/var/lib/authentic2/secret_key'):
    with open('/var/lib/authentic2/secret_key') as f:
        SECRET_KEY = f.read()

LOGGING = {
    'version': 1,
    'disable_existing_loggers': True,
    'filters': {
        'cleaning': {
            '()': 'authentic2.utils.misc.CleanLogMessage',
        },
        'request_context': {
            '()': 'authentic2.log_filters.RequestContextFilter',
        },
        'force_debug': {
            '()': 'authentic2.log_filters.ForceDebugFilter',
        },
    },
    'formatters': {
        'syslog': {
            'format': 'authentic2[%(process)d]: %(ip)s %(user)s %(request_id)s %(levelname)s %(message)s',
        },
        'syslog_db': {
            'format': 'authentic2[%(process)d]: %(levelname)s %(message)s',
        },
    },
    'handlers': {
        'syslog': {
            'level': 'DEBUG',
            'address': '/dev/log',
            'class': 'logging.handlers.SysLogHandler',
            'filters': ['cleaning', 'request_context'],
            'formatter': 'syslog',
        },
        # remove request_context filter for db log to prevent infinite loop
        # when logging sql query to retrieve the session user
        'syslog_db': {
            'level': 'DEBUG',
            'address': '/dev/log',
            'class': 'logging.handlers.SysLogHandler',
            'filters': ['cleaning'],
            'formatter': 'syslog_db',
        },
    },
    'loggers': {
        # even when debugging seeing SQL queries is too much, activate it
        # explicitly using DEBUG_DB
        'django.db': {
            # use a special handler to prevent recursive loop by the RequestContextFilter
            # as it does accesses to the database
            'handlers': ['syslog_db'],
            'level': logger.SettingsLogLevel('INFO', debug_setting='DEBUG_DB'),
            'propagate': False,
        },
        'django': {
            # Override Django default values
            'handlers': [],
            'level': 'NOTSET',
            'propagate': True,
        },
        'django.server': {
            # Override Django 1.8 default values
            'handlers': [],
            'level': 'NOTSET',
            'propagate': True,
        },
        'django.request': {
            # Override Django default values
            'handlers': [],
            'level': 'NOTSET',
            'propagate': True,
        },
        'django.security': {
            # Override Django default values
            'handlers': [],
            'level': 'NOTSET',
            'propagate': True,
        },
        # django_select2 outputs debug message at level INFO
        'django_select2': {
            'handlers': ['syslog'],
            'level': 'WARNING',
        },
        # lasso has the bad habit of logging everything as errors
        'Lasso': {
            'filters': ['force_debug'],
        },
        'libxml2': {
            'filters': ['force_debug'],
        },
        'libxmlsec': {
            'filters': ['force_debug'],
        },
        '': {
            'handlers': ['syslog'],
            'level': logger.SettingsLogLevel('INFO'),
        },
    },
}


# Old settings method
def extract_settings_from_environ():
    import json

    from django.core.exceptions import ImproperlyConfigured

    global MANAGERS, DATABASES, SENTRY_TRANSPORT, SENTRY_DSN, INSTALLED_APPS, SECURE_PROXY_SSL_HEADER, CACHES, SESSION_ENGINE, LDAP_AUTH_SETTINGS

    BOOLEAN_ENVS = (
        'DEBUG',
        'DEBUG_PROPAGATE_EXCEPTIONS',
        'SESSION_EXPIRE_AT_BROWSER_CLOSE',
        'SESSION_COOKIE_SECURE',
        'EMAIL_USE_TLS',
        'USE_X_FORWARDED_HOST',
        'DISCO_SERVICE',
        'DISCO_USE_OF_METADATA',
        'SHOW_DISCO_IN_MD',
        'SSLAUTH_CREATE_USER',
        'PUSH_PROFILE_UPDATES',
        'A2_CAN_RESET_PASSWORD',
        'A2_REGISTRATION_CAN_DELETE_ACCOUNT',
        'A2_REGISTRATION_EMAIL_IS_UNIQUE',
        'REGISTRATION_OPEN',
        'A2_AUTH_PASSWORD_ENABLE',
        'SSLAUTH_ENABLE',
        'A2_IDP_SAML2_ENABLE',
    )

    def to_boolean(name, default=True):
        try:
            value = os.environ[name]
        except KeyError:
            return default
        try:
            i = int(value)
            return bool(i)
        except ValueError:
            if value.lower() in ('true', 't', 'y', 'yes'):
                return True
            if value.lower() in ('false', 'f', 'n', 'no'):
                return False
        return default

    for boolean_env in BOOLEAN_ENVS:
        if boolean_env in os.environ:
            globals()[boolean_env] = to_boolean(boolean_env)

    STRING_ENVS = (
        'STATIC_ROOT',
        'STATIC_URL',
        'A2_OPENED_SESSION_COOKIE_DOMAIN',
        'SESSION_COOKIE_NAME',
        'SESSION_COOKIE_PATH',
        'SESSION_ENGINE',
        'EMAIL_HOST',
        'EMAIL_HOST_USER',
        'EMAIL_HOST_PASSWORD',
        'EMAIL_SUBJECT_PREFIX',
        'SERVER_EMAIL',
        'DEFAULT_FROM_EMAIL',
        'LOGIN_REDIRECT_URL',
        'LOGIN_URL',
        'LOGOUT_URL',
        'SECRET_KEY',
        'DISCO_SERVICE_NAME',
        'SAML_SIGNATURE_PUBLIC_KEY',
        'SAML_SIGNATURE_PRIVATE_KEY',
        'SAML_METADATA_AUTOLOAD',
        'A2_HOMEPAGE_URL',
    )

    for string_env in STRING_ENVS:
        if string_env in os.environ:
            globals()[string_env] = os.environ[string_env]

    PATH_ENVS = (
        'STATICFILES_DIRS',
        'TEMPLATE_DIRS',
        'LOCALE_PATHS',
        'ALLOWED_HOSTS',
        'INTERNAL_IPS',
        'PASSWORD_HASHERS',
    )

    for path_env in PATH_ENVS:
        if path_env in os.environ:
            if path_env == 'TEMPLATE_DIRS':
                old = globals()['TEMPLATES']['DIRS']
                globals()['TEMPLATES']['DIRS'] = list(os.environ[path_env].split(':')) + old
            else:
                old = globals().get(path_env)
                globals()[path_env] = tuple(os.environ[path_env].split(':')) + tuple(old)

    INT_ENVS = (
        'SESSION_COOKIE_AGE',
        'EMAIL_PORT',
        'AUTHENTICATION_EVENT_EXPIRATION',
        'LOCAL_METADATA_CACHE_TIMEOUT',
        'ACCOUNT_ACTIVATION_DAYS',
        'PASSWORD_RESET_TIMEOUT_DAYS',
    )

    def to_int(name, default):
        try:
            value = os.environ[name]
            return int(value)
        except KeyError:
            return default
        except ValueError:
            raise ImproperlyConfigured('environ variable %s must be an integer' % name)

    for int_env in INT_ENVS:
        if int_env in os.environ:
            try:
                globals()[int_env] = int(os.environ[int_env])
            except ValueError:
                raise ImproperlyConfigured('environement variable %s must be an integer' % int_env)

    ADMINS = ()
    if 'ADMINS' in os.environ:
        ADMINS = filter(None, os.environ.get('ADMINS').split(':'))
        ADMINS = [admin.split(';') for admin in ADMINS]
        for admin in ADMINS:
            assert (
                len(admin) == 2
            ), 'ADMINS setting must be a colon separated list of name and emails separated by a semi-colon'
            assert '@' in admin[1], 'ADMINS setting pairs second value must be emails'
        MANAGERS = ADMINS

    for key in os.environ:
        if key.startswith('DATABASE_'):
            prefix, db_key = key.split('_', 1)
            DATABASES['default'][db_key] = os.environ[key]

    if 'SECURE_PROXY_SSL_HEADER' in os.environ:
        SECURE_PROXY_SSL_HEADER = os.environ['SECURE_PROXY_SSL_HEADER'].split(':', 1)

    if 'LDAP_AUTH_SETTINGS' in os.environ:
        try:
            LDAP_AUTH_SETTINGS = json.loads(os.environ['LDAP_AUTH_SETTINGS'])
        except Exception as e:
            raise ImproperlyConfigured('LDAP_AUTH_SETTINGS is not a JSON document', e)

    if 'CACHE_BACKEND' in os.environ:
        CACHES['default'] = json.loads(os.environ['CACHE_BACKEND'])

    if 'USE_MEMCACHED' in os.environ:
        try:
            import pymemcache
        except:
            raise ImproperlyConfigured(
                'Python pymemcache library is not installed, please do: pip install pymemcache'
            )
        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
                'LOCATION': '127.0.0.1:11211',
                'KEY_PREFIX': 'authentic2',
                'OPTIONS': {'ignore_exc': True},
            }
        }
        SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'

    # extract any key starting with setting
    for key in os.environ:
        if key.startswith('SETTING_'):
            setting_key = key[len('SETTING_') :]
            value = os.environ[key]
            try:
                value = int(value)
            except ValueError:
                pass
            globals()[setting_key] = value


extract_settings_from_environ()

CONFIG_FILE = '/etc/authentic2/config.py'
if os.path.exists(CONFIG_FILE):
    with open(CONFIG_FILE) as fd:
        exec(fd.read())

for filename in sorted(glob.glob(os.path.join(ETC_DIR, 'settings.d', '*.py'))):
    exec(open(filename).read())

# Warn if DEFAULT_FROM_EMAIL is absent
if not locals().get('DEFAULT_FROM_EMAIL'):
    warnings.warn('DEFAULT_FROM_EMAIL must be customized')
