from __future__ import annotations

import logging
from collections.abc import Mapping
from typing import Any

logger = logging.getLogger("dscons.generation_payload.helpers")


class PayloadCoercionHelpersMixin:
    """Data extraction, dictionary fallback resolution, and string normalization helpers."""

    def _require_active_template(self) -> GenerationTemplateRegistryEntry:
        """Lấy template active cho pilot hoặc raise lỗi khi chưa cấu hình."""
        template = get_active_template_registry_entry(PILOT_DOCUMENT_TYPE)
        if template is None:
            raise ValueError(
                "Chưa tìm thấy template active cho bien_ban_ban_giao_mat_bang."
            )
        return template

    def _pick_first_mapping(
        self,
        source_data: Mapping[str, Any],
        *paths: str,
    ) -> Mapping[str, Any]:
        """Lấy mapping đầu tiên hợp lệ từ danh sách đường dẫn."""
        for path in paths:
            value = self._get_nested_value(source_data, path)
            if isinstance(value, Mapping):
                return value
        return {}

    def _pick_first_str(
        self,
        source_data: Mapping[str, Any],
        *paths: str,
    ) -> str | None:
        """Lấy chuỗi đầu tiên có ý nghĩa từ danh sách đường dẫn."""
        for path in paths:
            value = self._get_nested_value(source_data, path)
            normalized = self._coerce_to_string(value)
            if normalized is not None:
                return normalized
        return None

    def _pick_first_str_from_mapping(
        self,
        source_data: Mapping[str, Any],
        *keys: str,
    ) -> str | None:
        """Lấy chuỗi đầu tiên có ý nghĩa từ mapping phẳng."""
        for key in keys:
            value = source_data.get(key)
            normalized = self._coerce_to_string(value)
            if normalized is not None:
                return normalized
        return None

    def _get_nested_value(self, source_data: Mapping[str, Any], path: str) -> Any:
        """Đọc giá trị theo đường dẫn a.b.c có hỗ trợ index list dạng số."""
        current: Any = source_data
        for part in path.split("."):
            if isinstance(current, Mapping):
                current = current.get(part)
                continue
            if isinstance(current, list) and part.isdigit():
                index = int(part)
                if 0 <= index < len(current):
                    current = current[index]
                    continue
            return None
        return current

    def _coerce_to_string(self, value: Any) -> str | None:
        """Chuẩn hóa giá trị đơn thành chuỗi nếu có ý nghĩa."""
        if value is None:
            return None
        if isinstance(value, str):
            normalized = value.strip()
            return normalized or None
        if isinstance(value, (int, float, bool)):
            return str(value)
        return None

    def _has_meaningful_value(self, value: Any) -> bool:
        """Kiểm tra giá trị có đủ ý nghĩa để dùng cho payload hay không."""
        if value is None:
            return False
        if isinstance(value, str):
            return bool(value.strip())
        return True
