# -*- coding: utf-8 -*-
"""
Django settings for myproject project with django-tenants support.

This is a multi-tenant SaaS application where each shop owner gets their own subdomain
and isolated database schema.

Example: shop1.inventory.by, shop2.inventory.by
"""

from pathlib import Path
import os
import environ

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

# Initialize environment variables
env = environ.Env(
    # Set casting and default values
    DEBUG=(bool, True),  # Debug mode enabled
    SECRET_KEY=(str, 'django-insecure-default-key-change-in-production'),
)

# Read .env file (if exists - for local development)
# In Docker, environment variables are set via docker-compose env_file
env_file = BASE_DIR / '.env'
if env_file.exists():
    environ.Env.read_env(env_file)


# 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')

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

# Allowed hosts: принудительно разрешаем все для корректной работы поддоменов
ALLOWED_HOSTS = ['*']

# CSRF configuration
CSRF_TRUSTED_ORIGINS = env.list('CSRF_TRUSTED_ORIGINS', default=[
    'https://mix.smaa.by',
    'https://*.mix.smaa.by',
])
CSRF_USE_SESSIONS = True  # Рекомендуется для мультихостовых систем


# ============================================
# DJANGO-TENANTS CONFIGURATION
# ============================================

# Shared apps: доступны в public схеме (общие для всей системы)
SHARED_APPS = [
    'django_tenants',  # ОБЯЗАТЕЛЬНО ПЕРВЫМ!
    'tenants',  # Приложение с моделями тенантов
    'platform_admin',  # Администраторы платформы (отдельная модель от CustomUser)

    # Django встроенные приложения
    'django.contrib.contenttypes',
    'django.contrib.auth',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.admin',
    'django.contrib.staticfiles',

    # Celery results (для сохранения статуса асинхронных задач)
    'django_celery_results',
]

# Tenant apps: создаются в отдельной схеме для каждого тенанта (изолированные данные)
TENANT_APPS = [
    'django.contrib.contenttypes',  # Дублируем для tenant схем
    'django.contrib.auth',           # Дублируем для tenant схем

    # CustomUser - TENANT-ONLY модель!
    # Каждый тенант имеет свою таблицу accounts_customuser в своей схеме
    # Один email в разных тенантах = разные пользователи (полная изоляция)
    'accounts',

    # Приложения с бизнес-логикой (изолированные для каждого магазина)
    'nested_admin',
    'django_filters',  # Фильтрация данных
    'user_roles',    # Роли пользователей
    'customers',     # Клиенты магазина
    'products',      # Товары и категории
    'orders',        # Заказы
    'inventory',     # Складской учет
    'pos',           # POS Terminal
    'discounts',     # Скидки и промокоды
    'system_settings',  # Системные настройки компании (только для владельца)
    'integrations',  # Интеграции с внешними сервисами
    # TODO: 'simple_history' - вернуть позже для истории изменений
]

# Объединяем для INSTALLED_APPS
INSTALLED_APPS = list(SHARED_APPS) + [app for app in TENANT_APPS if app not in SHARED_APPS]

# Django Debug Toolbar (должен быть в SHARED_APPS для работы django-tenants)
if DEBUG_TOOLBAR_ENABLED:
    if 'debug_toolbar' not in SHARED_APPS:
        SHARED_APPS.append('debug_toolbar')
    # Пересобираем INSTALLED_APPS с учетом тулбара
    INSTALLED_APPS = list(SHARED_APPS) + [app for app in TENANT_APPS if app not in SHARED_APPS]

# Модели тенанта и домена
TENANT_MODEL = "tenants.Client"
TENANT_DOMAIN_MODEL = "tenants.Domain"

# Показывать tenant_id в логах (полезно для отладки)
SHOW_PUBLIC_IF_NO_TENANT_FOUND = True


# ============================================
# MIDDLEWARE
# ============================================

MIDDLEWARE = [
    'django_tenants.middleware.main.TenantMainMiddleware',  # 1. Обязательно первым!
    'django.middleware.security.SecurityMiddleware',         # 2. Безопасность (HTTPS и заголовки)
    'whitenoise.middleware.WhiteNoiseMiddleware',           # 3. Статика (после безопасности)
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware', # 4. Определение пользователя
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'simple_history.middleware.HistoryRequestMiddleware',
]

