"""
Django settings for eoshistory project.

Generated by 'django-admin startproject' using Django 2.2.2.

For more information on this file, see
https://docs.djangoproject.com/en/2.2/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.2/ref/settings/

**Copyright**::

    +===================================================+
    |                 © 2019 Privex Inc.                |
    |               https://www.privex.io               |
    +===================================================+
    |                                                   |
    |        Privex EOS History API                     |
    |                                                   |
    |        Core Developer(s):                         |
    |                                                   |
    |          (+)  Chris (@someguy123) [Privex]        |
    |                                                   |
    +===================================================+


"""
import os
import sys

import dotenv
from os import getenv as env
from os.path import dirname, abspath, join

from privex.helpers import env_bool, env_csv, env_int, random_str, empty, \
    settings as hlp_settings, plugin as hlp_plugin

dotenv.load_dotenv()

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = dirname(dirname(dirname(abspath(__file__))))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env('SECRET_KEY', None)

if SECRET_KEY is None:
    print('Critical ERROR: No SECRET_KEY set in .env! Cannot continue.')
    print('Please generate a secure random string used to encrypt sensitive data such as user sessions')
    print(
        f"Place the following line into the file {join(BASE_DIR, '.env')} - for production we "
        f"recommend generating it by hand."
    )
    print()
    print(f'SECRET_KEY={random_str(size=64)}')
    print()
    sys.exit()

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = env_bool('DEBUG', False)

ALLOWED_HOSTS = env_csv('ALLOWED_HOSTS', ['*'])

if '*' in ALLOWED_HOSTS and not DEBUG:
    print("\n================================================================================================\n")
    print('WARNING: ALLOWED_HOSTS currently contains "*". You should configure ALLOWED_HOSTS in your .env')
    print("so that it's restricted to the domains / IPs you expect this app to be accessed from, e.g.\n")
    print("    ALLOWED_HOSTS=eos-history.example.com,eoshistory.example.net,1.2.3.4\n")
    print("\n================================================================================================\n")

# Ignore the whitelist and allow CORS from anywhere
CORS_ORIGIN_ALLOW_ALL = env_bool('CORS_ORIGIN_ALLOW_ALL', True)
# A comma separated list of domains (must include each subdomain) that can send CORS requests
# This is ignored if you don't change CORS_ORIGIN_ALLOW_ALL to False.
CORS_ORIGIN_WHITELIST = env_csv('CORS_ORIGIN_WHITELIST', [])
# CORS_ORIGIN_WHITELIST = CORS_ORIGIN_WHITELIST.split(',') if CORS_ORIGIN_WHITELIST is not None else None

REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}

DEFAULT_CELERY_QUEUE = env('DEFAULT_CELERY_QUEUE', 'eoshist')

EOS_NODE = env_csv('EOS_NODE', [
    'https://eos.greymass.com', 'https://api.eosdetroit.io',
])

EOS_START_TYPE = env('EOS_START_TYPE', 'relative')
"""
EOS_START_TYPE can be either ``"relative"`` (meaning EOS_START_BLOCK is relative to the head block),
or ``"exact"`` (meaning EOS_START_BLOCK specifies an exact block number to start from).

This only really matters for the first run, as once there are some blocks in the database, the sync tasks will
determine it's current position from the last database block number.
"""

# Default is 1,210,000 blocks = 605,000 seconds = approx. 7 days of blocks.
EOS_START_BLOCK = env_int('EOS_START_BLOCK', 1210000)
"""
NOTE: See :py:attr:`.EOS_START_TYPE` as this number can mean different things based on EOS_START_TYPE.

EOS has one block every 500 milliseconds on average. This means 100,000 blocks behind head would be 50,000 seconds
behind, or just under 14 hrs.

For an entire week behind head, you'd enter ``1210000`` (the estd. amount of blocks produced over 605,000 seconds) and
ensure ``EOS_START_TYPE`` is set to 'relative'.
"""

EOS_SYNC_MAX_QUEUE = env_int('EOS_SYNC_MAX_QUEUE', 500)
"""
Queue no more than this many blocks to be imported at a time.

After ``EOS_SYNC_MAX_QUEUE`` blocks are queued, the block import queue function will wait for blocks
to finish importing before adding more to the queue.

This does not control how many Celery worker threads will be ran, it only places a cap on how many blocks
can be waiting to be imported at any given time.
"""

####
# Celery settings
####

CELERY_RESULT_BACKEND = env('CELERY_RESULT_BACKEND', 'django-db')
CELERY_CACHE_BACKEND = env('CELERY_CACHE_BACKEND', 'django-cache')

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'corsheaders',
    'rest_framework',
    'django_filters',
    'django_celery_results',
    'lockmgr',  # Privex's django-lockmgr package
    'historyapp',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'eoshistory.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['historyapp/templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'eoshistory.wsgi.application'


# Database
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE':   'django.db.backends.' + env('DB_BACKEND', 'postgresql'),
        'NAME':     env('DB_NAME', 'eoshistory'),
        'USER':     env('DB_USER', 'eoshistory'),
        'PASSWORD': env('DB_PASS', ''),
        'HOST':     env('DB_HOST', 'localhost'),
        'PORT':     env('DB_PORT', ''),
    },
}

# RabbitMQ host (used only by EOSHistory itself, not celery)
RMQ_HOST = 'localhost'
RMQ_QUEUE = 'eoshist_block'


