"""
Django settings for flower project.

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

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

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

# 兼容旧版 django-qiniu-storage
try:
    from django.utils.encoding import force_text
except ImportError:
    from django.utils.encoding import force_str as force_text
    import django.utils.encoding
    django.utils.encoding.force_text = force_text

from datetime import timedelta
from pathlib import Path
from environ import Env

# 应用七牛云 SDK 补丁（必须在导入其他模块之前）
from flower.qiniu_patch import apply_all_patches
apply_all_patches()

env = Env(
    DEBUG=(bool, False),
)


# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

# Initialize environment variables
Env.read_env(str(BASE_DIR / '.env'))

# 允许一次请求携带更多表单字段，避免 admin 批量操作时报 TooManyFieldsSent
# Django 默认 DATA_UPLOAD_MAX_NUMBER_FIELDS=1000，当一次 POST/GET 的字段（含重复 key）过多会直接抛异常。
DATA_UPLOAD_MAX_NUMBER_FIELDS = env.int('DATA_UPLOAD_MAX_NUMBER_FIELDS', default=20000)

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

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

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

ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=[
    'yuwenerp.yuwen.cloud',
    'testbackend.yuwen.cloud',
])
CSRF_TRUSTED_ORIGINS = env.list('CSRF_TRUSTED_ORIGINS', default=[
    'https://yuwenerp.yuwen.cloud',
    'https://testbackend.yuwen.cloud',
])

# 明道云同步配置
MDY_MERCHANT_ID = env.int('MDY_MERCHANT_ID', default=1)
MDY_PRODUCT_CATEGORY_ID = env.int('MDY_PRODUCT_CATEGORY_ID', default=1)
MDY_ISOLATED_MERCHANT_ID = env.int('MDY_ISOLATED_MERCHANT_ID', default=0)
MDY_SYNC_PAGE_SIZE = env.int('MDY_SYNC_PAGE_SIZE', default=100)
MDY_SYNC_MAX_PAGES = env.int('MDY_SYNC_MAX_PAGES', default=2)
MDY_SYNC_MAX_RECORDS = env.int('MDY_SYNC_MAX_RECORDS', default=200)
# 明道云“开版暂存”同步：每次请求之间的最小间隔（用于限流）
# - 0.02 ~ 50 qps（理论值，实际应更保守以预留重试/关联查询）
MDY_PLATE_ORDER_SYNC_REQUEST_INTERVAL_SECONDS = env.float('MDY_PLATE_ORDER_SYNC_REQUEST_INTERVAL_SECONDS', default=0.05)

# Tencent Cloud (TIIA) 配置：用于通过 ImageUrl 上传图片到图库（CreateImage）
# 注意：不要把 secret 写死在代码里，建议通过 .env / 环境变量注入。
TENCENTCLOUD_SECRET_ID = env('TENCENTCLOUD_SECRET_ID', default='AKID2wtgIhYCcprkS0QfiZCbopetxpW1KSPE')
TENCENTCLOUD_SECRET_KEY = env('TENCENTCLOUD_SECRET_KEY', default='oSwGOJ0XzJRODrIXZWIrEPNAmHdppdHh')
TENCENTCLOUD_TOKEN = env('TENCENTCLOUD_TOKEN', default='')  # STS 临时票据（可选）

TENCENTCLOUD_TIIA_GROUP_ID = env('TENCENTCLOUD_TIIA_GROUP_ID', default='168')
TENCENTCLOUD_TIIA_REGION = env('TENCENTCLOUD_TIIA_REGION', default='ap-guangzhou')
TENCENTCLOUD_TIIA_ENDPOINT = env('TENCENTCLOUD_TIIA_ENDPOINT', default='tiia.tencentcloudapi.com')
TENCENTCLOUD_TIIA_PIC_NAME_PREFIX = env('TENCENTCLOUD_TIIA_PIC_NAME_PREFIX', default='plate_order')
TENCENTCLOUD_TIIA_QPS = env.int('TENCENTCLOUD_TIIA_QPS', default=10)  # Tencent API 限速：每秒最多 10 次

# 企业微信机器人 Webhook（目前按需求直接写入 settings，不走 .env）
# 使用：https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxx
WECOM_WEBHOOK_BASE_URL = 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send'
WECOM_WEBHOOK_KEY = env('WECOM_WEBHOOK_KEY', default='')
MESSAGE_API_AUTHORIZATION = env('MESSAGE_API_AUTHORIZATION', default='hophopkk')
MESSAGE_API_BASE_URL = env('MESSAGE_API_BASE_URL', default='https://www.ruicaiyinhua.online')
MESSAGE_API_DEFAULT_NEWS_IMAGE_URL = env(
    'MESSAGE_API_DEFAULT_NEWS_IMAGE_URL',
    default='https://via.placeholder.com/640x360.png?text=No+Image',
)
SPEECH_ENABLED = True
SPEAK_ENDPOINT = env('SPEAK_ENDPOINT', default='https://tts.yuwen.cloud/speak')
SPEAK_API_KEY = 'wobushixiaoai_1216'
PRINTING_ORDER_CREATED_SPEECH_ENABLED = False
BUSINESS_ORDER_SPEECH_NOTIFY_ENABLED = True
MISSION_SPEECH_NOTIFY_ENABLED = True
AGENT_ACCESS_KEY = env('AGENT_ACCESS_KEY', default='')

# HaoBuYe 外部财务同步
HAOBUYE_API_BASE_URL = env('HAOBUYE_API_BASE_URL', default='http://43.139.183.222:18080')
HAOBUYE_API_AUTHORIZATION = env('HAOBUYE_API_AUTHORIZATION', default='your-fixed-authorization-secret')
HAOBUYE_API_TIMEOUT_SECONDS = env.float('HAOBUYE_API_TIMEOUT_SECONDS', default=30.0)
HAOBUYE_FINANCE_SYNC_OPERATOR_ID = env.int('HAOBUYE_FINANCE_SYNC_OPERATOR_ID', default=6)

# Business 金额计算口径
# - haobuye_integer_round_half_up: 行金额=ROUND_HALF_UP(quantity * price, 0)，收/付款金额取整数元
# - standard_decimal_2: 原系统口径，行金额=ROUND_HALF_UP(real_quantity * price, 2)，收/付款金额保留两位
BUSINESS_AMOUNT_MODE = env('BUSINESS_AMOUNT_MODE', default='haobuye_integer_round_half_up')

# App version check API
# 默认由环境变量提供；如需不重启动态更新，可用管理命令写入缓存。
APP_LATEST_VERSION_MAJOR = env.int('APP_LATEST_VERSION_MAJOR', default=0)
APP_LATEST_VERSION_MINOR = env.int('APP_LATEST_VERSION_MINOR', default=0)
APP_LATEST_VERSION_BUILD = env.int('APP_LATEST_VERSION_BUILD', default=0)
APP_DOWNLOAD_URL = env('APP_DOWNLOAD_URL', default='')

# 定时财务同步客户列表（临时需求，直接写死不走 env）
FINANCE_SYNC_CUSTOMER_NAMES: list[str] = [
    '曾念', '紫琪', '胡肖宇', '歌斯拉-胜利星厂', '胡鼎',
    '罗标', '永琪服饰', '罗兵', '杜辉', '李群', '超麦汇大洋',
    '展兴', '王杰敏', '锐木', '何玄', '周刚（周总）', '彤彤服饰',
    '杰恩', '来发裁床', '刘静贤', '金源', '达达-金腾达qs', '周乔峰',
    '杨锐辉', '杨赛英', '别坤', 'A黄宇', '英豪'
]


# CORS 配置
CORS_ALLOW_ALL_ORIGINS = True # 开发环境允许所有源，生产环境需要配置白名单
CORS_ALLOW_CREDENTIALS = True  # 允许携带凭证（如 Cookie、认证头）

# SSE 需要的特殊 CORS 配置
CORS_ALLOW_HEADERS = [
    'accept',
    'accept-encoding',
    'authorization',
    'content-type',
    'dnt',
    'origin',
    'user-agent',
    'x-csrftoken',
    'x-requested-with',
    'cache-control',  # SSE 需要
    'x-accel-buffering',  # SSE 需要
    'last-event-id',  # SSE 重连需要
    # 注意：不要添加 'connection'，这是 hop-by-hop 头部，会被代理过滤
]

# SSE 需要暴露的响应头
CORS_EXPOSE_HEADERS = [
    'content-type',
    'cache-control',
    'x-accel-buffering',
]

# 预检请求缓存时间（秒）
CORS_PREFLIGHT_MAX_AGE = 86400  # 24小时


# Application definition

INSTALLED_APPS = [
    'simpleui',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',  # 使用七牛云存储，不需要staticfiles app
    'corsheaders',  # CORS 支持
    'rest_framework',
    'drf_spectacular',
    'basic_info',
    'business',
    'stock',
    'api_v1',
    'api_man',
    'printing',
    'stateflow',
    'sse',
    'api_v2',
    'api_core',
    'shipment',
    'settlement',
    'mission',
    'notifier',
    'mes',
    'cost',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'corsheaders.middleware.CorsMiddleware',  # CORS 中间件，必须放在 CommonMiddleware 之前
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'flower.middleware.ApiAuditLogMiddleware',  # API审计日志中间件，需在AuthenticationMiddleware之后
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
    'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
    'EXCEPTION_HANDLER': 'flower.exception_handler.custom_exception_handler',
}

# JWT 配置
SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(days=7),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
    'ROTATE_REFRESH_TOKENS': True,
    'UPDATE_LAST_LOGIN': True,
}

SPECTACULAR_SETTINGS = {
    'TITLE': 'Flower API',
    'DESCRIPTION': 'API documentation for the Flower project',
    'VERSION': '1.0.0',
    'SERVE_INCLUDE_SCHEMA': False,
    'SERVE_AUTHENTICATION': [
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ],
    'SERVE_PERMISSIONS': [
        'rest_framework.permissions.IsAuthenticated',
    ],
}

ROOT_URLCONF = 'flower.urls'

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

WSGI_APPLICATION = 'flower.wsgi.application'


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

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': env('DB_NAME'),
        'USER': env('DB_USER'),
        'PASSWORD': env('DB_PASSWORD'),
        'HOST': env('DB_HOST', default='localhost'),
        'PORT': env('DB_PORT', default='6432'),
        'CONN_HEALTH_CHECK': True,
        'CONN_MAX_AGE': env.int('CONN_MAX_AGE', default=0),
        'DISABLE_SERVER_SIDE_CURSORS': True,
    }
}


# Cache configuration
# https://docs.djangoproject.com/en/5.2/topics/cache/
# Django 5.x 内置 Redis 缓存后端，使用 redis 包（已安装）
# Redis 连接配置：优先使用 CACHE_URL，否则从 CACHE_HOST/CACHE_PORT/CACHE_DB 构建
# 默认 localhost:6379（适合宿主机运行），Docker Compose 可通过环境变量指定 CACHE_HOST=redis

# 检测是否在测试环境中
import sys
TESTING = 'test' in sys.argv

if TESTING:
    # 测试环境使用内存缓存，避免 Redis 连接问题
    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
            'LOCATION': 'unique-testing-cache',
        }
    }
else:
    # 生产/开发环境使用 Redis
    # 优先使用 CACHE_URL（完整 URL），否则从 host/port/db 构建
    cache_url = env('CACHE_URL', default=None)
    if cache_url is None:
        cache_host = env('CACHE_HOST', default='localhost')
        cache_port = env.int('CACHE_PORT', default=6379)
        cache_db = env.int('CACHE_DB', default=0)
        cache_url = f'redis://{cache_host}:{cache_port}/{cache_db}'
    
    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.redis.RedisCache',
            'LOCATION': cache_url,
            'OPTIONS': {
                # Redis 连接选项
                'socket_connect_timeout': 5,  # 连接超时（秒）
                'socket_timeout': 5,  # 操作超时（秒）
                'retry_on_timeout': True,  # 超时后重试
                'health_check_interval': 30,  # 健康检查间隔（秒）
            },
            # 键前缀，避免不同项目/环境之间的键冲突
            'KEY_PREFIX': env('CACHE_KEY_PREFIX', default='flower'),
            # 默认过期时间（秒），None 表示永不过期（由具体使用场景决定）
            'TIMEOUT': env.int('CACHE_DEFAULT_TIMEOUT', default=300),  # 默认 5 分钟
        }
    }


# PrintingJob：状态推进时的企业微信通知（markdown）
# - 默认：测试环境关闭（避免单测出网/刷屏），非测试环境开启
PRINTING_JOB_STATE_ADVANCED_WECOM_NOTIFY_ENABLED = (not TESTING)
# PrintingJob 跟进地址（用于企业微信通知里展示/点击）
# orderId 使用 PrintingOrder.id
PRINTING_JOB_STATE_ADVANCED_FOLLOWUP_URL_TEMPLATE = env('PRINTING_JOB_STATE_ADVANCED_FOLLOWUP_URL_TEMPLATE', default='')
PRINTING_JOB_STATE_ADVANCED_WECOM_MARKDOWN_TEMPLATE = (
    "### 印染任务状态推进\n"
    "\n"
    "- **印染订单ID**：`{printing_order_id}`\n"
    "- **印染任务ID**：`{printing_job_id}`\n"
    "- **推进状态**：**{state_name}**\n"
    "- **推进时间**：`{advanced_at}`\n"
    "- **发送者**：{sender}\n"
    "{followup_line}"
    "\n"
    "**工序参数**：\n"
    "{process_params_markdown}\n"
)

# PrintingOrder：创建时的企业微信通知（markdown）
# - 默认：测试环境关闭（避免单测出网/刷屏），非测试环境开启
PRINTING_ORDER_CREATED_WECOM_NOTIFY_ENABLED = env.bool(
    "PRINTING_ORDER_CREATED_WECOM_NOTIFY_ENABLED",
    default=(not TESTING),
)
PRINTING_JOB_PRODUCTION_COMPLETED_WECOM_NOTIFY_ENABLED = env.bool(
    "PRINTING_JOB_PRODUCTION_COMPLETED_WECOM_NOTIFY_ENABLED",
    default=True,
)
PRINTING_ORDER_CREATED_WECOM_MARKDOWN_TEMPLATE = (
    "### 印染订单创建\n"
    "\n"
    "- **印染订单ID**：`{printing_order_id}`\n"
    "- **订单编号**：`{printing_order_human_id}`\n"
    "- **创建时间**：`{created_at}`\n"
    "- **发送者**：{sender}\n"
    "- **客户**：{customer_name}\n"
    "- **面料**：{fabric}\n"
    "- **出货日期**：`{outgoing_date}`\n"
)

SHIPMENT_CREATED_WECOM_NOTIFY_ENABLED = env.bool(
    "SHIPMENT_CREATED_WECOM_NOTIFY_ENABLED",
    default=True,
)

# PreSalesOrder：创建时的企业微信通知（markdown）
# - 默认：测试环境关闭（避免单测出网/刷屏），非测试环境开启
PRE_SALES_ORDER_CREATED_WECOM_NOTIFY_ENABLED = env.bool(
    "PRE_SALES_ORDER_CREATED_WECOM_NOTIFY_ENABLED",
    default=(not TESTING),
)
# 预销售单跟进地址（用于企业微信通知里展示/点击）
# 使用 pre_sales_order_id 进行格式化
PRE_SALES_ORDER_CREATED_FOLLOWUP_URL_TEMPLATE = env(
    "PRE_SALES_ORDER_CREATED_FOLLOWUP_URL_TEMPLATE",
    default="https://app.yuwen.cloud/workstation/warehouse/task-allocation/{pre_sales_order_id}",
)


# Logging configuration
# 目标：
# - 生产环境出现 500 时，能在 stdout 日志里看到完整 traceback
# - 所有日志以单行 JSON 输出，便于 Loki / Filebeat 检索与聚合
LOG_LEVEL = env('LOG_LEVEL', default='INFO').upper()
DJANGO_LOG_LEVEL = env('DJANGO_LOG_LEVEL', default=LOG_LEVEL).upper()
UVICORN_LOG_LEVEL = env('UVICORN_LOG_LEVEL', default=LOG_LEVEL).upper()
UVICORN_ACCESS_LOG_LEVEL = env('UVICORN_ACCESS_LOG_LEVEL', default='INFO').upper()

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'json': {
            '()': 'flower.logging_formatters.JsonFormatter',
        },
    },
    'filters': {
        'below_warning': {
            '()': 'flower.logging_formatters.MaxLevelFilter',
            'max_level': 'WARNING',
        },
    },
    'handlers': {
        'stdout': {
            'class': 'logging.StreamHandler',
            'formatter': 'json',
            'stream': 'ext://sys.stdout',
            'filters': ['below_warning'],
        },
        'stderr': {
            'class': 'logging.StreamHandler',
            'formatter': 'json',
            'stream': 'ext://sys.stderr',
            'level': 'WARNING',
        },
    },
    'root': {
        'handlers': ['stdout', 'stderr'],
        'level': LOG_LEVEL,
    },
    'loggers': {
        # Django 在发生未捕获异常（500）时，会通过 django.request 输出错误日志，
        # record.exc_info 会携带 traceback，Formatter 会自动把 traceback 打到日志中。
        'django.request': {
            'handlers': ['stdout', 'stderr'],
            'level': 'ERROR',
            'propagate': False,
        },
        'django': {
            'handlers': ['stdout', 'stderr'],
            'level': DJANGO_LOG_LEVEL,
            'propagate': False,
        },
        # Uvicorn 日志（access/error）统一走我们的 console formatter，确保有时间戳
        'uvicorn': {
            'handlers': ['stdout', 'stderr'],
            'level': UVICORN_LOG_LEVEL,
            'propagate': False,
        },
        'uvicorn.error': {
            'handlers': ['stdout', 'stderr'],
            'level': UVICORN_LOG_LEVEL,
            'propagate': False,
        },
        'uvicorn.access': {
            'handlers': ['stdout', 'stderr'],
            'level': UVICORN_ACCESS_LOG_LEVEL,
            'propagate': False,
        },
    },
}


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

LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_TZ = True


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

# 七牛云存储配置
QINIU_ACCESS_KEY = 'IySZff0zEN7jHeDuxj5PrQNMv0qjKoVqBRCuFMzi'
QINIU_SECRET_KEY = 'Mph5XkjUQO3VHFPT1JulYHY442uMOya2bXjbSZp8'
QINIU_BUCKET_NAME = 'yunwenerp2'
QINIU_BUCKET_DOMAIN = 'image.yuwen.cloud'
QINIU_SECURE_URL = True

STORAGES = {
    'default': {
        'BACKEND': 'qiniustorage.backends.QiniuStorage',
    },
    'staticfiles': {
        'BACKEND': 'qiniustorage.backends.QiniuStorage',
    },
}

DEFAULT_FILE_STORAGE = 'qiniustorage.backends.QiniuStorage'
STATICFILES_STORAGE = 'qiniustorage.backends.QiniuStorage'

# 静态文件URL（直接从七牛云访问）
STATIC_URL = f'http://{QINIU_BUCKET_DOMAIN}/static/'
STATIC_ROOT = 'static'

MEDIA_URL = f'http://{QINIU_BUCKET_DOMAIN}/media/'

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

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

# Stateflow 配置
# ------------------------------------------------------------------------------
# STATEFLOW_CURRENT_STATE_MODE: 控制 current_state 的语义
# 
# 可选值:
#   'NEXT' (默认): current_state 返回"下一个待执行的节点"
#                  - 配合 progress 判断："节点名" / "已完成"
#                  - 适合显示"接下来要做什么"
#                  - 原有默认行为
#
#   'LAST':        current_state 返回"最后完成的节点"
#                  - 显示"刚做完了什么"
#                  - 适合审计和历史查看
#                  - 新增行为模式
#
# 注意:
# - 修改此配置会影响 status 属性的显示内容
# - API 接口保持兼容，但返回的 status 和 status_id 语义会变化
# - 推荐在新代码中直接使用 get_last_completed_state() 或 get_next_pending_state() 
#   以避免歧义
# - 已废除"未开始"的显示，直接显示第一个节点名称
# ------------------------------------------------------------------------------
STATEFLOW_CURRENT_STATE_MODE = 'NEXT'
# STATEFLOW_CURRENT_STATE_MODE = 'LAST'

# Printing module settings
PRINTING_DEFAULT_PROCESS_ID = 1  # 默认印染流程ID
PRINTING_EXTERNAL_RECORDS_BASE_URL = 'http://43.139.183.222:18080'
PRINTING_EXTERNAL_RECORDS_AUTHORIZATION = 'your-fixed-authorization-secret'
PRINTING_EXTERNAL_SYNC_USER_ID = 2
PRINTING_EXTERNAL_SYNC_PRODUCT_CATEGORY_ID = None
PLATE_ORDER_DEFAULT_PROCESS_ID = 2  # 默认开版流程ID

# 销售品自动创建配置（PrintingJob 流程完成时）
# ------------------------------------------------------------------------------
# 指定从哪个流程节点获取数量参数，单位固定为"米"
# 如果该节点未完成或参数不存在，则不创建销售品
# ------------------------------------------------------------------------------
AUTO_CREATE_SALESITEM_FROM_PRINT_ORDER = env.bool('AUTO_CREATE_SALESITEM_FROM_PRINT_ORDER', default=False)
PRINTING_SALES_ITEM_SOURCE_STATE_ID = env.int('PRINTING_SALES_ITEM_SOURCE_STATE_ID')  # 必须在 .env 中配置
PRINTING_SALES_ITEM_QUANTITY_KEY = '米数'  # 数量参数的 key

# Settlement module settings
# ------------------------------------------------------------------------------
# 日结运行时间（固定时间，所有商户统一）
SETTLEMENT_RUN_HOUR = env.int('SETTLEMENT_RUN_HOUR', default=5)
SETTLEMENT_RUN_MINUTE = env.int('SETTLEMENT_RUN_MINUTE', default=0)
# ------------------------------------------------------------------------------

# API 审计日志配置
# ------------------------------------------------------------------------------
# 用于记录特定模块POST请求的历史现场，便于追踪"创建"操作。
# 通过Celery异步写入，不影响API响应性能。
# ------------------------------------------------------------------------------
API_AUDIT_LOG_ENABLED = True
API_AUDIT_LOG_URL_PREFIXES = [
    '/api/v1/printing',
    '/api/v1/plate',
]

# Celery 配置
# RabbitMQ Broker 配置：优先使用 CELERY_BROKER_URL，否则从各组件构建
# 默认 localhost（适合宿主机运行），Docker Compose 可通过环境变量指定 CELERY_BROKER_HOST=rabbitmq
celery_broker_url = env('CELERY_BROKER_URL', default=None)
if celery_broker_url is None:
    celery_broker_host = env('CELERY_BROKER_HOST', default='localhost')
    celery_broker_port = env.int('CELERY_BROKER_PORT', default=5672)
    celery_broker_user = env('CELERY_BROKER_USER', default='guest')
    celery_broker_password = env('CELERY_BROKER_PASSWORD', default='guest')
    celery_broker_vhost = env('CELERY_BROKER_VHOST', default='/')
    celery_broker_url = f'amqp://{celery_broker_user}:{celery_broker_password}@{celery_broker_host}:{celery_broker_port}/{celery_broker_vhost}'
CELERY_BROKER_URL = celery_broker_url

# Celery Result Backend 配置：优先使用 CELERY_RESULT_BACKEND，否则从各组件构建
# 默认使用与 Cache 相同的 Redis 实例，Docker Compose 可通过环境变量指定 CELERY_RESULT_HOST=redis
celery_result_url = env('CELERY_RESULT_BACKEND', default=None)
if celery_result_url is None:
    celery_result_host = env('CELERY_RESULT_HOST', default='localhost')
    celery_result_port = env.int('CELERY_RESULT_PORT', default=6379)
    celery_result_db = env.int('CELERY_RESULT_DB', default=1)  # 使用 db=1，与 Cache 的 db=0 区分
    celery_result_url = f'redis://{celery_result_host}:{celery_result_port}/{celery_result_db}'
CELERY_RESULT_BACKEND = celery_result_url

CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = TIME_ZONE

from celery.schedules import crontab

CELERY_BEAT_SCHEDULE = {
    # 'daily_database_backup': {
    #     'task': 'api_v1.tasks.backup_database',
    #     'schedule': crontab(hour=3, minute=0),
    #     'kwargs': {
    #         'output_dir': str(BASE_DIR / 'data-bak'),
    #         'filename_prefix': 'db-backup',
    #     },
    # },
    # 'daily_settlement': {
    #     'task': 'settlement.tasks.run_daily_settlement',
    #     'schedule': crontab(
    #         hour=SETTLEMENT_RUN_HOUR,
    #         minute=SETTLEMENT_RUN_MINUTE
    #     ),
    # },
    # 'daily_plate_order_tiia_image_upload': {
    #     'task': 'printing.tasks.upload_yesterday_plate_order_images_to_tencent_tiia',
    #     'schedule': crontab(hour=3, minute=0),
    # },
    # 'daily_mdy_plate_order_staging_tiia_image_upload': {
    #     'task': 'api_v1.tasks.upload_mdy_plate_order_staging_images_to_tencent_tiia',
    #     'schedule': crontab(hour=3, minute=20),
    #     'kwargs': {
    #         'batch_size': 500,
    #         'dry_run': False,
    #     },
    # },
    # 'mdy_product_sync': {
    #     'task': 'api_v1.tasks.sync_mdy_products',
    #     'schedule': crontab(minute='*/10'),
    #     'kwargs': {
    #         'page_size': MDY_SYNC_PAGE_SIZE,
    #         'max_pages': MDY_SYNC_MAX_PAGES,
    #         'max_records': MDY_SYNC_MAX_RECORDS,
    #     },
    # },
    # 'mdy_customer_sync': {
    #     'task': 'api_v1.tasks.sync_mdy_customers',
    #     'schedule': crontab(minute='*/5'),
    #     'kwargs': {
    #         'page_size': MDY_SYNC_PAGE_SIZE,
    #         'max_pages': MDY_SYNC_MAX_PAGES,
    #         'max_records': MDY_SYNC_MAX_RECORDS,
    #     },
    # },
    # 'printing_external_records_sync': {
    #     'task': 'api_v1.tasks.sync_external_printing_records',
    #     'schedule': crontab(minute='*/5'),
    #     'kwargs': {
    #         'limit': 100,
    #     },
    # },
    # 'notify_unreplied_missions_every_minute': {
    #     'task': 'notifier.tasks.notify_unreplied_missions_task',
    #     'schedule': crontab(minute='*'),
    #     'kwargs': {
    #         'limit': 100,
    #     },
    # },
    # 'backfill_external_product_images_hourly': {
    #     'task': 'api_v1.tasks.backfill_external_product_images',
    #     'schedule': crontab(minute=17),
    #     'kwargs': {
    #         'limit': 500,
    #         'dry_run': False,
    #     },
    # },
    # 'retry_external_printing_sync_failures_every_120_minutes': {
    #     'task': 'api_v1.tasks.retry_external_printing_sync_failures',
    #     'schedule': crontab(minute='0', hour='*/2'),
    #     'kwargs': {
    #         'limit': 100,
    #     },
    # },
    # 外部财务同步：每天凌晨 5 点同步指定客户列表的对账数据
    'sync_external_customer_finance_daily': {
        'task': 'business.tasks.sync_external_customer_finance_scheduled',
        'schedule': crontab(hour=5, minute=0),
    },
    # 明道云开版：同步到“暂存表”
    # - 仅在 02:00-08:00 时间窗内持续运行（每 N 分钟触发一次）
    # - 通过 request_interval_seconds 控制单次任务对明道云 API 的请求节奏，避免超 QPS
    # 'mdy_plate_order_staging_sync': {
    #     'task': 'api_v1.tasks.sync_mdy_plate_orders',
    #     # 02:00 - 07:59（不包含 08:xx）
    #     'schedule': crontab(minute='*/2', hour='2-7'),
    #     'kwargs': {
    #         'page_size': max(1, int(MDY_SYNC_PAGE_SIZE)),
    #         'max_pages': max(1, int(MDY_SYNC_MAX_PAGES)),
    #         'max_records': max(1, int(MDY_SYNC_MAX_RECORDS)),
    #         'with_related': True,
    #         'max_related_per_type': 5,
    #         'request_interval_seconds': float(MDY_PLATE_ORDER_SYNC_REQUEST_INTERVAL_SECONDS),
    #     },
    # },
}

if MDY_ISOLATED_MERCHANT_ID and MDY_ISOLATED_MERCHANT_ID > 0:
    CELERY_BEAT_SCHEDULE.update(
        {
            # 'mdy_product_sync_isolated': {
            #     'task': 'api_v1.tasks.sync_mdy_products_for_merchant',
            #     'schedule': crontab(minute='3,13,23,33,43,53'),
            #     'kwargs': {
            #         'merchant_id': MDY_ISOLATED_MERCHANT_ID,
            #         'page_size': MDY_SYNC_PAGE_SIZE,
            #         'max_pages': MDY_SYNC_MAX_PAGES,
            #         'max_records': MDY_SYNC_MAX_RECORDS,
            #     },
            # },
            # 'mdy_customer_sync_isolated': {
            #     'task': 'api_v1.tasks.sync_mdy_customers_for_merchant',
            #     'schedule': crontab(minute='1,11,21,31,41,51'),
            #     'kwargs': {
            #         'merchant_id': MDY_ISOLATED_MERCHANT_ID,
            #         'page_size': MDY_SYNC_PAGE_SIZE,
            #         'max_pages': MDY_SYNC_MAX_PAGES,
            #         'max_records': MDY_SYNC_MAX_RECORDS,
            #     },
            # },
            # 'mdy_plate_order_staging_sync_isolated': {
            #     'task': 'api_v1.tasks.sync_mdy_plate_orders_for_merchant',
            #     'schedule': crontab(minute='*/2', hour='8-11'),
            #     'kwargs': {
            #         'merchant_id': MDY_ISOLATED_MERCHANT_ID,
            #         'page_size': max(1, int(MDY_SYNC_PAGE_SIZE)),
            #         'max_pages': max(1, int(MDY_SYNC_MAX_PAGES)),
            #         'max_records': max(1, int(MDY_SYNC_MAX_RECORDS)),
            #         'with_related': True,
            #         'max_related_per_type': 5,
            #         'request_interval_seconds': float(MDY_PLATE_ORDER_SYNC_REQUEST_INTERVAL_SECONDS),
            #     },
            # },
        }
    )
