#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
Django 通用底座默认配置：DRF、JWT、分页、认证、异常处理、日志、API 记录等。
主工程使用方式：
  from django_base_ai.settings import *
  # 再覆盖 DATABASES, INSTALLED_APPS 等（可选覆盖 SECRET_KEY）
SECRET_KEY 由底座从环境变量 SECRET_KEY 读取，多应用共用同一底座时使用同一密钥即可共用会话/JWT 等能力，新建项目仅需处理业务逻辑、无需单独配置密钥；若需项目独立密钥可在引入后覆盖 SECRET_KEY。
"""

"""
Django settings for application project.

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

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

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

import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

# 底座统一 SECRET_KEY：从环境变量读取，同一底座上的应用使用相同 SECRET_KEY 可共用会话、JWT、签名等
# 子项目不覆盖即共用；生产环境请在部署层设置环境变量 SECRET_KEY
SECRET_KEY = os.environ.get(
    "SECRET_KEY",
    "django-insecure-dev-change-me-when-using-base-default",
)

API_LOG_ENABLE = True
APPID = locals().get("APPID", "未知")
# API_LOG_METHODS = 'ALL'
API_LOG_METHODS = ["POST", "UPDATE", "DELETE", "PUT"]  # ['POST', 'DELETE']
# API_MODEL_MAP、API_EXEMPT_MAP 见下方「其他配置」节，主工程可覆盖
PATH_MAPPING = locals().get(
    "PATH_MAPPING",
    {
        "/healthy/": "健康检查",
        "/token/refresh/": "刷新Token",
    },
)
# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators


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

LANGUAGE_CODE = "zh-hans"

TIME_ZONE = "Asia/Shanghai"

USE_I18N = True

USE_L10N = True

USE_TZ = False

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

STATIC_URL = "/static/"
static_path = os.path.join(BASE_DIR, "static")
if not os.path.exists(static_path):
    os.makedirs(static_path)
# # 设置django的静态文件目录
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),
]

MEDIA_ROOT = "media"  # 项目下的目录
MEDIA_URL = "media/"  # 跟STATIC_URL类似，指定用户可以通过这个url找到文件

# 收集静态文件，必须将 MEDIA_ROOT,STATICFILES_DIRS先注释
# python manage.py collectstatic
# STATIC_ROOT=os.path.join(BASE_DIR,'static')

# ================================================= #
# ******************* 跨域的配置 ******************* #
# ================================================= #

# 全部允许配置
CORS_ORIGIN_ALLOW_ALL = True
# 允许cookie
CORS_ALLOW_CREDENTIALS = True  # 指明在跨域访问中，后端是否支持对cookie的操作

# ================================================= #
# ********************* channels配置 ******************* #
# ================================================= #
# 由主工程覆盖：ASGI_APPLICATION = 'YourProject.asgi.application'
ASGI_APPLICATION = locals().get("ASGI_APPLICATION", None)
REDIS_MODE = locals().get("REDIS_MODE", 0)
REDIS_HOST = locals().get("REDIS_HOST", "")
REDIS_URL = locals().get("REDIS_URL", "")
REDIS_URLS = locals().get("REDIS_HOSTS", [])

# ================================================= #
# *************** REST_FRAMEWORK配置 *************** #
# ================================================= #

REST_FRAMEWORK = {
    "DATETIME_FORMAT": "%Y-%m-%d %H:%M:%S",  # 日期时间格式配置
    "DATE_FORMAT": "%Y-%m-%d",
    "DEFAULT_FILTER_BACKENDS": (
        # 'django_filters.rest_framework.DjangoFilterBackend',
        "django_base_ai.utils.filters.CustomDjangoFilterBackend",
        "rest_framework.filters.SearchFilter",
        "rest_framework.filters.OrderingFilter",
    ),
    "DEFAULT_PAGINATION_CLASS": "django_base_ai.utils.pagination.CustomPagination",  # 自定义分页
    "DEFAULT_AUTHENTICATION_CLASSES": (
        "django_base_ai.utils.authentication.UserAuthentication",  # 自定义的认证类-用于处理get请求access_token发送的凭证
        "rest_framework_simplejwt.authentication.JWTAuthentication",
        "rest_framework.authentication.SessionAuthentication",
    ),
    "DEFAULT_PERMISSION_CLASSES": [
        "rest_framework.permissions.IsAuthenticated",  # 只有经过身份认证确定用户身份才能访问
        # 'rest_framework.permissions.IsAdminUser', # is_staff=True才能访问 —— 管理员(员工)权限
        # 'rest_framework.permissions.AllowAny', # 允许所有
        # 'rest_framework.permissions.IsAuthenticatedOrReadOnly', # 有身份 或者 只读访问(self.list,self.retrieve)
    ],
    "EXCEPTION_HANDLER": "django_base_ai.utils.exception.custom_exception_handler",  # 自定义的异常处理
    "DEFAULT_RENDERER_CLASSES": ("rest_framework.renderers.JSONRenderer",),  # 关闭 API 调试界面，主工程可覆盖
}
# ================================================= #
# ******************** 登录方式配置 ******************** #
# ================================================= #