# REDIS_DB = hlp_settings.REDIS_DB = env_int('REDIS_DB', 0)
# REDIS_HOST = hlp_settings.REDIS_HOST = env('REDIS_HOST', 'localhost')
# REDIS_PORT = hlp_settings.REDIS_PORT = env_int('REDIS_PORT', 6379)
# REDIS_QUEUE_NAME = 'eoshist:tasks'

# hlp_plugin.configure_redis()

# By default, caching is done in local memory of the app, which is fine for development, or small scale production.
# In production, you should probably use Memcached or database caching.
# See https://docs.djangoproject.com/en/2.2/topics/cache/
#
# If you want to use Memcached, install memcached + dev headers, and pylibmc (pip3 install pylibmc)
# then set env var CACHE_BACKEND to 'django.core.cache.backends.memcached.PyLibMCCache', and CACHE_LOCATION to
# ``ip:port`` where 'ip' is the IP/hostname of the memcached server, and 'port' is the memcached port.

CACHE_BACKEND = env('CACHE_BACKEND')

CACHE_BACKEND_DEFAULTS = {
    'redis_cache.RedisCache': dict(
        location=['localhost:6379'],
        options=dict(
            DB=1, PARSER_CLASS='redis.connection.HiredisParser', CONNECTION_POOL_CLASS='redis.BlockingConnectionPool',
            MAX_CONNECTIONS=1000, PICKLE_VERSION=-1, CONNECTION_POOL_CLASS_KWARGS=dict(max_connections=50, timeout=20),
        )
    ),
    'django.core.cache.backends.locmem.LocMemCache': dict(location=None, options={}),
    'django.core.cache.backends.memcached.MemcachedCache': dict(location=['127.0.0.1:11211'], options={}),
    'django.core.cache.backends.memcached.PyLibMCCache': dict(location=['127.0.0.1:11211'], options={}),
}

REDIS_DEFAULT_OPTIONS = dict(
    DB=1, PARSER_CLASS='redis.connection.HiredisParser', CONNECTION_POOL_CLASS='redis.BlockingConnectionPool',
    MAX_CONNECTIONS=1000, PICKLE_VERSION=-1, CONNECTION_POOL_CLASS_KWARGS=dict(max_connections=50, timeout=20),
)

REDIS_DEFAULT_LOCATION = ['localhost:6379']

DEFAULT_CACHE_LOCATION = None
"""If the user doesn't specify a backend, """
DEFAULT_CACHE_OPTIONS = {}

if DEBUG:
    DEFAULT_CACHE_BACKEND = 'django.core.cache.backends.locmem.LocMemCache'
else:
    DEFAULT_CACHE_BACKEND = 'redis_cache.RedisCache'
    # We only set the default location + options for Redis if the CACHE_BACKEND .env var is unset/empty
    # if empty(CACHE_BACKEND):
    #     DEFAULT_CACHE_LOCATION = REDIS_DEFAULT_LOCATION
    #     DEFAULT_CACHE_OPTIONS = REDIS_DEFAULT_OPTIONS

CACHE_BACKEND = env('CACHE_BACKEND', DEFAULT_CACHE_BACKEND)

DEFAULT_CACHE_LOCATION = CACHE_BACKEND_DEFAULTS.get(CACHE_BACKEND, dict(location=None))['location']
DEFAULT_CACHE_OPTIONS = CACHE_BACKEND_DEFAULTS.get(CACHE_BACKEND, dict(options={}))['options']

# If the user has set their cache backend to redis, then we need to make sure the default cache location + options
# are set, regardless of whether DEBUG is enabled or not.
# if CACHE_BACKEND == 'redis_cache.RedisCache':
#     DEFAULT_CACHE_LOCATION = REDIS_DEFAULT_LOCATION
#     DEFAULT_CACHE_OPTIONS = REDIS_DEFAULT_OPTIONS

CACHES = {
    'default': {
        'BACKEND':  env('CACHE_BACKEND', DEFAULT_CACHE_BACKEND),
        'LOCATION': env_csv('CACHE_LOCATION', DEFAULT_CACHE_LOCATION),
        'OPTIONS': DEFAULT_CACHE_OPTIONS
    }
}

# To add / override cache options, add keys to your .env starting with CACHE_OPTION_
# For example:
#     CACHE_OPTION_DB=2
# Would be equivalent to:
#     CACHES['default']['OPTIONS']['DB'] = 2
#
envkeys = os.environ.keys()
for k in envkeys:
    if k[:13].upper() == 'CACHE_OPTION_':
        kdata = k.split('_')
        k_key = '_'.join(kdata[2:])
        CACHES['default']['OPTIONS'][k_key] = env(k)
    

# Password validation
# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/2.2/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.2/howto/static-files/

STATIC_URL = '/static/'

if DEBUG:
    # STATICFILES_DIRS = [
    #     join(BASE_DIR, "static"),
    # ]
    STATIC_ROOT = join(BASE_DIR, 'static')
else:
    STATIC_ROOT = join(BASE_DIR, 'static')

MAX_QUEUE_THREADS = env_int('MAX_QUEUE_THREADS', 4)
MAX_WAIT_THREADS = env_int('MAX_WAIT_THREADS', 4)
MAX_BLOCKS_THREAD = env_int('MAX_BLOCKS_THREAD', 25)
"""Maximum amount of blocks to load per thread"""

MAX_CELERY_QUEUE = env_int('MAX_CELERY_QUEUE', 100)
"""Maximum amount of tasks allowed in the celery queue before sync_blocks pauses"""
