# app/modules/core/services/platform_settings_service.py
"""
Platform Settings Service

Provides access to platform-wide settings with a resolution chain:
1. AdminSetting from database (can be set via admin UI)
2. Environment variables (from .env/config)
3. Hardcoded defaults

This allows admins to override defaults without code changes,
while still supporting environment-based configuration.
"""

from __future__ import annotations

import logging
from typing import Any

from sqlalchemy.orm import Session

from app.core.config import settings

logger = logging.getLogger(__name__)


class PlatformSettingsService:
    """
    Service for accessing platform-wide settings.

    Resolution order:
    1. AdminSetting in database (highest priority)
    2. Environment variable via config
    3. Hardcoded default (lowest priority)
    """

    # Mapping of setting keys to their config attribute names and defaults
    SETTINGS_MAP = {
        "default_storefront_locale": {
            "config_attr": "default_storefront_locale",
            "default": "fr-LU",
            "description": "Default locale for currency/number formatting (e.g., fr-LU, de-DE)",
            "category": "storefront",
        },
        "default_currency": {
            "config_attr": "default_currency",
            "default": "EUR",
            "description": "Default currency code for the platform",
            "category": "storefront",
        },
    }

    def get(self, db: Session, key: str) -> str | None:
        """
        Get a setting value with full resolution chain.

        Args:
            db: Database session
            key: Setting key (e.g., 'default_storefront_locale')

        Returns:
            Setting value or None if not found
        """
        # 1. Check AdminSetting in database
        from app.modules.tenancy.models import AdminSetting

        admin_setting = db.query(AdminSetting).filter_by(key=key).first()
        if admin_setting and admin_setting.value:
            logger.debug(f"Setting '{key}' resolved from AdminSetting: {admin_setting.value}")
            return admin_setting.value

        # 2. Check environment/config
        setting_info = self.SETTINGS_MAP.get(key)
        if setting_info:
            config_attr = setting_info.get("config_attr")
            if config_attr and hasattr(settings, config_attr):
                value = getattr(settings, config_attr)
                logger.debug(f"Setting '{key}' resolved from config: {value}")
                return value

            # 3. Return hardcoded default
            default = setting_info.get("default")
            logger.debug(f"Setting '{key}' resolved from default: {default}")
            return default

        logger.warning(f"Unknown setting key: {key}")
        return None

    def get_storefront_locale(self, db: Session) -> str:
        """Get the default storefront locale."""
        return self.get(db, "default_storefront_locale") or "fr-LU"

    def get_currency(self, db: Session) -> str:
        """Get the default currency."""
        return self.get(db, "default_currency") or "EUR"

    def get_storefront_config(self, db: Session) -> dict[str, str]:
        """
        Get all storefront-related settings as a dict.

        Returns:
            Dict with 'locale' and 'currency' keys
        """
        return {
            "locale": self.get_storefront_locale(db),
            "currency": self.get_currency(db),
        }

    def set(self, db: Session, key: str, value: str, user_id: int | None = None) -> AdminSetting:
        """
        Set a platform setting in the database.

        Args:
            db: Database session
            key: Setting key
            value: Setting value
            user_id: ID of user making the change (for audit)

        Returns:
            The created/updated AdminSetting
        """
        from app.modules.tenancy.models import AdminSetting

        setting_info = self.SETTINGS_MAP.get(key, {})

        admin_setting = db.query(AdminSetting).filter_by(key=key).first()
        if admin_setting:
            admin_setting.value = value
            if user_id:
                admin_setting.last_modified_by_user_id = user_id
        else:
            admin_setting = AdminSetting(
                key=key,
                value=value,
                value_type="string",
                category=setting_info.get("category", "system"),
                description=setting_info.get("description", ""),
                last_modified_by_user_id=user_id,
            )
            db.add(admin_setting)

        db.commit()  # SVC-006 - Setting change is atomic, commit is intentional
        db.refresh(admin_setting)

        logger.info(f"Platform setting '{key}' set to '{value}' by user {user_id}")
        return admin_setting

    def get_all_storefront_settings(self, db: Session) -> dict[str, Any]:
        """
        Get all storefront settings with their current values and metadata.

        Useful for admin UI to display current settings.

        Returns:
            Dict with setting info including current value and source
        """
        result = {}
        for key, info in self.SETTINGS_MAP.items():
            if info.get("category") == "storefront":
                current_value = self.get(db, key)

                # Determine source
                from app.modules.tenancy.models import AdminSetting

                admin_setting = db.query(AdminSetting).filter_by(key=key).first()
                if admin_setting and admin_setting.value:
                    source = "database"
                elif hasattr(settings, info.get("config_attr", "")):
                    source = "environment"
                else:
                    source = "default"

                result[key] = {
                    "value": current_value,
                    "source": source,
                    "description": info.get("description", ""),
                    "default": info.get("default"),
                }

        return result


# Singleton instance
platform_settings_service = PlatformSettingsService()