AUTHENTICATION_BACKENDS = ["django_base_ai.utils.backends.CustomBackend"]
# ================================================= #
# ****************** simplejwt配置 ***************** #
# ================================================= #
from datetime import timedelta

SIMPLE_JWT = {
    # token有效时长
    "ACCESS_TOKEN_LIFETIME": timedelta(minutes=15),
    # token刷新后的有效时间
    "REFRESH_TOKEN_LIFETIME": timedelta(minutes=30),
    # 设置前缀
    "AUTH_HEADER_TYPES": ("JWT",),
    "ROTATE_REFRESH_TOKENS": True,
    "BLACKLIST_AFTER_ROTATION": True,
    "AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",),
}

# ================================================= #
# **************** 验证码配置  ******************* #
# ================================================= #
CAPTCHA_IMAGE_SIZE = (160, 60)  # 设置 captcha 图片大小
CAPTCHA_LENGTH = 4  # 字符个数
CAPTCHA_TIMEOUT = 1  # 超时(minutes)
CAPTCHA_OUTPUT_FORMAT = "%(image)s %(text_field)s %(hidden_field)s "
CAPTCHA_FONT_SIZE = 40  # 字体大小
CAPTCHA_FOREGROUND_COLOR = "#64DAAA"  # 前景色
CAPTCHA_BACKGROUND_COLOR = "#F5F7F4"  # 背景色
CAPTCHA_NOISE_FUNCTIONS = (
    "captcha.helpers.noise_arcs",  # 线
    # "captcha.helpers.noise_dots",  # 点
)
# CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.random_char_challenge' #字母验证码
CAPTCHA_CHALLENGE_FUNCT = "captcha.helpers.math_challenge"  # 加减乘除验证码

# ================================================= #
# ******************** 其他配置 ******************** #
# ================================================= #

DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
# 是否启动API日志记录
API_LOG_ENABLE = locals().get("API_LOG_ENABLE", True)
# API 日志记录的请求方式
API_LOG_METHODS = locals().get("API_LOG_METHODS", ["POST", "UPDATE", "DELETE", "PUT"])
# API_LOG_METHODS = 'ALL' # ['POST', 'DELETE']
# 在操作日志中详细记录的请求模块映射
API_MODEL_MAP = locals().get(
    "API_MODEL_MAP",
    {
        "/token/": "登录模块",
        "/base/api/login/": "登录模块",
        "/base/api/logout/": "登录模块",
    },
)
API_EXEMPT_MAP = locals().get(
    "API_EXEMPT_MAP",
    {
        "/healthy/": "健康检查",
        "/token/refresh/": "刷新Token",
    },
)
# 是否启动 License 验证（关闭则不做 License 校验）
LICENSE_VERIFY_ENABLE = locals().get("LICENSE_VERIFY_ENABLE", False)
# License 验证排除路径（请求 path 包含以下任一则跳过校验）
LICENSE_VERIFY_EXCLUDE = locals().get(
    "LICENSE_VERIFY_EXCLUDE",
    [
        "/healthy",
        "/readiness",
        "/static",
        "/media",
        "license/verify",
    ],
)
DJANGO_CELERY_BEAT_TZ_AWARE = False
CELERY_TIMEZONE = "Asia/Shanghai"  # celery 时区问题
# 静态页面压缩
STATICFILES_STORAGE = "whitenoise.storage.CompressedStaticFilesStorage"

ALL_MODELS_OBJECTS = []  # 所有app models 对象

# 初始化需要执行的列表，用来初始化后执行
INITIALIZE_LIST = []
INITIALIZE_RESET_LIST = []
# 表前缀（主工程可覆盖，默认空）
TABLE_PREFIX = locals().get("TABLE_PREFIX", "")
# 系统配置
SYSTEM_CONFIG = {}
# 字典配置
DICTIONARY_CONFIG = {}
# 系统配置存放位置：redis/memory(默认)
DISPATCH_DB_TYPE = "memory"

# ================================================= #
# ******************** 插件配置 ******************** #
# ================================================= #
# 插件 urlpatterns
PLUGINS_URL_PATTERNS = []

SECURE_CROSS_ORIGIN_OPENER_POLICY = "None"
CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP = True

# # ================================================= #
# # ********************* 日志配置 ******************* #
# # ================================================= #
# # log 配置部分BEGIN #
SERVER_LOGS_FILE = os.path.join(BASE_DIR, "logs", "server.log")
ERROR_LOGS_FILE = os.path.join(BASE_DIR, "logs", "error.log")
LOGS_FILE = os.path.join(BASE_DIR, "logs")
if not os.path.exists(os.path.join(BASE_DIR, "logs")):
    os.makedirs(os.path.join(BASE_DIR, "logs"))