# Django Debug Toolbar Middleware
if DEBUG_TOOLBAR_ENABLED:
    MIDDLEWARE.append('debug_toolbar.middleware.DebugToolbarMiddleware')


# ============================================
# AUTHENTICATION BACKENDS
# ============================================

# Authentication backends для изолированной аутентификации
# ВАЖНО: Порядок важен! Django пробует backends по очереди до первого успеха
AUTHENTICATION_BACKENDS = [
    # 1. PlatformAdmin - администраторы платформы (public schema)
    # Работает на public домене, а также на tenant доменах для суперадминов (поддержка)
    'platform_admin.backends.PlatformAdminBackend',

    # 2. CustomUser - пользователи тенантов (tenant schema)
    # Работает ТОЛЬКО на tenant доменах, ищет пользователя в текущей schema
    'accounts.backends.TenantUserBackend',

    # 3. Ролевой backend для проверки permissions (работает с RoleService)
    'user_roles.auth_backend.RoleBasedPermissionBackend',
]


# ============================================
# URL CONFIGURATION
# ============================================

ROOT_URLCONF = 'myproject.urls'

# URL-конфигурация для public схемы (главный домен inventory.by)
PUBLIC_SCHEMA_URLCONF = 'myproject.urls_public'


SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
USE_X_FORWARDED_HOST = True



# ============================================
# TEMPLATES
# ============================================

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],
        '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 = 'myproject.wsgi.application'


# ============================================
# DATABASE CONFIGURATION
# ============================================

DATABASES = {
    'default': {
        'ENGINE': 'django_tenants.postgresql_backend',  # ВАЖНО: используем backend от django-tenants
        'NAME': env('DB_NAME'),
        'USER': env('DB_USER'),
        'PASSWORD': env('DB_PASSWORD'),
        'HOST': env('DB_HOST'),
        'PORT': env('DB_PORT'),
        'OPTIONS': {
            'client_encoding': 'UTF8',
        },
        'CONN_MAX_AGE': 0,
    }
}

# Database router для django-tenants
DATABASE_ROUTERS = [
    'django_tenants.routers.TenantSyncRouter',
]


# ============================================
# PASSWORD VALIDATION
# ============================================

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
# ============================================

LANGUAGE_CODE = 'ru-ru'
TIME_ZONE = 'Europe/Minsk'
USE_I18N = True
USE_TZ = True


# ============================================
# DOMAIN SETTINGS (for multi-tenant URLs)
# ============================================

# Главный домен приложения (без схемы http/https)
# Локально: localhost:8000, в проде: mix.smaa.by
TENANT_DOMAIN_BASE = env('TENANT_DOMAIN_BASE', default='localhost:8000')

# Использовать HTTPS для ссылок (в проде True, локально False)
USE_HTTPS = env.bool('USE_HTTPS', default=False)


# ============================================
# SESSION CONFIGURATION
# ============================================

# Время жизни сессии: 7 дней (в секундах)
# SECURITY: Сокращено с 28 до 7 дней для уменьшения окна атаки
SESSION_COOKIE_AGE = 604800  # 7 дней

# Продлевать сессию при каждом запросе (токен не устареет, если пользователь активен)
SESSION_SAVE_EVERY_REQUEST = True

# Время жизни CSRF cookie (привязан к сессии, но можно увеличить отдельно)
# 1 год для удобства пользователей
CSRF_COOKIE_AGE = 31449600

# Настройки безопасности куки (универсально для локала и сервера)
CSRF_COOKIE_SECURE = USE_HTTPS
SESSION_COOKIE_SECURE = USE_HTTPS
CSRF_COOKIE_HTTPONLY = True
SESSION_COOKIE_HTTPONLY = True

# SECURITY: SameSite защита от CSRF атак
# Lax - позволяет работать с поддоменами, но защищает от внешних сайтов
SESSION_COOKIE_SAMESITE = 'Lax'
CSRF_COOKIE_SAMESITE = 'Lax'


