"""
Metadata Schema Service.
动态元数据模式管理服务，支持租户自定义元数据字段配置。
"""

import logging
import uuid
from datetime import datetime
from typing import Any

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import col

from app.models.entities import (
    MetadataField,
    MetadataFieldType,
    MetadataSchema,
    MetadataSchemaCreate,
    MetadataSchemaUpdate,
)

logger = logging.getLogger(__name__)


class MetadataSchemaService:
    """
    元数据模式服务
    管理租户的动态元数据字段配置
    """

    def __init__(self, session: AsyncSession):
        self._session = session

    async def get_schema(
        self,
        tenant_id: str,
        schema_id: str | None = None,
    ) -> MetadataSchema | None:
        """
        获取元数据模式
        
        Args:
            tenant_id: 租户 ID
            schema_id: 模式 ID（可选，不传则获取默认模式）
        
        Returns:
            MetadataSchema 或 None
        """
        if schema_id:
            stmt = select(MetadataSchema).where(
                MetadataSchema.tenant_id == tenant_id,
                MetadataSchema.id == uuid.UUID(schema_id),
            )
        else:
            stmt = select(MetadataSchema).where(
                MetadataSchema.tenant_id == tenant_id,
                MetadataSchema.is_default == True,
                MetadataSchema.is_enabled == True,
            ).order_by(col(MetadataSchema.created_at).desc())
        
        result = await self._session.execute(stmt)
        return result.scalar_one_or_none()

    async def list_schemas(
        self,
        tenant_id: str,
        include_disabled: bool = False,
    ) -> list[MetadataSchema]:
        """
        列出租户所有元数据模式
        
        Args:
            tenant_id: 租户 ID
            include_disabled: 是否包含禁用的模式
        
        Returns:
            MetadataSchema 列表
        """
        stmt = select(MetadataSchema).where(
            MetadataSchema.tenant_id == tenant_id,
        )
        if not include_disabled:
            stmt = stmt.where(MetadataSchema.is_enabled == True)
        
        stmt = stmt.order_by(col(MetadataSchema.created_at).desc())
        
        result = await self._session.execute(stmt)
        return list(result.scalars().all())

    async def create_schema(
        self,
        tenant_id: str,
        schema_create: MetadataSchemaCreate,
    ) -> MetadataSchema:
        """
        创建元数据模式
        
        Args:
            tenant_id: 租户 ID
            schema_create: 创建数据
        
        Returns:
            创建的 MetadataSchema
        """
        schema = MetadataSchema(
            tenant_id=tenant_id,
            name=schema_create.name,
            description=schema_create.description,
            fields=[f.model_dump() if hasattr(f, 'model_dump') else f for f in schema_create.fields],
            is_default=schema_create.is_default,
            is_enabled=True,
        )
        
        self._session.add(schema)
        await self._session.flush()
        
        logger.info(
            f"[MetadataSchemaService] Created schema: tenant={tenant_id}, "
            f"name={schema.name}, fields_count={len(schema.fields)}"
        )
        
        return schema

    async def update_schema(
        self,
        tenant_id: str,
        schema_id: str,
        schema_update: MetadataSchemaUpdate,
    ) -> MetadataSchema | None:
        """
        更新元数据模式
        
        Args:
            tenant_id: 租户 ID
            schema_id: 模式 ID
            schema_update: 更新数据
        
        Returns:
            更新后的 MetadataSchema 或 None
        """
        stmt = select(MetadataSchema).where(
            MetadataSchema.tenant_id == tenant_id,
            MetadataSchema.id == uuid.UUID(schema_id),
        )
        result = await self._session.execute(stmt)
        schema = result.scalar_one_or_none()
        
        if not schema:
            return None
        
        if schema_update.name is not None:
            schema.name = schema_update.name
        if schema_update.description is not None:
            schema.description = schema_update.description
        if schema_update.fields is not None:
            schema.fields = schema_update.fields
        if schema_update.is_default is not None:
            if schema_update.is_default:
                await self._unset_other_defaults(tenant_id, schema_id)
            schema.is_default = True
        if schema_update.is_enabled is not None:
            schema.is_enabled = schema_update.is_enabled
        
        schema.updated_at = datetime.utcnow()
        await self._session.flush()
        
        logger.info(
            f"[MetadataSchemaService] Updated schema: tenant={tenant_id}, "
            f"schema_id={schema_id}"
        )
        
        return schema

    async def delete_schema(
        self,
        tenant_id: str,
        schema_id: str,
    ) -> bool:
        """
        删除元数据模式
        
        Args:
            tenant_id: 租户 ID
            schema_id: 模式 ID
        
        Returns:
            是否删除成功
        """
        stmt = select(MetadataSchema).where(
            MetadataSchema.tenant_id == tenant_id,
            MetadataSchema.id == uuid.UUID(schema_id),
        )
        result = await self._session.execute(stmt)
        schema = result.scalar_one_or_none()
        
        if not schema:
            return False
        
        if schema.is_default:
            logger.warning(
                f"[MetadataSchemaService] Cannot delete default schema: "
                f"tenant={tenant_id}, schema_id={schema_id}"
            )
            return False
        
        await self._session.delete(schema)
        await self._session.flush()
        
        logger.info(
            f"[MetadataSchemaService] Deleted schema: tenant={tenant_id}, "
            f"schema_id={schema_id}"
        )
        
        return True

    async def _unset_other_defaults(
        self,
        tenant_id: str,
        exclude_schema_id: str,
    ) -> None:
        """取消其他模式的默认状态"""
        stmt = select(MetadataSchema).where(
            MetadataSchema.tenant_id == tenant_id,
            MetadataSchema.is_default == True,
            MetadataSchema.id != uuid.UUID(exclude_schema_id),
        )
        result = await self._session.execute(stmt)
        other_schemas = result.scalars().all()
        
        for other in other_schemas:
            other.is_default = False

    async def get_field_definitions(
        self,
        tenant_id: str,
        schema_id: str | None = None,
    ) -> dict[str, dict[str, Any]]:
        """
        获取字段定义映射
        
        Args:
            tenant_id: 租户 ID
            schema_id: 模式 ID（可选）
        
        Returns:
            字段名到字段定义的映射，如 {"grade": {"label": "年级", "type": "select", "options": [...]}}
        """
        schema = await self.get_schema(tenant_id, schema_id)
        if not schema:
            return {}
        
        field_map = {}
        for field in schema.fields:
            field_name = field.get("name") if isinstance(field, dict) else field.name
            field_map[field_name] = field if isinstance(field, dict) else field.model_dump()
        
        return field_map

    async def validate_metadata(
        self,
        tenant_id: str,
        metadata: dict[str, Any],
        schema_id: str | None = None,
    ) -> tuple[bool, list[str]]:
        """
        验证元数据是否符合模式定义
        
        Args:
            tenant_id: 租户 ID
            metadata: 元数据字典
            schema_id: 模式 ID（可选）
        
        Returns:
            (是否有效, 错误消息列表)
        """
        field_defs = await self.get_field_definitions(tenant_id, schema_id)
        
        if not field_defs:
            return True, []
        
        errors = []
        
        for field_name, field_def in field_defs.items():
                field_type = field_def.get("field_type", "string")
                required = field_def.get("required", False)
                options = field_def.get("options", [])
                value = metadata.get(field_name)
                
                if required and value is None:
                    errors.append(f"字段 '{field_def.get('label', field_name)}' 是必填的")
                    continue
                
                if value is None:
                    continue
                
                if field_type == MetadataFieldType.SELECT.value:
                    if value not in options:
                        errors.append(
                            f"字段 '{field_def.get('label', field_name)}' 的值 '{value}' 不在允许选项中"
                        )
                
                elif field_type == MetadataFieldType.MULTI_SELECT.value:
                    if not isinstance(value, list):
                        errors.append(f"字段 '{field_def.get('label', field_name)}' 应该是多选值")
                    else:
                        for v in value:
                            if v not in options:
                                errors.append(
                                    f"字段 '{field_def.get('label', field_name)}' 的值 '{v}' 不在允许选项中"
                                )
                
                elif field_type == MetadataFieldType.NUMBER.value:
                    if not isinstance(value, (int, float)):
                        try:
                            float(value)
                        except (ValueError, TypeError):
                            errors.append(f"字段 '{field_def.get('label', field_name)}' 应该是数字")
                
                elif field_type == MetadataFieldType.BOOLEAN.value:
                    if not isinstance(value, bool):
                        if value not in ["true", "false", "1", "0", 1, 0]:
                            errors.append(f"字段 '{field_def.get('label', field_name)}' 应该是布尔值")
        
        return len(errors) == 0, errors
