# flake8: noqa

"""
Django settings for tordonate project.

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

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

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

import base64
import os
import sys
from pathlib import Path
from uuid import uuid4
import mimetypes

from .civicrm.models import Perk
from .civicrm.repository import CivicrmRepositoryMock as CivicrmRepository
from .utils import extract_client_ip_from_request
from csp.constants import SELF, UNSAFE_INLINE, NONCE

# Load environment variables from .env file, if present, so that os.environ.get() can retrieve
# them for assignation to various site setting variables below.
# If an .env file is not present, it is presumed that these environment variables will have
# been set in a different manner. If not, the site will fail to load properly.
if os.path.exists(".env"):
    from dotenv import load_dotenv

    load_dotenv(override=False)

# add proper MIME-types for various assets
mimetypes.add_type("text/css", ".css", True)
mimetypes.add_type("text/javascript", ".js", True)

# Set application environment, either "staging" or "prod", defaulting to "staging"
APP_ENV = os.environ.get("APP_ENVIRONMENT") or "staging"

# Set this flag to either hide or show optional year-end campaign content on the donate page.
IS_YEC = False

# Build paths inside the project like this: BASE_DIR / 'subdir'.
if "BASE_DIR" in os.environ:
    BASE_DIR = Path(os.environ.get("BASE_DIR"))
else:
    BASE_DIR = Path(__file__).resolve().parent.parent


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

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get("DJANGO_SECRET_KEY")

# SECURITY WARNING: don't run with debug turned on in production!
# Since we store this flag in an environment variable, it will be
# imported as a string rather than a bool. In Python, bool('False')
# returns True. The following string comparison against the DEBUG
# env var is performed so that 'True' (string) evaluates as
# True (bool), and 'False' (string) evaluates as False (bool).
DEBUG = os.environ.get("DEBUG") == "True"

# These flags determine whether we log incoming webhook messages, regardless of type.
# These are intended for debugging donations in production and should be otherwise kept off.
# We retrieve and interpret these string-stored bools as described above.
TRACE_STRIPE_WEBHOOK = os.environ.get("TRACE_STRIPE_WEBHOOK") == "True"
TRACE_PAYPAL_WEBHOOK = os.environ.get("TRACE_PAYPAL_WEBHOOK") == "True"

# Set to prevent HTTP Host header attacks.
# See https://docs.djangoproject.com/en/5.0/topics/security/#host-headers-virtual-hosting
if "ALLOWED_HOSTS" in os.environ:
    ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS").split()

# Set to prevent cross-origin attacks.
# If unset or improperly set (including "correct host, but has a trailing slash"),
# POST requests to local API endpoints will fail.
# See https://docs.djangoproject.com/en/5.0/ref/settings/#csrf-trusted-origins
if "CSRF_TRUSTED_ORIGINS" in os.environ:
    CSRF_TRUSTED_ORIGINS = os.environ.get("CSRF_TRUSTED_ORIGINS").split()

# Application definition

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "django.forms",
    "django_prometheus",
    "bootstrapform_jinja",
    "django_jinja",
    "django_altcha",
    "csp",
    "tordonate",
    "maintenancemode",
]

FORM_RENDERER = "django.forms.renderers.TemplatesSetting"

MIDDLEWARE = [
    'django_prometheus.middleware.PrometheusBeforeMiddleware',
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "maintenancemode.middleware.MaintenanceModeMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
    "tordonate.middleware.CiviCrmMiddleware",
    "csp.middleware.CSPMiddleware",
    "django_ratelimit.middleware.RatelimitMiddleware",
    'django_prometheus.middleware.PrometheusAfterMiddleware',
]

# IP rate limiting configuration
# https://django-ratelimit.readthedocs.io/
RATELIMIT_ENABLE = os.environ.get("RATELIMIT_ENABLE") != "False"
RATE_LIMITING_RATE = "10/m"
RATELIMIT_VIEW = "tordonate.views.RateLimiter"
RATELIMIT_DEFAULT_CACHE_LOCATION = "{}/.cache/django_ratelimiter".format(os.environ.get("HOME"))
RATELIMIT_CACHE_LOCATION = os.environ.get("RATELIMIT_CACHE_LOCATION",
                                          RATELIMIT_DEFAULT_CACHE_LOCATION)

# Use a file-based cache for the rate limiter in staging or prod
# (the default memory cache is not compatible with multiprocess)
if APP_ENV in [ "prod", "staging" ]:
    RATELIMIT_USE_CACHE = 'ratelimiter'
    # fetch the right IP address behind our reverse proxy
    RATELIMIT_IP_META_KEY = extract_client_ip_from_request
else:
    RATELIMIT_USE_CACHE = 'default'

ROOT_URLCONF = "tordonate.urls"

TEMPLATES = [
    {
        "BACKEND": "django_jinja.backend.Jinja2",
        "DIRS": [os.path.join(os.path.dirname(__file__), "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",
            ],
        },
    },
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [os.path.join(os.path.dirname(__file__), "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",
            ],
        },
    },
]

TEMPLATE_LOADERS = [
    "django.template.loaders.filesystem.load_template_source",
    "django.template.loaders.app_directories.load_template_source",
]


WSGI_APPLICATION = "tordonate.wsgi.application"

# Security
# Allow Paypal pop-up to spawn

SECURE_CROSS_ORIGIN_OPENER_POLICY = "same-origin-allow-popups"


# HMAC key for Altcha proof-of-work validation
# https://github.com/aboutcode-org/django-altcha#altcha_hmac_key
# In the event that this environment variable is missing, we generate a random key on the fly
# to prevent Django's system check from failing during URL route resolution testing.
ALTCHA_HMAC_KEY = os.environ.get("ALTCHA_HMAC_KEY") or base64.b64encode(os.urandom(24)).decode("utf-8")

# Cohorts
if "COHORTS_TEST_RATIO" in os.environ:
    COHORTS_TEST_RATIO = float(os.environ["COHORTS_TEST_RATIO"])
    if not 0.0 <= COHORTS_TEST_RATIO <= 1.0:
        raise ValueError("COHORTS_TEST_RATIO must be between 0 and 1 inclusively.")
else:
    COHORTS_TEST_RATIO = 0

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

DATABASES = {
    "default": {
        "ENGINE": "django_prometheus.db.backends.sqlite3",
        "NAME": BASE_DIR / "db.sqlite3",
    }
}

# Caches
# https://docs.djangoproject.com/en/4.1/ref/settings/#caches
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
    },
    'ratelimiter': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': RATELIMIT_CACHE_LOCATION,
    }
}



# Password validation
# https://docs.djangoproject.com/en/4.1/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/4.1/topics/i18n/

LANGUAGE_CODE = "en-us"

TIME_ZONE = "UTC"

USE_I18N = True

USE_TZ = True


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

STATIC_URL = "static/"
STATIC_ROOT = os.path.join(BASE_DIR, "static")

# Default primary key field type
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")

DONATE_PRICES = {
    "single": [500, 2500, 7500, 12500, 50000, 100000],
    "monthly": [500, 1500, 2500, 5000, 7500, 12500],
}
DEFAULT_DONATION = {"single": 12500, "monthly": 2500}
MINIMUM_DONATION = 200

CRYPTO_WALLET_ADDRESSES = {
    "BTC": ("Bitcoin", "bc1qtt04zfgjxg7lpqhk9vk8hnmnwf88ucwww5arsd"),
    "DOGE": ("Dogecoin", "DJwRnafcjDbzqWM5vsCphuyQuTc2QB3a8F"),
    "ETH": ("Ether", "0x532Fb5D00f40ced99B16d1E295C77Cda2Eb1BB4F"),
    "LTC": ("Litecoin", "MTQBNhAP58vpWKsns4ZFUDoh5NK7XECVrs"),
    "XMR": (
        "Monero",
        "4AcQxuMBUfJM7uAWpZP1Vs1BzQLC1QR6zZL3sMYdBuayWmpZHmaVYo7EQ3cSneyHYf2LRKJnRtrGz5ogZzjmmGygAyusEcJ",
    ),
    "XLM": (
        "Stellar Lumen",
        "GABWGQEQESRX5TKDTPIYJFPKGJDMEW6VLOOLBTIFPJIN7XT6KAFXJQPJ",
    ),
    "ZEC": ("Zcash", "t1NnsSG46uPPPMr3D3MdBCKrMpr9XXis8sz"),
}

BTCPAYSERVER_URL = "https://btcpay.torproject.org/"

# settings that shouldn't be checked into version control, like api keys
PAYPAL_CLIENT_ID = os.environ.get("PAYPAL_CLIENT_ID")
PAYPAL_APP_SECRET = os.environ.get("PAYPAL_APP_SECRET")
PAYPAL_SUBSCRIPTION_PRODUCT_ID = os.environ.get("PAYPAL_SUBSCRIPTION_PRODUCT_ID")
PAYPAL_WEBHOOK_ID = os.environ.get("PAYPAL_WEBHOOK_ID")

STRIPE_API_KEY = os.environ.get("STRIPE_API_KEY")
STRIPE_API_SECRET = os.environ.get("STRIPE_API_SECRET")
STRIPE_WEBHOOK_SECRET = os.environ.get("STRIPE_WEBHOOK_SECRET")

REDIS_SERVER = os.environ.get("REDIS_SERVER", "localhost")
REDIS_PORT = int(os.environ.get("REDIS_PORT", "6379"))
REDIS_PASSWORD = os.environ.get("REDIS_PASSWORD", "")
REDIS_DB = int(os.environ.get("REDIS_DB", "0"))

CONTENT_SECURITY_POLICY = {
    "DIRECTIVES": {
        "default-src": [SELF],
        "img-src": [SELF, "data:", "*.stripe.com", "*.paypal.com", "*.paypalobjects.com"],
        "script-src": [SELF, "*.stripe.com", "*.paypal.com", "*.paypalobjects.com", "hcaptcha.com", "*.hcaptcha.com"],
        "script-src-elem": [SELF, NONCE, UNSAFE_INLINE, "'sha256-Yv+VlKVBitwyUcy8H/hWRd1s/FZpaLnrj51ICrowGnw='", "*.stripe.com", "*.paypal.com", "*.paypalobjects.com"],
        "style-src": [SELF, "'sha256-0hAheEzaMe6uXIKV4EehS9pu1am1lj/KnnzrOYqckXk='", "hcaptcha.com", "*.hcaptcha.com"],
        "style-src-elem": [SELF, UNSAFE_INLINE, "*.stripe.com"],
        "style-src-attr": [SELF, UNSAFE_INLINE],
        "connect-src": [SELF, "*.stripe.com", "*.paypal.com"],
        "frame-src": [SELF, "*.stripe.com", "*.paypal.com", "*.paypalobjects.com"],
        "worker-src": [SELF, "blob:"],
    },
}

# Logging configuration
# https://docs.djangoproject.com/en/5.1/topics/logging/#examples
LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "formatters": {
        "verbose": {
            "format": "[{levelname}: {name}.{funcName}] {message}",
            "style": "{",
        },
    },
    "handlers": {
        "console": {
            "class": "logging.StreamHandler",
            "formatter": "verbose",
        },
    },
    "root": {
        "handlers": ["console"],
        "level": "WARNING",
    },
    "loggers": {
        "django": {
            "handlers": ["console"],
            "level": os.getenv("DJANGO_LOG_LEVEL", "WARNING"),
            "propagate": False,
        },
        "tordonate": {
            "handlers": ["console"],
            "level": os.getenv("LOG_LEVEL", "INFO"),
            "propagate": False,
        },
    },
}

# Enable / disable maintenance mode
# (can also be toggled using "./manage.py maintenance on/off")
MAINTENANCE_MODE = os.environ.get("MAINTENANCE_MODE") == "True"

# Ignore non-transactional URLs from maintenance mode
MAINTENANCE_IGNORE_URLS = (
    r'^/faq',
    r'^/privacy-policy',
    r'^/refund-policy',
    r'^/robots.txt',
    r'^/state-disclosures',
)
