"""
Module Settings — Schema Registry

سیستم ثبت و مدیریت schema تنظیمات ماژول‌ها.
هر ماژول schema خود را اینجا ثبت می‌کند.
"""
from typing import Any

from .domain import SettingsSchemaDefinition
from .exceptions import ModuleSchemaNotRegistered


class SettingsSchemaRegistry:
    """
    Singleton registry برای schema تنظیمات ماژول‌ها.

    هر ماژول باید schema تنظیمات خود را هنگام ready() ثبت کند.
    """

    _instance = None
    _schemas: dict[str, SettingsSchemaDefinition] = {}

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._schemas = {}
        return cls._instance

    def register(self, schema: SettingsSchemaDefinition) -> None:
        """
        ثبت schema تنظیمات یک ماژول.

        Args:
            schema: تعریف schema تنظیمات
        """
        self._schemas[schema.module_key] = schema

    def unregister(self, module_key: str) -> None:
        """
        حذف schema یک ماژول.

        Args:
            module_key: کلید ماژول
        """
        self._schemas.pop(module_key, None)

    def get_schema(self, module_key: str) -> SettingsSchemaDefinition:
        """
        دریافت schema تنظیمات یک ماژول.

        Args:
            module_key: کلید ماژول

        Returns:
            تعریف schema

        Raises:
            ModuleSchemaNotRegistered: اگر schema ثبت نشده باشد
        """
        if module_key not in self._schemas:
            raise ModuleSchemaNotRegistered(module_key)
        return self._schemas[module_key]

    def has_schema(self, module_key: str) -> bool:
        """آیا schema برای ماژول ثبت شده است؟"""
        return module_key in self._schemas

    def list_schemas(self) -> list[SettingsSchemaDefinition]:
        """لیست تمام schema‌های ثبت‌شده."""
        return list(self._schemas.values())

    def list_module_keys(self) -> list[str]:
        """لیست کلید تمام ماژول‌های دارای schema."""
        return list(self._schemas.keys())

    def get_defaults(self, module_key: str) -> dict[str, Any]:
        """
        دریافت مقادیر پیش‌فرض schema یک ماژول.

        Args:
            module_key: کلید ماژول

        Returns:
            دیکشنری مقادیر پیش‌فرض
        """
        schema = self.get_schema(module_key)
        return schema.get_default_values()

    def validate_data(self, module_key: str, data: dict[str, Any]) -> dict[str, list[str]]:
        """
        اعتبارسنجی دیتای تنظیمات بر اساس schema.

        Args:
            module_key: کلید ماژول
            data: دیکشنری تنظیمات

        Returns:
            دیکشنری خطاها (خالی = معتبر)
        """
        schema = self.get_schema(module_key)
        errors: dict[str, list[str]] = {}

        for section in schema.sections:
            section_data = data.get(section.key, {})
            if not isinstance(section_data, dict):
                errors[section.key] = ["باید یک دیکشنری باشد"]
                continue

            for f in section.fields:
                value = section_data.get(f.key)
                field_path = f"{section.key}.{f.key}"

                # Required check
                if f.required and value is None:
                    errors[field_path] = [f"فیلد {f.label} الزامی است"]
                    continue

                if value is None:
                    continue

                # Type check
                field_errors = self._validate_field_value(f, value)
                if field_errors:
                    errors[field_path] = field_errors

        return errors

    @staticmethod
    def _validate_field_value(field_def, value) -> list[str]:
        """اعتبارسنجی مقدار یک فیلد."""
        errors = []
        type_map = {
            "bool": bool,
            "int": int,
            "float": (int, float),
            "str": str,
            "select": str,
            "multi_select": list,
        }

        expected_type = type_map.get(field_def.field_type)
        if expected_type and not isinstance(value, expected_type):
            errors.append(f"نوع مقدار باید {field_def.field_type} باشد")
            return errors

        # Range checks
        if field_def.field_type in ("int", "float") and isinstance(value, (int, float)):
            if field_def.min_value is not None and value < field_def.min_value:
                errors.append(f"مقدار نباید کمتر از {field_def.min_value} باشد")
            if field_def.max_value is not None and value > field_def.max_value:
                errors.append(f"مقدار نباید بیشتر از {field_def.max_value} باشد")

        # Select option check
        if field_def.field_type == "select" and field_def.options:
            valid_values = [opt.get("value") for opt in field_def.options]
            if value not in valid_values:
                errors.append(f"مقدار '{value}' معتبر نیست")

        # Multi-select option check
        if field_def.field_type == "multi_select" and field_def.options:
            valid_values = [opt.get("value") for opt in field_def.options]
            for item in value:
                if item not in valid_values:
                    errors.append(f"مقدار '{item}' معتبر نیست")

        return errors

    def schema_to_dict(self, module_key: str) -> dict[str, Any]:
        """
        تبدیل schema به dict برای ارسال به frontend.

        Args:
            module_key: کلید ماژول

        Returns:
            دیکشنری schema
        """
        # Map internal field types to frontend-compatible names
        type_map = {
            "bool": "boolean",
            "int": "integer",
            "float": "float",
            "str": "string",
            "select": "select",
            "multi_select": "multi_select",
        }

        schema = self.get_schema(module_key)
        return {
            "module_key": schema.module_key,
            "module_label": schema.label,
            "version": schema.version,
            "label": schema.label,
            "label_en": schema.label_en,
            "description": schema.description,
            "sections": [
                {
                    "key": s.key,
                    "label": s.label,
                    "label_en": s.label_en,
                    "description": s.description,
                    "icon": s.icon,
                    "order": s.order,
                    "fields": [
                        {
                            "key": f.key,
                            "type": type_map.get(f.field_type, f.field_type),
                            "field_type": f.field_type,
                            "label": f.label,
                            "label_en": f.label_en,
                            "description": f.description,
                            "default": f.default_value,
                            "default_value": f.default_value,
                            "required": f.required,
                            "options": f.options,
                            "min": f.min_value,
                            "max": f.max_value,
                            "min_value": f.min_value,
                            "max_value": f.max_value,
                            "depends_on": f.depends_on,
                        }
                        for f in s.fields
                    ],
                }
                for s in schema.sections
            ],
        }


# Global singleton instance
settings_schema_registry = SettingsSchemaRegistry()