# 格式: 2025-12-30T10:58:00 [INFO] [app.xx.xxx.xxx] -- 登录成功
# 格式: 日期时间 [级别] [模块名] -- 信息
STANDARD_LOG_FORMAT = "%(asctime)s [%(levelname)s] [%(name)s] -- %(message)s"
CONSOLE_LOG_FORMAT = "%(asctime)s [%(levelname)s] [%(name)s] -- %(message)s"
LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "formatters": {
        "standard": {
            "format": STANDARD_LOG_FORMAT,
            "datefmt": "%Y-%m-%dT%H:%M:%S",
        },
        "console": {
            "format": CONSOLE_LOG_FORMAT,
            "datefmt": "%Y-%m-%dT%H:%M:%S",
        },
        "file": {
            "format": CONSOLE_LOG_FORMAT,
            "datefmt": "%Y-%m-%dT%H:%M:%S",
        },
    },
    "handlers": {
        "file": {
            "level": "INFO",
            "class": "logging.handlers.RotatingFileHandler",
            "filename": SERVER_LOGS_FILE,
            "maxBytes": 1024 * 1024 * 100,  # 100 MB
            "backupCount": 5,  # 最多备份5个
            "formatter": "standard",
            "encoding": "utf-8",
        },
        "error": {
            "level": "ERROR",
            "class": "logging.handlers.RotatingFileHandler",
            "filename": ERROR_LOGS_FILE,
            "maxBytes": 1024 * 1024 * 100,  # 100 MB
            "backupCount": 3,  # 最多备份3个
            "formatter": "standard",
            "encoding": "utf-8",
        },
        "console": {
            "level": "INFO",
            "class": "logging.StreamHandler",
            "formatter": "console",
        },
    },
    "loggers": {
        "": {
            "handlers": ["console", "error", "file"],
            "level": "INFO",
        },
        "django": {
            "handlers": ["console", "error", "file"],
            "level": "INFO",
            "propagate": False,
        },
        "django.db.backends": {"handlers": ["console", "error", "file"], "propagate": False, "level": "INFO"},
        "uvicorn.error": {
            "level": "INFO",
            "handlers": ["console", "error", "file"],
        },
        "uvicorn.access": {"handlers": ["console", "error", "file"], "level": "INFO"},
    },
}
# 任务状态
TASK_STATUS = {"PENDING": "待处理", "STARTED": "已开始", "RETRY": "重试", "FAILURE": "失败", "SUCCESS": "成功"}

# XSS
ALLOWED_TAGS = [
    "a",
    "font",
    "abbr",
    "address",
    "area",
    "article",
    "aside",
    "audio",
    "b",
    "base",
    "bdi",
    "bdo",
    "big",
    "blockquote",
    "body",
    "br",
    "button",
    "canvas",
    "caption",
    "cite",
    "code",
    "col",
    "colgroup",
    "data",
    "datalist",
    "dd",
    "del",
    "details",
    "dfn",
    "dialog",
    "div",
    "dl",
    "dt",
    "em",
    "embed",
    "fieldset",
    "figcaption",
    "figure",
    "footer",
    "form",
    "h1",
    "h2",
    "h3",
    "h4",
    "h5",
    "h6",
    "head",
    "header",
    "hr",
    "html",
    "i",
    "img",
    "input",
    "ins",
    "kbd",
    "label",
    "legend",
    "li",
    "link",
    "main",
    "map",
    "mark",
    "meta",
    "meter",
    "nav",
    "noscript",
    "object",
    "ol",
    "optgroup",
    "option",
    "output",
    "p",
    "param",
    "picture",
    "pre",
    "progress",
    "q",
    "rp",
    "rt",
    "ruby",
    "s",
    "samp",
    "script",
    "section",
    "select",
    "small",
    "source",
    "span",
    "strong",
    "style",
    "sub",
    "summary",
    "sup",
    "svg",
    "table",
    "tbody",
    "td",
    "template",
    "textarea",
    "tfoot",
    "th",
    "thead",
    "time",
    "title",
    "tr",
    "track",
    "u",
    "ul",
    "video",
    "wbr",
]  # 允许的标签
ALLOWED_ATTRS = {
    "*": ["style"],  # 所有标签允许 style 属性
    "a": ["href", "title"],  # a 标签允许 href 和 title 属性
    "img": ["src", "alt"],  # img 标签允许 src 和 alt 属性
}
ALLOWED_STYLES = [
    "color",
    "font-family",
    "font-style",
    "text-align",
    "text-decoration",
    "text-indent",
    "background-color",
    "line-height",
    "letter-spacing",
    "word-spacing",
]

"""
[ 'color', 'font-family', 'font-size', 'font-style', 'font-weight', 'text-align', 'text-decoration', 'text-indent',
                   'background-color', 'background-image', 'background-repeat', 'background-size', 'border', 'border-bottom',
                   'border-left', 'border-radius', 'border-right', 'border-top', 'margin', 'margin-bottom', 'margin-left',
                   'margin-right', 'margin-top', 'padding', 'padding-bottom', 'padding-left', 'padding-right', 'padding-top',
                   'line-height', 'letter-spacing', 'word-spacing']
"""