# ============================================
# STATIC FILES (CSS, JavaScript, Images)
# ============================================

STATIC_URL = '/static/'
STATICFILES_DIRS = [BASE_DIR / 'static']

# В production используем внешнюю директорию для nginx
# В Docker контейнере BASE_DIR = /app, но структура проекта: /app/myproject/
# Поэтому STATIC_ROOT должен быть /app/myproject/staticfiles
if str(BASE_DIR) == '/app':  # В Docker контейнере
    STATIC_ROOT = BASE_DIR / 'myproject' / 'staticfiles'
else:  # Локальная разработка
    STATIC_ROOT = BASE_DIR / 'staticfiles'

# Whitenoise storage
STORAGES = {
    "default": {
        "BACKEND": "products.utils.storage.TenantAwareFileSystemStorage",
    },
    "staticfiles": {
        "BACKEND": "whitenoise.storage.CompressedStaticFilesStorage",
    },
}


# ============================================
# MEDIA FILES (User uploads)
# ============================================

MEDIA_URL = '/media/'
# MEDIA_ROOT должен соответствовать монтированию volume в docker-compose.yml
# На проде в Docker: /app/myproject/media (BASE_DIR = /app)
# Локально: BASE_DIR / 'media' (BASE_DIR = путь к проекту)
if os.environ.get('MEDIA_ROOT'):
    MEDIA_ROOT = Path(os.environ.get('MEDIA_ROOT'))
elif str(BASE_DIR) == '/app':  # В Docker контейнере
    MEDIA_ROOT = BASE_DIR / 'myproject' / 'media'
else:  # Локальная разработка
    MEDIA_ROOT = BASE_DIR / 'media'



# Время жизни временных файлов фото (TTL) до авто-удаления, в часах
TEMP_MEDIA_TTL_HOURS = 24


# ============================================
# IMAGE PROCESSING SETTINGS
# ============================================

IMAGE_PROCESSING_CONFIG = {
    'formats': {
        'original': {
            'format': 'JPEG',
            'quality': 100,
            'max_width': 2160,
            'max_height': 2160,
            'description': 'Original image (4K max, JPEG format)'
        },
        'large': {
            'format': 'WEBP',
            'quality': 90,
            'width': 1200,
            'height': 1200,
            'description': 'Large image (1200x1200, WebP format)'
        },
        'medium': {
            'format': 'WEBP',
            'quality': 85,
            'width': 600,
            'height': 600,
            'description': 'Medium image (600x600, WebP format)'
        },
        'thumbnail': {
            'format': 'WEBP',
            'quality': 80,
            'width': 200,
            'height': 200,
            'description': 'Thumbnail (200x200, WebP format)'
        },
    }
}


# ============================================
# IMAGE QUALITY ASSESSMENT SETTINGS
# ============================================

# Пороги качества как доля от максимального размера оригинала (0.0 - 1.0)
# Вычисляется динамически: if image_size >= threshold * max_original_size → quality_level
#
# Пример: если max_width=2160, то:
# - excellent: >= 2052px (95% * 2160)
# - good: >= 1512px (70% * 2160)
# - acceptable: >= 864px (40% * 2160)
# - poor: >= 432px (20% * 2160)
# - very_poor: < 432px
IMAGE_QUALITY_LEVELS = {
    'excellent': 0.95,      # 95% от максимума
    'good': 0.70,           # 70% от максимума
    'acceptable': 0.40,     # 40% от максимума
    'poor': 0.20,           # 20% от максимума
    # < 20% = very_poor
}

