# #region SupersetContextRecoveryMixin [C:4] [TYPE Module] [SEMANTICS superset, context, recovery, dashboard, dataset]
# @LAYER Infrastructure
# @BRIEF Recover imported filters from Superset parsed context and dashboard metadata.
# @RELATION CALLS -> [SupersetClient]
# @RELATION DEPENDS_ON -> [SupersetContextExtractorBase]
# #endregion SupersetContextRecoveryMixin
# #region _recovery_imports [TYPE Block]
from __future__ import annotations

from copy import deepcopy
import json
from typing import Any, cast

from ...logger import belief_scope, logger
from ._base import SupersetParsedContext

logger = cast(Any, logger)
# #endregion _recovery_imports
# #region SupersetContextRecoveryMixin [C:4] [TYPE Class]
# @BRIEF Mixin providing filter recovery for the composed SupersetContextExtractor.
class SupersetContextRecoveryMixin:
    # #region SupersetContextRecoveryMixin.recover_imported_filters [TYPE Function] [C:4]
    # @PURPOSE: Build imported filter entries from URL state and Superset-side saved context.
    # @RELATION CALLS -> [EXT:method:SupersetClient.get_dashboard]
    # @PRE  parsed_context comes from a successful Superset link parse for one environment.
    # @POST  returns explicit recovered and partial filter entries with preserved provenance and confirmation requirements.
    # @SIDE_EFFECT  may issue Superset reads for dashboard metadata enrichment.
    # @DATA_CONTRACT  Input[SupersetParsedContext] -> Output[List[Dict[str,Any]]]
    def recover_imported_filters(
        self, parsed_context: SupersetParsedContext
    ) -> list[dict[str, Any]]:
        with belief_scope("SupersetContextExtractor.recover_imported_filters"):
            recovered_filters: list[dict[str, Any]] = []
            seen_filter_keys: set[str] = set()
            metadata_filters: list[dict[str, Any]] = []
            metadata_filters_by_id: dict[str, dict[str, Any]] = {}
            def merge_recovered_filter(candidate: dict[str, Any]) -> None:
                filter_key = candidate["filter_name"].strip().lower()
                existing_index = next(
                    (
                        index
                        for index, existing in enumerate(recovered_filters)
                        if existing["filter_name"].strip().lower() == filter_key
                    ),
                    None,
                )
                if existing_index is None:
                    seen_filter_keys.add(filter_key)
                    recovered_filters.append(candidate)
                    return
                existing = recovered_filters[existing_index]
                if existing.get("display_name") in {
                    None,
                    "",
                    existing.get("filter_name"),
                } and candidate.get("display_name"):
                    existing["display_name"] = candidate["display_name"]
                if (
                    existing.get("raw_value") is None
                    and candidate.get("raw_value") is not None
                ):
                    existing["raw_value"] = candidate["raw_value"]
                    existing["confidence_state"] = candidate.get(
                        "confidence_state", "imported"
                    )
                    existing["requires_confirmation"] = candidate.get(
                        "requires_confirmation", False
                    )
                    existing["recovery_status"] = candidate.get(
                        "recovery_status", "recovered"
                    )
                    existing["source"] = candidate.get(
                        "source", existing.get("source")
                    )
                if (
                    existing.get("normalized_value") is None
                    and candidate.get("normalized_value") is not None
                ):
                    existing["normalized_value"] = deepcopy(
                        candidate["normalized_value"]
                    )
                if (
                    existing.get("notes")
                    and candidate.get("notes")
                    and candidate["notes"] not in existing["notes"]
                ):
                    existing["notes"] = f"{existing['notes']}; {candidate['notes']}"
            if parsed_context.dashboard_id is not None:
                try:
                    dashboard_payload = self.client.get_dashboard(
                        parsed_context.dashboard_id
                    )
                    dashboard_record = (
                        dashboard_payload.get("result", dashboard_payload)
                        if isinstance(dashboard_payload, dict)
                        else {}
                    )
                    json_metadata = dashboard_record.get("json_metadata")
                    if isinstance(json_metadata, str) and json_metadata.strip():
                        json_metadata = json.loads(json_metadata)
                    if not isinstance(json_metadata, dict):
                        json_metadata = {}
                    native_filter_configuration = (
                        json_metadata.get("native_filter_configuration") or []
                    )
                    default_filters = json_metadata.get("default_filters") or {}
                    if isinstance(default_filters, str) and default_filters.strip():
                        try:
                            default_filters = json.loads(default_filters)
                        except Exception:
                            logger.explore(
                                "Superset default_filters payload was not valid JSON",
                                extra={
                                    "dashboard_id": parsed_context.dashboard_id
                                },
                            )
                            default_filters = {}
                    for item in native_filter_configuration:
                        if not isinstance(item, dict):
                            continue
                        filter_name = str(
                            item.get("name")
                            or item.get("filter_name")
                            or item.get("column")
                            or ""
                        ).strip()
                        if not filter_name:
                            continue
                        display_name = (
                            item.get("label") or item.get("name") or filter_name
                        )
                        filter_id = str(item.get("id") or "").strip()
                        default_value = None
                        if isinstance(default_filters, dict):
                            default_value = default_filters.get(filter_name)
                        metadata_filter = self._normalize_imported_filter_payload(
                            {
                                "filter_name": filter_name,
                                "display_name": display_name,
                                "raw_value": default_value,
                                "source": "superset_native",
                                "recovery_status": "recovered"
                                if default_value is not None
                                else "partial",
                                "requires_confirmation": default_value is None,
                                "notes": "Recovered from Superset dashboard native filter configuration",
                            },
                            default_source="superset_native",
                            default_note="Recovered from Superset dashboard native filter configuration",
                        )
                        metadata_filters.append(metadata_filter)
                        if filter_id:
                            metadata_filters_by_id[filter_id.lower()] = {
                                "filter_name": filter_name,
                                "display_name": display_name,
                            }
                except Exception as exc:
                    logger.explore(
                        "Dashboard native filter enrichment failed; preserving partial imported filters",
                        extra={
                            "dashboard_id": parsed_context.dashboard_id,
                            "error": str(exc),
                            "filter_count": len(recovered_filters),
                        },
                    )
                    metadata_filters = []
                    metadata_filters_by_id = {}
            for item in parsed_context.imported_filters:
                normalized = self._normalize_imported_filter_payload(
                    item,
                    default_source="superset_url",
                    default_note="Recovered from Superset URL state",
                )
                metadata_match = metadata_filters_by_id.get(
                    normalized["filter_name"].strip().lower()
                )
                if metadata_match is not None:
                    normalized["filter_name"] = metadata_match["filter_name"]
                    normalized["display_name"] = metadata_match["display_name"]
                    normalized["notes"] = (
                        "Recovered from Superset URL state and reconciled against dashboard native filter metadata"
                    )
                merge_recovered_filter(normalized)
                logger.reflect(
                    "Recovered filter from URL state",
                    extra={
                        "filter_name": normalized["filter_name"],
                        "source": normalized["source"],
                        "has_value": normalized["raw_value"] is not None,
                        "canonicalized": metadata_match is not None,
                    },
                )
            if parsed_context.dashboard_id is None:
                logger.reflect(
                    "Imported filter recovery completed without dashboard enrichment",
                    extra={
                        "dashboard_id": None,
                        "filter_count": len(recovered_filters),
                        "partial_recovery": parsed_context.partial_recovery,
                    },
                )
                return recovered_filters
            for saved_filter in metadata_filters:
                merge_recovered_filter(saved_filter)
                logger.reflect(
                    "Recovered filter from dashboard metadata",
                    extra={
                        "filter_name": saved_filter["filter_name"],
                        "has_value": saved_filter["raw_value"] is not None,
                    },
                )
            if not recovered_filters:
                recovered_filters.append(
                    self._normalize_imported_filter_payload(
                        {
                            "filter_name": f"dashboard_{parsed_context.dashboard_id}_filters",
                            "display_name": "Dashboard native filters",
                            "raw_value": None,
                            "source": "superset_native",
                            "recovery_status": "partial",
                            "requires_confirmation": True,
                            "notes": "Superset dashboard filter configuration could not be recovered fully",
                        },
                        default_source="superset_native",
                        default_note="Superset dashboard filter configuration could not be recovered fully",
                    )
                )
            logger.reflect(
                "Imported filter recovery completed with dashboard enrichment",
                extra={
                    "dashboard_id": parsed_context.dashboard_id,
                    "filter_count": len(recovered_filters),
                    "partial_entries": len(
                        [
                            item
                            for item in recovered_filters
                            if item["recovery_status"] == "partial"
                        ]
                    ),
                },
            )
            return recovered_filters
    # #endregion SupersetContextRecoveryMixin.recover_imported_filters
    # #region SupersetContextRecoveryMixin._normalize_imported_filter_payload [TYPE Function] [C:2]
    # @PURPOSE: Normalize one imported-filter payload with explicit provenance and confirmation state.
    def _normalize_imported_filter_payload(
        self,
        payload: dict[str, Any],
        default_source: str,
        default_note: str,
    ) -> dict[str, Any]:
        raw_value = payload.get("raw_value")
        if "raw_value" not in payload and "value" in payload:
            raw_value = payload.get("value")
        recovery_status = (
            str(
                payload.get("recovery_status")
                or ("recovered" if raw_value is not None else "partial")
            )
            .strip()
            .lower()
        )
        requires_confirmation = bool(
            payload.get(
                "requires_confirmation",
                raw_value is None or recovery_status != "recovered",
            )
        )
        return {
            "filter_name": str(
                payload.get("filter_name") or "unresolved_filter"
            ).strip(),
            "display_name": payload.get("display_name"),
            "raw_value": raw_value,
            "normalized_value": payload.get("normalized_value"),
            "source": str(payload.get("source") or default_source),
            "confidence_state": "imported"
            if raw_value is not None
            else "unresolved",
            "requires_confirmation": requires_confirmation,
            "recovery_status": recovery_status,
            "notes": str(payload.get("notes") or default_note),
        }
    # #endregion SupersetContextRecoveryMixin._normalize_imported_filter_payload
# #endregion SupersetContextRecoveryMixin
