# #region SupersetCompilationAdapter [C:4] [TYPE Module] [SEMANTICS superset, preview, compile, execution, adapter]
# @BRIEF Interact with Superset preview compilation and SQL Lab execution endpoints using the current approved execution context.
# @LAYER Infrastructure
# @RELATION CALLS -> [SupersetClient]
# @RELATION DEPENDS_ON -> [CompiledPreview]
# @PRE  effective template params and dataset execution reference are available.
# @POST  preview and launch calls return Superset-originated artifacts or explicit errors.
# @SIDE_EFFECT  performs upstream Superset preview and SQL Lab calls.
# @INVARIANT  The adapter never fabricates compiled SQL locally; preview truth is delegated to Superset only.
from __future__ import annotations

# #region SupersetCompilationAdapter.imports [TYPE Block]
from dataclasses import dataclass
from datetime import UTC, datetime
from typing import Any

from src.core.config_models import Environment
from src.core.logger import belief_scope, logger
from src.core.superset_client import SupersetClient
from src.models.dataset_review import CompiledPreview, PreviewStatus


# #endregion SupersetCompilationAdapter.imports
# #region PreviewCompilationPayload [C:2] [TYPE Class]
# @BRIEF Typed preview payload for Superset-side compilation.
@dataclass(frozen=True)
class PreviewCompilationPayload:
    session_id: str
    dataset_id: int
    preview_fingerprint: str
    template_params: dict[str, Any]
    effective_filters: list[dict[str, Any]]
# #endregion PreviewCompilationPayload
# #region SqlLabLaunchPayload [C:2] [TYPE Class]
# @BRIEF Typed SQL Lab payload for audited launch handoff.
@dataclass(frozen=True)
class SqlLabLaunchPayload:
    session_id: str
    dataset_id: int
    preview_id: str
    compiled_sql: str
    template_params: dict[str, Any]