# Описания и рекомендации для каждого уровня качества
# Используется в админке, формах и API
IMAGE_QUALITY_LABELS = {
    'excellent': {
        'label': 'Отлично',
        'short_label': 'Отлично ✓',
        'description': 'Идеальное качество изображения',
        'color': 'success',
        'icon': '✓',
        'recommendation': 'Готово для выгрузки на сайт',
        'badge_class': 'badge-success',
    },
    'good': {
        'label': 'Хорошо',
        'short_label': 'Хорошо ◐',
        'description': 'Хорошее качество изображения',
        'color': 'info',
        'icon': '◐',
        'recommendation': 'Можно выгружать на сайт',
        'badge_class': 'badge-info',
    },
    'acceptable': {
        'label': 'Приемлемо',
        'short_label': 'Приемлемо ⚠',
        'description': 'Приемлемое качество, но рекомендуется обновить',
        'color': 'warning',
        'icon': '⚠',
        'recommendation': 'Лучше обновить перед выгрузкой на сайт',
        'badge_class': 'badge-warning',
    },
    'poor': {
        'label': 'Плохо',
        'short_label': 'Плохо ✗',
        'description': 'Низкое качество изображения',
        'color': 'danger',
        'icon': '✗',
        'recommendation': 'Требует обновления перед выгрузкой на сайт',
        'badge_class': 'badge-danger',
    },
    'very_poor': {
        'label': 'Очень плохо',
        'short_label': 'Очень плохо ✗✗',
        'description': 'Очень низкое качество изображения',
        'color': 'danger',
        'icon': '✗✗',
        'recommendation': 'Обязательно обновить перед любой выгрузкой',
        'badge_class': 'badge-danger',
    },
}


# ============================================
# BUSINESS LOGIC SETTINGS
# ============================================

# Максимальная глубина вложенности категорий товаров
MAX_CATEGORY_DEPTH = 10

# Настройки телефонных номеров
PHONENUMBER_DEFAULT_REGION = 'BY'





# ============================================
# DJANGO DEBUG TOOLBAR SETTINGS
# ============================================

# Улучшенный блок INTERNAL_IPS (для Docker и локальной разработки)
if DEBUG_TOOLBAR_ENABLED:
    import socket
    INTERNAL_IPS = ['127.0.0.1', '10.0.2.2', 'localhost']
    
    try:
        # Получаем все IP хоста (контейнера)
        hostname, _, ips = socket.gethostbyname_ex(socket.gethostname())
        for ip_str in ips:
            try:
                # Для IPv4: заменяем последний октет на 1 (шлюз Docker)
                if '.' in ip_str:
                    parts = ip_str.split('.')
                    if len(parts) == 4:
                        gateway_ip = '.'.join(parts[:3] + ['1'])
                        INTERNAL_IPS.append(gateway_ip)
                    
                    # Возможные шлюзы и алиасы
                    INTERNAL_IPS.extend([
                        '.'.join(parts[:3] + ['254']),
                        'host.docker.internal',
                    ])
            except (ValueError, AttributeError):
                continue
    except Exception as e:
        print(f"Debug Info: Could not determine Docker gateway IPs: {e}")

    # Конфигурация Debug Toolbar
    DEBUG_TOOLBAR_CONFIG = {
        'SHOW_TOOLBAR_CALLBACK': lambda request: DEBUG_TOOLBAR_ENABLED,
        'IS_RUNNING_TESTS': False,
    }


# ============================================
# EMAIL SETTINGS
# ============================================

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
DEFAULT_FROM_EMAIL = 'noreply@inventory.by'


# ============================================
# AUTHENTICATION
# ============================================

# AUTH_USER_MODEL указывает на PlatformAdmin (public schema)
# Это нужно для django.contrib.admin.LogEntry и других Django-компонентов
# CustomUser живёт в TENANT_APPS и НЕ является AUTH_USER_MODEL
AUTH_USER_MODEL = 'platform_admin.PlatformAdmin'


# ============================================
# DEFAULT SETTINGS
# ============================================

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'


# ============================================
# CACHE CONFIGURATION (Redis)
# ============================================

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.redis.RedisCache',
        'LOCATION': f'redis://{env("REDIS_HOST", default="localhost")}:{env("REDIS_PORT", default="6379")}/{env("REDIS_DB", default="0")}',
        'KEY_PREFIX': 'myproject',  # Префикс для всех ключей
        'TIMEOUT': 300,  # Таймаут по умолчанию (5 минут)
    }
}


# ============================================
# CELERY CONFIGURATION
# ============================================

