"""
Metadata Field Definition Service.
[AC-IDSMETA-13, AC-IDSMETA-14] 元数据字段定义管理服务，支持字段级状态治理。
[AC-MRS-01, AC-MRS-02, AC-MRS-03, AC-MRS-06] 支持字段角色分层配置。
"""

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

from sqlalchemy import select, func, cast, text, any_
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import col

from app.models.entities import (
    MetadataFieldDefinition,
    MetadataFieldDefinitionCreate,
    MetadataFieldDefinitionUpdate,
    MetadataFieldStatus,
    MetadataFieldType,
    MetadataScope,
    FieldRole,
)
from app.schemas.metadata import VALID_FIELD_ROLES

logger = logging.getLogger(__name__)


class MetadataFieldDefinitionService:
    """
    [AC-IDSMETA-13] 元数据字段定义服务
    管理租户的动态元数据字段配置，支持字段级状态治理
    """

    FIELD_KEY_PATTERN = re.compile(r"^[a-z0-9_]+$")

    def __init__(self, session: AsyncSession):
        self._session = session
    
    async def _invalidate_cache(self, tenant_id: str) -> None:
        """
        清除租户的元数据字段缓存
        在字段创建、更新、删除时调用
        """
        try:
            from app.services.metadata_cache_service import get_metadata_cache_service
            cache_service = await get_metadata_cache_service()
            await cache_service.invalidate(tenant_id)
        except Exception as e:
            # 缓存失效失败不影响主流程
            logger.warning(f"[AC-IDSMETA-13] Failed to invalidate cache: {e}")

    async def list_field_definitions(
        self,
        tenant_id: str,
        status: str | None = None,
        scope: str | None = None,
        role: str | None = None,
    ) -> list[MetadataFieldDefinition]:
        """
        [AC-IDSMETA-13] [AC-MRS-06] 列出租户所有元数据字段定义
        
        Args:
            tenant_id: 租户 ID
            status: 按状态过滤（draft/active/deprecated）
            scope: 按适用范围过滤
            role: [AC-MRS-06] 按字段角色过滤
        
        Returns:
            MetadataFieldDefinition 列表
        """
        stmt = select(MetadataFieldDefinition).where(
            MetadataFieldDefinition.tenant_id == tenant_id,
        )
        
        if status:
            stmt = stmt.where(MetadataFieldDefinition.status == status)
        
        if scope:
            stmt = stmt.where(
                cast(MetadataFieldDefinition.scope, JSONB).op('?')(scope)
            )
        
        if role:
            stmt = stmt.where(
                cast(MetadataFieldDefinition.field_roles, JSONB).op('?')(role)
            )
        
        stmt = stmt.order_by(col(MetadataFieldDefinition.created_at).desc())
        
        result = await self._session.execute(stmt)
        return list(result.scalars().all())

    async def get_field_definition(
        self,
        tenant_id: str,
        field_id: str,
    ) -> MetadataFieldDefinition | None:
        """
        获取单个字段定义
        
        Args:
            tenant_id: 租户 ID
            field_id: 字段定义 ID
        
        Returns:
            MetadataFieldDefinition 或 None
        """
        stmt = select(MetadataFieldDefinition).where(
            MetadataFieldDefinition.tenant_id == tenant_id,
            MetadataFieldDefinition.id == uuid.UUID(field_id),
        )
        result = await self._session.execute(stmt)
        return result.scalar_one_or_none()

    async def get_field_definition_by_key(
        self,
        tenant_id: str,
        field_key: str,
    ) -> MetadataFieldDefinition | None:
        """
        通过 field_key 获取字段定义
        
        Args:
            tenant_id: 租户 ID
            field_key: 字段键名
        
        Returns:
            MetadataFieldDefinition 或 None
        """
        stmt = select(MetadataFieldDefinition).where(
            MetadataFieldDefinition.tenant_id == tenant_id,
            MetadataFieldDefinition.field_key == field_key,
        )
        result = await self._session.execute(stmt)
        return result.scalar_one_or_none()

    async def create_field_definition(
        self,
        tenant_id: str,
        field_create: MetadataFieldDefinitionCreate,
    ) -> MetadataFieldDefinition:
        """
        [AC-IDSMETA-13] [AC-MRS-01,02,03] 创建元数据字段定义
        
        Args:
            tenant_id: 租户 ID
            field_create: 创建数据
        
        Returns:
            创建的 MetadataFieldDefinition
        
        Raises:
            ValueError: 如果 field_key 已存在或格式不正确
        """
        if not self.FIELD_KEY_PATTERN.match(field_create.field_key):
            raise ValueError(
                f"field_key '{field_create.field_key}' 格式不正确，"
                "仅允许小写字母、数字和下划线"
            )
        
        existing = await self.get_field_definition_by_key(tenant_id, field_create.field_key)
        if existing:
            raise ValueError(f"field_key '{field_create.field_key}' 已存在")
        
        self._validate_field_type_and_options(
            field_create.type,
            field_create.options,
            field_create.field_key,
        )
        
        self._validate_field_roles(field_create.field_roles)
        
        field = MetadataFieldDefinition(
            tenant_id=tenant_id,
            field_key=field_create.field_key,
            label=field_create.label,
            type=field_create.type,
            required=field_create.required,
            options=field_create.options,
            default_value=field_create.default_value,
            scope=field_create.scope,
            is_filterable=field_create.is_filterable,
            is_rank_feature=field_create.is_rank_feature,
            field_roles=field_create.field_roles or [],
            status=field_create.status,
            version=1,
        )
        
        self._session.add(field)
        await self._session.flush()
        
        # 清除缓存，使新字段在下次查询时生效
        await self._invalidate_cache(tenant_id)
        
        logger.info(
            f"[AC-IDSMETA-13] [AC-MRS-01] Created field definition: tenant={tenant_id}, "
            f"field_key={field.field_key}, status={field.status}, field_roles={field.field_roles}"
        )
        
        return field

    async def update_field_definition(
        self,
        tenant_id: str,
        field_id: str,
        field_update: MetadataFieldDefinitionUpdate,
    ) -> MetadataFieldDefinition | None:
        """
        [AC-IDSMETA-14] 更新元数据字段定义
        
        Args:
            tenant_id: 租户 ID
            field_id: 字段定义 ID
            field_update: 更新数据
        
        Returns:
            更新后的 MetadataFieldDefinition 或 None
        """
        field = await self.get_field_definition(tenant_id, field_id)
        if not field:
            return None
        
        if field_update.label is not None:
            field.label = field_update.label
        if field_update.required is not None:
            field.required = field_update.required
        if field_update.options is not None:
            self._validate_field_type_and_options(field.type, field_update.options, field.field_key)
            field.options = field_update.options
        if field_update.default_value is not None:
            field.default_value = field_update.default_value
        if field_update.scope is not None:
            field.scope = field_update.scope
        if field_update.is_filterable is not None:
            field.is_filterable = field_update.is_filterable
        if field_update.is_rank_feature is not None:
            field.is_rank_feature = field_update.is_rank_feature
        # [AC-MRS-01] 修复：添加 field_roles 更新逻辑
        if field_update.field_roles is not None:
            self._validate_field_roles(field_update.field_roles)
            field.field_roles = field_update.field_roles
        if field_update.status is not None:
            old_status = field.status
            field.status = field_update.status
            logger.info(
                f"[AC-IDSMETA-14] Field status changed: tenant={tenant_id}, "
                f"field_key={field.field_key}, {old_status} -> {field.status}"
            )
        
        field.version += 1
        field.updated_at = datetime.utcnow()
        await self._session.flush()
        
        # 清除缓存，使更新在下次查询时生效
        await self._invalidate_cache(tenant_id)
        
        logger.info(
            f"[AC-IDSMETA-14] Updated field definition: tenant={tenant_id}, "
            f"field_id={field_id}, version={field.version}"
        )
        
        return field

    async def get_active_field_definitions(
        self,
        tenant_id: str,
        scope: str | None = None,
    ) -> list[MetadataFieldDefinition]:
        """
        [AC-IDSMETA-14] 获取活跃状态的字段定义（用于新建对象时选择）
        
        Args:
            tenant_id: 租户 ID
            scope: 按适用范围过滤
        
        Returns:
            状态为 active 的 MetadataFieldDefinition 列表
        """
        return await self.list_field_definitions(
            tenant_id,
            status=MetadataFieldStatus.ACTIVE.value,
            scope=scope,
        )

    async def get_field_definitions_for_read(
        self,
        tenant_id: str,
        scope: str | None = None,
    ) -> list[MetadataFieldDefinition]:
        """
        [AC-IDSMETA-14] 获取可用于读取的字段定义（active + deprecated，不含 draft）
        用于历史数据读取和展示
        
        Args:
            tenant_id: 租户 ID
            scope: 按适用范围过滤
        
        Returns:
            状态为 active 或 deprecated 的 MetadataFieldDefinition 列表
        """
        stmt = select(MetadataFieldDefinition).where(
            MetadataFieldDefinition.tenant_id == tenant_id,
            MetadataFieldDefinition.status.in_([
                MetadataFieldStatus.ACTIVE.value,
                MetadataFieldStatus.DEPRECATED.value,
            ]),
        )
        
        if scope:
            stmt = stmt.where(
                cast(MetadataFieldDefinition.scope, JSONB).op('?')(scope)
            )
        
        stmt = stmt.order_by(col(MetadataFieldDefinition.created_at).desc())
        
        result = await self._session.execute(stmt)
        return list(result.scalars().all())

    async def validate_metadata_for_create(
        self,
        tenant_id: str,
        metadata: dict[str, Any],
        scope: str,
    ) -> tuple[bool, list[str]]:
        """
        [AC-IDSMETA-14, AC-IDSMETA-15] 验证元数据是否可用于新建对象
        
        检查:
        1. 所有 required 字段是否已填写
        2. 字段是否为 active 状态（deprecated 字段禁止用于新建）
        3. 值类型是否正确
        4. enum/array_enum 类型的值是否在 options 中
        
        Args:
            tenant_id: 租户 ID
            metadata: 元数据字典
            scope: 对象类型范围
        
        Returns:
            (是否有效, 错误消息列表)
        """
        active_fields = await self.get_active_field_definitions(tenant_id, scope)
        active_field_map = {f.field_key: f for f in active_fields}
        
        errors = []
        
        for field_key, field_def in active_field_map.items():
            if field_def.required and field_key not in metadata:
                errors.append(f"必填字段 '{field_def.label}' ({field_key}) 未填写")
                continue
        
        for field_key, value in metadata.items():
            if field_key not in active_field_map:
                deprecated_field = await self.get_field_definition_by_key(tenant_id, field_key)
                if deprecated_field and deprecated_field.status == MetadataFieldStatus.DEPRECATED.value:
                    errors.append(
                        f"字段 '{deprecated_field.label}' ({field_key}) 已废弃，"
                        "不能用于新建对象"
                    )
                continue
            
            field_def = active_field_map[field_key]
            type_errors = self._validate_field_value(field_def, value)
            errors.extend(type_errors)
        
        return len(errors) == 0, errors

    async def validate_metadata_for_update(
        self,
        tenant_id: str,
        metadata: dict[str, Any],
        scope: str,
    ) -> tuple[bool, list[str]]:
        """
        [AC-IDSMETA-14] 验证元数据是否可用于更新对象
        
        与新建不同，更新时允许保留 deprecated 字段的值（但不能新增）
        
        Args:
            tenant_id: 租户 ID
            metadata: 元数据字典
            scope: 对象类型范围
        
        Returns:
            (是否有效, 错误消息列表)
        """
        readable_fields = await self.get_field_definitions_for_read(tenant_id, scope)
        readable_field_map = {f.field_key: f for f in readable_fields}
        
        active_fields = await self.get_active_field_definitions(tenant_id, scope)
        active_field_map = {f.field_key: f for f in active_fields}
        
        errors = []
        
        for field_key, field_def in active_field_map.items():
            if field_def.required and field_key not in metadata:
                errors.append(f"必填字段 '{field_def.label}' ({field_key}) 未填写")
        
        for field_key, value in metadata.items():
            if field_key not in readable_field_map:
                errors.append(f"未知字段 '{field_key}'")
                continue
            
            field_def = readable_field_map[field_key]
            type_errors = self._validate_field_value(field_def, value)
            errors.extend(type_errors)
        
        return len(errors) == 0, errors

    def _validate_field_value(
        self,
        field_def: MetadataFieldDefinition,
        value: Any,
    ) -> list[str]:
        """验证字段值类型和选项"""
        errors = []
        field_key = field_def.field_key
        field_type = field_def.type
        
        if value is None:
            return errors
        
        if field_type == MetadataFieldType.NUMBER.value:
            if not isinstance(value, (int, float)):
                try:
                    float(value)
                except (ValueError, TypeError):
                    errors.append(f"字段 '{field_def.label}' ({field_key}) 应为数字类型")
        
        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.label}' ({field_key}) 应为布尔类型")
        
        elif field_type == MetadataFieldType.ENUM.value:
            if field_def.options and value not in field_def.options:
                errors.append(
                    f"字段 '{field_def.label}' ({field_key}) 的值 '{value}' "
                    f"不在允许选项中: {field_def.options}"
                )
        
        elif field_type == MetadataFieldType.ARRAY_ENUM.value:
            if not isinstance(value, list):
                errors.append(f"字段 '{field_def.label}' ({field_key}) 应为数组类型")
            elif field_def.options:
                for v in value:
                    if v not in field_def.options:
                        errors.append(
                            f"字段 '{field_def.label}' ({field_key}) 的值 '{v}' "
                            f"不在允许选项中: {field_def.options}"
                        )
        
        return errors

    def _validate_field_type_and_options(
        self,
        field_type: str,
        options: list[str] | None,
        field_key: str,
    ) -> None:
        """验证字段类型和选项的一致性"""
        if field_type in [MetadataFieldType.ENUM.value, MetadataFieldType.ARRAY_ENUM.value]:
            if not options or len(options) == 0:
                raise ValueError(
                    f"字段 '{field_key}' 类型为 {field_type}，必须提供 options"
                )
            if len(options) != len(set(options)):
                raise ValueError(
                    f"字段 '{field_key}' 的 options 存在重复值"
                )

    def _validate_field_roles(
        self,
        field_roles: list[str] | None,
    ) -> None:
        """
        [AC-MRS-01,02,03] 验证字段角色配置的有效性
        
        Args:
            field_roles: 字段角色列表
        
        Raises:
            ValueError: 如果包含无效的字段角色
        """
        if not field_roles:
            return
        
        for role in field_roles:
            if role not in VALID_FIELD_ROLES:
                raise ValueError(
                    f"无效的字段角色 '{role}'，有效角色为: {VALID_FIELD_ROLES}"
                )

    async def get_field_definitions_map(
        self,
        tenant_id: str,
        scope: str | None = None,
        include_deprecated: bool = False,
    ) -> dict[str, dict[str, Any]]:
        """
        获取字段定义映射，用于前端动态渲染表单
        
        Args:
            tenant_id: 租户 ID
            scope: 按适用范围过滤
            include_deprecated: 是否包含 deprecated 字段
        
        Returns:
            字段键名到字段定义的映射
        """
        if include_deprecated:
            fields = await self.get_field_definitions_for_read(tenant_id, scope)
        else:
            fields = await self.get_active_field_definitions(tenant_id, scope)
        
        return {
            f.field_key: {
                "id": str(f.id),
                "field_key": f.field_key,
                "label": f.label,
                "type": f.type,
                "required": f.required,
                "options": f.options,
                "default": f.default_value,
                "scope": f.scope,
                "is_filterable": f.is_filterable,
                "is_rank_feature": f.is_rank_feature,
                "status": f.status,
            }
            for f in fields
        }

    async def delete_field_definition(
        self,
        tenant_id: str,
        field_id: str,
    ) -> bool:
        """
        删除元数据字段定义
        
        Args:
            tenant_id: 租户 ID
            field_id: 字段定义 ID
        
        Returns:
            是否删除成功
        """
        try:
            import uuid
            field_uuid = uuid.UUID(field_id)
        except ValueError:
            return False
        
        stmt = select(MetadataFieldDefinition).where(
            MetadataFieldDefinition.tenant_id == tenant_id,
            MetadataFieldDefinition.id == field_uuid,
        )
        result = await self._session.execute(stmt)
        field = result.scalar_one_or_none()
        
        if not field:
            return False
        
        await self._session.delete(field)
        await self._session.commit()
        
        return True