# #endregion SqlLabLaunchPayload
# #region SupersetCompilationAdapter [C:4] [TYPE Class]
# @BRIEF Delegate preview compilation and SQL Lab launch to Superset without local SQL fabrication.
# @RELATION CALLS -> [SupersetClient]
# @PRE  environment is configured and Superset is reachable for the target session.
# @POST  adapter can return explicit ready/failed preview artifacts and canonical SQL Lab references.
# @SIDE_EFFECT  issues network requests to Superset API surfaces.
class SupersetCompilationAdapter:
    # #region SupersetCompilationAdapter.__init__ [TYPE Function] [C:2]
    # @PURPOSE: Bind adapter to one Superset environment and client instance.
    def __init__(
        self, environment: Environment, client: SupersetClient | None = None
    ) -> None:
        self.environment = environment
        self.client = client or SupersetClient(environment)
    # #endregion SupersetCompilationAdapter.__init__
    # #region SupersetCompilationAdapter._supports_client_method [TYPE Function] [C:2]
    # @PURPOSE: Detect explicitly implemented client capabilities without treating loose mocks as real methods.
    def _supports_client_method(self, method_name: str) -> bool:
        client_dict = getattr(self.client, "__dict__", {})
        if method_name in client_dict:
            return callable(client_dict[method_name])
        return callable(getattr(type(self.client), method_name, None))
    # #endregion SupersetCompilationAdapter._supports_client_method
    # #region SupersetCompilationAdapter.compile_preview [TYPE Function] [C:4]
    # @PURPOSE: Request Superset-side compiled SQL preview for the current effective inputs.
    # @RELATION CALLS -> [SupersetCompilationAdapter._request_superset_preview]
    # @PRE  dataset_id and effective inputs are available for the current session.
    # @POST  returns a ready or failed preview artifact backed only by Superset-originated SQL or diagnostics.
    # @SIDE_EFFECT  performs upstream preview requests.
    # @DATA_CONTRACT  Input[PreviewCompilationPayload] -> Output[CompiledPreview]
    def compile_preview(self, payload: PreviewCompilationPayload) -> CompiledPreview:
        with belief_scope("SupersetCompilationAdapter.compile_preview"):
            if payload.dataset_id <= 0:
                logger.explore(
                    "Preview compilation rejected because dataset identifier is invalid",
                    extra={
                        "dataset_id": payload.dataset_id,
                        "session_id": payload.session_id,
                    },
                )
                raise ValueError("dataset_id must be a positive integer")
            logger.reason(
                "Requesting Superset-generated SQL preview",
                extra={
                    "session_id": payload.session_id,
                    "dataset_id": payload.dataset_id,
                    "template_param_count": len(payload.template_params),
                    "filter_count": len(payload.effective_filters),
                },
            )
            try:
                preview_result = self._request_superset_preview(payload)
            except Exception as exc:
                logger.explore(
                    "Superset preview compilation failed with explicit upstream error",
                    extra={
                        "session_id": payload.session_id,
                        "dataset_id": payload.dataset_id,
                        "error": str(exc),
                    },
                )
                return CompiledPreview(
                    session_id=payload.session_id,
                    preview_status=PreviewStatus.FAILED,
                    compiled_sql=None,
                    preview_fingerprint=payload.preview_fingerprint,
                    compiled_by="superset",
                    error_code="superset_preview_failed",
                    error_details=str(exc),
                    compiled_at=None,
                )
            compiled_sql = str(preview_result.get("compiled_sql") or "").strip()
            if not compiled_sql:
                logger.explore(
                    "Superset preview response did not include compiled SQL",
                    extra={
                        "session_id": payload.session_id,
                        "dataset_id": payload.dataset_id,
                        "response_keys": sorted(preview_result.keys()),
                    },
                )
                return CompiledPreview(
                    session_id=payload.session_id,
                    preview_status=PreviewStatus.FAILED,
                    compiled_sql=None,
                    preview_fingerprint=payload.preview_fingerprint,
                    compiled_by="superset",
                    error_code="superset_preview_empty",
                    error_details="Superset preview response did not include compiled SQL",
                    compiled_at=None,
                )
            preview = CompiledPreview(
                session_id=payload.session_id,
                preview_status=PreviewStatus.READY,
                compiled_sql=compiled_sql,
                preview_fingerprint=payload.preview_fingerprint,
                compiled_by="superset",
                error_code=None,
                error_details=None,
                compiled_at=datetime.now(UTC),
            )
            logger.reflect(
                "Superset-generated SQL preview captured successfully",
                extra={
                    "session_id": payload.session_id,
                    "dataset_id": payload.dataset_id,
                    "compiled_sql_length": len(compiled_sql),
                },
            )
            return preview
    # #endregion SupersetCompilationAdapter.compile_preview
    # #region SupersetCompilationAdapter.mark_preview_stale [TYPE Function] [C:2]
    # @PURPOSE: Invalidate previous preview after mapping or value changes.
    # @PRE  preview is a persisted preview artifact or current in-memory snapshot.
    # @POST  preview status becomes stale without fabricating a replacement artifact.
    def mark_preview_stale(self, preview: CompiledPreview) -> CompiledPreview:
        preview.preview_status = PreviewStatus.STALE
        return preview
    # #endregion SupersetCompilationAdapter.mark_preview_stale
    # #region SupersetCompilationAdapter.create_sql_lab_session [TYPE Function] [C:4]
    # @PURPOSE: Create the canonical audited execution session after all launch gates pass.
    # @RELATION CALLS -> [SupersetCompilationAdapter._request_sql_lab_session]
    # @PRE  compiled_sql is Superset-originated and launch gates are already satisfied.
    # @POST  returns one canonical SQL Lab session reference from Superset.
    # @SIDE_EFFECT  performs upstream SQL Lab execution/session creation.
    # @DATA_CONTRACT  Input[SqlLabLaunchPayload] -> Output[str]
    def create_sql_lab_session(self, payload: SqlLabLaunchPayload) -> str:
        with belief_scope("SupersetCompilationAdapter.create_sql_lab_session"):
            compiled_sql = str(payload.compiled_sql or "").strip()
            if not compiled_sql:
                logger.explore(
                    "SQL Lab launch rejected because compiled SQL is empty",
                    extra={
                        "session_id": payload.session_id,
                        "preview_id": payload.preview_id,
                    },
                )
                raise ValueError("compiled_sql must be non-empty")
            logger.reason(
                "Creating SQL Lab execution session from Superset-originated preview",
                extra={
                    "session_id": payload.session_id,
                    "dataset_id": payload.dataset_id,
                    "preview_id": payload.preview_id,
                },
            )
            result = self._request_sql_lab_session(payload)
            sql_lab_session_ref = str(
                result.get("sql_lab_session_ref")
                or result.get("query_id")
                or result.get("id")
                or result.get("result", {}).get("id")
                or ""
            ).strip()
            if not sql_lab_session_ref:
                logger.explore(
                    "Superset SQL Lab launch response did not include a stable session reference",
                    extra={
                        "session_id": payload.session_id,
                        "preview_id": payload.preview_id,
                    },
                )
                raise RuntimeError(
                    "Superset SQL Lab launch response did not include a session reference"
                )
            logger.reflect(
                "Canonical SQL Lab session created successfully",
                extra={
                    "session_id": payload.session_id,
                    "preview_id": payload.preview_id,
                    "sql_lab_session_ref": sql_lab_session_ref,
                },
            )
            return sql_lab_session_ref
    # #endregion SupersetCompilationAdapter.create_sql_lab_session
    # #region SupersetCompilationAdapter._request_superset_preview [TYPE Function] [C:4]
    # @PURPOSE: Request preview compilation through explicit client support backed by real Superset endpoints only.
    # @RELATION CALLS -> [EXT:method:SupersetClient.compile_dataset_preview]
    # @PRE  payload contains a valid dataset identifier and deterministic execution inputs for one preview attempt.
    # @POST  returns one normalized upstream compilation response including the chosen strategy metadata.
    # @SIDE_EFFECT  issues one or more Superset preview requests through the client fallback chain.
    # @DATA_CONTRACT  Input[PreviewCompilationPayload] -> Output[Dict[str,Any]]
    def _request_superset_preview(
        self, payload: PreviewCompilationPayload
    ) -> dict[str, Any]:
        direct_compile_preview = getattr(self.client, "compile_preview", None)
        if self._supports_client_method("compile_preview") and callable(
            direct_compile_preview
        ):
            try:
                logger.reason(
                    "Attempting preview compilation via direct client capability",
                    extra={
                        "dataset_id": payload.dataset_id,
                        "session_id": payload.session_id,
                    },
                )
                response = direct_compile_preview(payload)
            except TypeError:
                response = direct_compile_preview(
                    payload.dataset_id,
                    template_params=payload.template_params,
                    effective_filters=payload.effective_filters,
                )
            except Exception as exc:
                logger.explore(
                    "Direct client preview capability failed; falling back to dataset preview strategies",
                    extra={
                        "dataset_id": payload.dataset_id,
                        "session_id": payload.session_id,
                        "error": str(exc),
                    },
                )
            else:
                normalized = self._normalize_preview_response(response)
                if normalized is not None:
                    return normalized
        direct_compile_dataset_preview = getattr(
            self.client, "compile_dataset_preview", None
        )
        if self._supports_client_method("compile_dataset_preview") and callable(
            direct_compile_dataset_preview
        ):
            try:
                logger.reason(
                    "Attempting deterministic Superset preview compilation through supported endpoint strategies",
                    extra={
                        "dataset_id": payload.dataset_id,
                        "session_id": payload.session_id,
                        "filter_count": len(payload.effective_filters),
                        "template_param_count": len(payload.template_params),
                    },
                )
                response = direct_compile_dataset_preview(
                    dataset_id=payload.dataset_id,
                    template_params=payload.template_params,
                    effective_filters=payload.effective_filters,
                )
            except Exception as exc:
                logger.explore(
                    "Superset preview compilation failed across supported endpoint strategies",
                    extra={
                        "dataset_id": payload.dataset_id,
                        "session_id": payload.session_id,
                        "error": str(exc),
                    },
                )
                raise RuntimeError(str(exc)) from exc
            normalized = self._normalize_preview_response(response)
            if normalized is None:
                raise RuntimeError(
                    "Superset preview compilation response could not be normalized"
                )
            return normalized
        try:
            logger.reason(
                "Attempting deterministic Superset preview compilation through supported endpoint strategies",
                extra={
                    "dataset_id": payload.dataset_id,
                    "session_id": payload.session_id,
                    "filter_count": len(payload.effective_filters),
                    "template_param_count": len(payload.template_params),
                },
            )
            if self._supports_client_method("compile_dataset_preview"):
                response = self.client.compile_dataset_preview(
                    dataset_id=payload.dataset_id,
                    template_params=payload.template_params,
                    effective_filters=payload.effective_filters,
                )
                normalized = self._normalize_preview_response(response)
                if normalized is None:
                    raise RuntimeError(
                        "Superset preview compilation response could not be normalized"
                    )
                return normalized
            errors: list[str] = []
            for endpoint in (
                f"/dataset/{payload.dataset_id}/preview",
                f"/dataset/{payload.dataset_id}/sql",
            ):
                try:
                    response = self.client.network.request(
                        method="POST",
                        endpoint=endpoint,
                        data=self._dump_json(
                            {
                                "template_params": payload.template_params,
                                "effective_filters": payload.effective_filters,
                            }
                        ),
                        headers={"Content-Type": "application/json"},
                    )
                    normalized = self._normalize_preview_response(response)
                    if normalized is not None:
                        return normalized
                    errors.append(f"{endpoint}:unrecognized_response")
                except Exception as exc:
                    errors.append(f"{endpoint}:{exc}")
            raise RuntimeError(
                "; ".join(errors) or "Superset preview compilation failed"
            )
        except Exception as exc:
            logger.explore(
                "Superset preview compilation failed across supported endpoint strategies",
                extra={
                    "dataset_id": payload.dataset_id,
                    "session_id": payload.session_id,
                    "error": str(exc),
                },
            )
            raise RuntimeError(str(exc)) from exc
    # #endregion SupersetCompilationAdapter._request_superset_preview
    # #region SupersetCompilationAdapter._request_sql_lab_session [TYPE Function] [C:4]
    # @PURPOSE: Probe supported SQL Lab execution surfaces and return the first successful response.
    # @RELATION CALLS -> [EXT:method:SupersetClient.get_dataset]
    # @PRE  payload carries non-empty Superset-originated SQL and a preview identifier for the current launch.
    # @POST  returns the first successful SQL Lab execution response from Superset.
    # @SIDE_EFFECT  issues Superset dataset lookup and SQL Lab execution requests.
    # @DATA_CONTRACT  Input[SqlLabLaunchPayload] -> Output[Dict[str,Any]]
    def _request_sql_lab_session(self, payload: SqlLabLaunchPayload) -> dict[str, Any]:
        dataset_raw = self.client.get_dataset(payload.dataset_id)
        dataset_record = (
            dataset_raw.get("result", dataset_raw)
            if isinstance(dataset_raw, dict)
            else {}
        )
        database_id = (
            dataset_record.get("database", {}).get("id")
            if isinstance(dataset_record.get("database"), dict)
            else dataset_record.get("database_id")
        )
        if database_id is None:
            raise RuntimeError(
                "Superset dataset does not expose a database identifier for SQL Lab launch"
            )
        request_payload = {
            "database_id": database_id,
            "sql": payload.compiled_sql,
            "templateParams": payload.template_params,
            "schema": dataset_record.get("schema"),
            "client_id": payload.preview_id,
        }
        candidate_calls = [
            {"kind": "network", "target": "/sqllab/execute/", "http_method": "POST"},
            {"kind": "network", "target": "/sql_lab/execute/", "http_method": "POST"},
        ]
        errors: list[str] = []
        for candidate in candidate_calls:
            try:
                response = self.client.network.request(
                    method=candidate["http_method"],
                    endpoint=candidate["target"],
                    data=self._dump_json(request_payload),
                    headers={"Content-Type": "application/json"},
                )
                if isinstance(response, dict) and response:
                    return response
            except Exception as exc:
                errors.append(f"{candidate['target']}:{exc}")
                logger.explore(
                    "Superset SQL Lab candidate failed",
                    extra={"target": candidate["target"], "error": str(exc)},
                )
        raise RuntimeError(
            "; ".join(errors) or "No Superset SQL Lab surface accepted the request"
        )
    # #endregion SupersetCompilationAdapter._request_sql_lab_session
    # #region SupersetCompilationAdapter._normalize_preview_response [TYPE Function] [C:3]
    # @PURPOSE: Normalize candidate Superset preview responses into one compiled-sql structure.
    # @RELATION DEPENDS_ON -> [CompiledPreview]
    def _normalize_preview_response(self, response: Any) -> dict[str, Any] | None:
        if not isinstance(response, dict):
            return None
        compiled_sql_candidates = [
            response.get("compiled_sql"),
            response.get("sql"),
            response.get("query"),
        ]
        result_payload = response.get("result")
        if isinstance(result_payload, dict):
            compiled_sql_candidates.extend(
                [
                    result_payload.get("compiled_sql"),
                    result_payload.get("sql"),
                    result_payload.get("query"),
                ]
            )
        for candidate in compiled_sql_candidates:
            compiled_sql = str(candidate or "").strip()
            if compiled_sql:
                return {
                    "compiled_sql": compiled_sql,
                    "raw_response": response,
                }
        return None
    # #endregion SupersetCompilationAdapter._normalize_preview_response
    # #region SupersetCompilationAdapter._dump_json [TYPE Function] [C:1]
    # @PURPOSE: Serialize Superset request payload deterministically for network transport.
    def _dump_json(self, payload: dict[str, Any]) -> str:
        import json
        return json.dumps(payload, sort_keys=True, default=str)
    # #endregion SupersetCompilationAdapter._dump_json
# #endregion SupersetCompilationAdapter
# #endregion SupersetCompilationAdapter