# Redis broker и backend для хранения результатов
CELERY_BROKER_URL = f'redis://{env("REDIS_HOST", default="localhost")}:{env("REDIS_PORT", default="6379")}/{env("REDIS_DB", default="0")}'
CELERY_RESULT_BACKEND = 'django-db'  # Сохраняем результаты в БД (совместимо с мультитенантностью)

# Сериализация
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = TIME_ZONE

# Task routing для разделения нагрузки
CELERY_TASK_ROUTES = {
    'products.tasks.process_product_photo_async': {'queue': 'photo_processing'},
    'products.tasks.process_multiple_photos_async': {'queue': 'photo_processing'},
    'products.tasks.cleanup_temp_media_for_schema': {'queue': 'photo_processing'},
    'products.tasks.cleanup_temp_media_all': {'queue': 'photo_processing'},
}

# Worker настройки для обработки длительных задач
CELERY_WORKER_PREFETCH_MULTIPLIER = 1  # Worker берет по одной задаче за раз
CELERY_TASK_ACKS_LATE = True  # Подтверждаем задачу только после успешного выполнения
CELERY_WORKER_MAX_TASKS_PER_CHILD = 50  # Перезапускаем worker после 50 задач (защита от утечек памяти PIL)

# Timeouts
CELERY_TASK_TIME_LIMIT = 300  # 5 минут максимум на одну задачу
CELERY_TASK_SOFT_TIME_LIMIT = 240  # 4 минуты - мягкий лимит перед жестким

# Результаты и события
CELERY_RESULT_EXPIRES = 3600  # Результаты хранятся 1 час (достаточно для отслеживания прогресса)
CELERY_WORKER_SEND_TASK_EVENTS = True  # Отправляем события для мониторинга
CELERY_TASK_SEND_SENT_EVENT = True

# Retry настройки
CELERY_TASK_DEFAULT_MAX_RETRIES = 3
CELERY_TASK_DEFAULT_RETRY_DELAY = 60  # Повторить через 60 секунд при ошибке

# Celery Beat Schedule (периодические задачи)
# Store schedule in /tmp to avoid PermissionError in Docker volumes
CELERY_BEAT_SCHEDULE_FILENAME = os.path.join('/tmp', 'celerybeat-schedule')

from celery.schedules import crontab

CELERY_BEAT_SCHEDULE = {
    # Очистка истекших блокировок корзины каждые 5 минут
    'cleanup-expired-cart-locks': {
        'task': 'inventory.tasks.cleanup_expired_cart_locks',
        'schedule': crontab(minute='*/5'),  # Каждые 5 минут
        'options': {
            'expires': 240,  # Задача устаревает через 4 минуты (меньше интервала)
        },
    },
    # Очистка временных файлов фото каждые 6 часов
    'cleanup-temp-media-all-tenants': {
        'task': 'products.tasks.cleanup_temp_media_all',
        'schedule': crontab(minute=0, hour='*/6'),  # Каждые 6 часов
        'options': {
            'queue': 'photo_processing',
        },
    },
    # Очистка устаревших файлов ошибок импорта клиентов каждый день в полночь
    'delete-old-import-error-files-every-24-hours': {
        'task': 'customers.tasks.delete_old_import_error_files',
        'schedule': crontab(hour=0, minute=0),  # Запускать каждый день в полночь
    },
}

# ============================================
# DATA UPLOAD SETTINGS
# ============================================

# Увеличиваем лимиты для загрузки больших списков (10 000+ клиентов)
DATA_UPLOAD_MAX_NUMBER_FIELDS = 50000
DATA_UPLOAD_MAX_MEMORY_SIZE = 104857600  # 100MB


# ============================================
# ENCRYPTION SETTINGS (for sensitive data like API tokens)
# ============================================

# Ключ шифрования для EncryptedCharField (Fernet AES-128)
# ВАЖНО: Сгенерировать один раз и сохранить в .env!
# python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
ENCRYPTION_KEY = env('ENCRYPTION_KEY', default=None)

# Проверка наличия ключа в production
if not DEBUG and not ENCRYPTION_KEY:
    import warnings
    warnings.warn(
        "ENCRYPTION_KEY not set! Encrypted fields will fail. "
        "Generate with: python -c \"from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())\""
    )


