# #region SupersetDashboardsWriteMixin [C:4] [TYPE Module] [SEMANTICS superset, dashboard, chart, write, maintenance, banner]
# @BRIEF Dashboard write mixin for SupersetClient — markdown chart CRUD and layout manipulation for maintenance banners.
# @LAYER Infrastructure
# @RELATION DEPENDS_ON -> [SupersetClientBase]
# @RELATION DEPENDS_ON -> [SupersetChartsMixin]
# @RELATION DEPENDS_ON -> [LayoutUtils]
# @SIDE_EFFECT Creates, updates, deletes markdown charts & modifies dashboard layout via Superset API.
# @DATA_CONTRACT Input: dashboard_id / chart_id / markdown_text → Output: API response dict or chart_id int
# @INVARIANT All network operations use self.network.request()
# @RATIONALE Extracted from monolithic superset_client to satisfy INV_7.
#   Uses belief_scope with REASON/REFLECT/EXPLORE markers for all C4 operations per Std.Semantics.Python.

import json
from typing import Any, cast

from ..logger import belief_scope, logger as app_logger
from ._layout_utils import (
    insert_banner_markdown_at_top,
    parse_position_json,
    remove_banner_from_position,
    update_banner_markdown_content,
)

app_logger = cast(Any, app_logger)


# #region SupersetDashboardsWriteMixin [C:4] [TYPE Class]
# @BRIEF Mixin providing markdown chart CRUD and dashboard layout manipulation for maintenance banners.
# @RELATION DEPENDS_ON -> [SupersetClientBase]
# @RELATION DEPENDS_ON -> [SupersetChartsMixin]
class SupersetDashboardsWriteMixin:
    """Mixin for creating/updating/deleting markdown charts and manipulating dashboard layouts."""

    # #region create_markdown_chart [C:3] [TYPE Function]
    # @BRIEF Create a markdown chart and return the new chart ID.
    # @PRE dashboard_id exists in Superset. markdown_text not empty.
    # @POST Returns chart_id (int). Chart is NOT yet placed in dashboard layout.
    # @SIDE_EFFECT Creates a new chart resource in Superset.
    # @RELATION CALLS -> [EXT:method:self.network.request]
    def create_markdown_chart(self, dashboard_id: int, markdown_text: str) -> int:
        with belief_scope(
            "SupersetDashboardsWriteMixin.create_markdown_chart",
            f"dashboard_id={dashboard_id}",
        ):
            app_logger.reason(
                "Creating markdown chart",
                extra={"dashboard_id": dashboard_id, "len": len(markdown_text)},
            )
            datasource_id = self._resolve_markdown_datasource(dashboard_id)
            payload = {
                "dashboards": [dashboard_id],
                "datasource_id": datasource_id,
                "datasource_type": "table",
                "slice_name": "Maintenance Banner",
                "viz_type": "markdown",
                "params": json.dumps({
                    "markdown": markdown_text,
                    "viz_type": "markdown",
                }),
            }
            try:
                response = cast(dict, self.network.request(
                    method="POST", endpoint="/chart/", json=payload
                ))
                chart_id = int(response.get("id") or response.get("result", {}).get("id", 0))
                app_logger.reflect("Chart created", extra={"chart_id": chart_id})
                return chart_id
            except Exception as e:
                app_logger.explore("Create chart failed", extra={"dashboard_id": dashboard_id}, error=str(e))
                raise
    # #endregion create_markdown_chart

    # #region update_markdown_chart [C:3] [TYPE Function]
    # @BRIEF Update the markdown text of an existing markdown chart.
    # @PRE chart_id exists and is a markdown chart.
    # @POST Chart markdown content updated.
    # @SIDE_EFFECT Modifies a chart resource in Superset.
    def update_markdown_chart(self, chart_id: int, markdown_text: str) -> dict:
        with belief_scope(
            "SupersetDashboardsWriteMixin.update_markdown_chart",
            f"chart_id={chart_id}",
        ):
            app_logger.reason("Updating markdown chart", extra={"chart_id": chart_id, "len": len(markdown_text)})
            payload = {"params": json.dumps({"markdown": markdown_text, "viz_type": "markdown"})}
            try:
                response = cast(dict, self.network.request(method="PUT", endpoint=f"/chart/{chart_id}", json=payload))
                app_logger.reflect("Chart updated", extra={"chart_id": chart_id})
                return response
            except Exception as e:
                app_logger.explore("Update chart failed", extra={"chart_id": chart_id}, error=str(e))
                raise
    # #endregion update_markdown_chart

    # #region update_dashboard_layout [C:4] [TYPE Function]
    # @BRIEF Insert a native MARKDOWN element at (0,0) with full width (12 cols),
    #   shift existing charts down. Uses native MARKDOWN for reliable rendering.
    # @PRE dashboard_id exists in Superset. chart_id is used for tracking/DB.
    # @POST MARKDOWN element placed at top; existing items shifted down.
    # @SIDE_EFFECT Modifies dashboard layout JSON.
    def update_dashboard_layout(self, dashboard_id: int, chart_id: int) -> dict:
        with belief_scope(
            "SupersetDashboardsWriteMixin.update_dashboard_layout",
            f"dashboard_id={dashboard_id}, chart_id={chart_id}",
        ):
            app_logger.reason(
                "Updating layout with native MARKDOWN",
                extra={"dashboard_id": dashboard_id, "chart_id": chart_id},
            )
            try:
                dashboard = cast(dict, self.network.request(
                    method="GET", endpoint=f"/dashboard/{dashboard_id}"
                ))
                result = dashboard.get("result", dashboard)
                position_json = parse_position_json(result.get("position_json", "{}"))

                # Use native MARKDOWN element inside a ROW, connected to GRID_ID
                placeholder = "*Maintenance banner*"
                insert_banner_markdown_at_top(position_json, chart_id, placeholder)

                response = cast(dict, self.network.request(
                    method="PUT", endpoint=f"/dashboard/{dashboard_id}",
                    json={"position_json": json.dumps(position_json)},
                ))
                app_logger.reflect(
                    "Layout updated with native MARKDOWN",
                    extra={"dashboard_id": dashboard_id, "chart_id": chart_id},
                )
                return response
            except Exception as e:
                app_logger.explore(
                    "Layout update failed",
                    extra={"dashboard_id": dashboard_id},
                    error=str(e),
                )
                raise
    # #endregion update_dashboard_layout

    # #region remove_chart_from_layout [C:3] [TYPE Function]
    # @BRIEF Remove banner markdown element from dashboard layout without deleting the chart.
    # @PRE dashboard_id exists. chart_id exists in layout as MARKDOWN-banner-{chart_id}.
    # @POST MARKDOWN element removed from position_json; items shifted up.
    # @SIDE_EFFECT Modifies dashboard layout JSON.
    def remove_chart_from_layout(self, dashboard_id: int, chart_id: int) -> dict:
        with belief_scope(
            "SupersetDashboardsWriteMixin.remove_chart_from_layout",
            f"dashboard_id={dashboard_id}, chart_id={chart_id}",
        ):
            app_logger.reason(
                "Removing banner from layout",
                extra={"dashboard_id": dashboard_id, "chart_id": chart_id},
            )
            try:
                dashboard = cast(dict, self.network.request(
                    method="GET", endpoint=f"/dashboard/{dashboard_id}"
                ))
                result = dashboard.get("result", dashboard)
                position_json = parse_position_json(result.get("position_json", "{}"))
                # Remove new MARKDOWN+ROW pair (old CHART-{id} format no longer created)
                remove_banner_from_position(position_json, chart_id)

                response = cast(dict, self.network.request(
                    method="PUT", endpoint=f"/dashboard/{dashboard_id}",
                    json={"position_json": json.dumps(position_json)},
                ))
                app_logger.reflect(
                    "Banner removed from layout",
                    extra={"dashboard_id": dashboard_id},
                )
                return response
            except Exception as e:
                app_logger.explore(
                    "Remove from layout failed",
                    extra={"dashboard_id": dashboard_id},
                    error=str(e),
                )
                raise
    # #endregion remove_chart_from_layout

    # #region delete_chart [C:3] [TYPE Function]
    # @BRIEF Delete a chart from Superset by ID.
    # @PRE chart_id exists.
    # @POST Chart permanently deleted from Superset.
    # @SIDE_EFFECT Destroys chart resource.
    def delete_chart(self, chart_id: int) -> dict:
        with belief_scope("SupersetDashboardsWriteMixin.delete_chart", f"chart_id={chart_id}"):
            app_logger.reason("Deleting chart", extra={"chart_id": chart_id})
            try:
                response = cast(dict, self.network.request(method="DELETE", endpoint=f"/chart/{chart_id}"))
                app_logger.reflect("Chart deleted", extra={"chart_id": chart_id})
                return response
            except Exception as e:
                app_logger.explore("Delete chart failed", extra={"chart_id": chart_id}, error=str(e))
                raise
    # #endregion delete_chart

    # #region update_banner_on_dashboard [C:3] [TYPE Function]
    # @BRIEF Update the content of a native MARKDOWN banner element on a dashboard.
    # @PRE dashboard_id exists. chart_id used for key lookup.
    # @POST MARKDOWN element content updated on dashboard.
    # @SIDE_EFFECT Modifies dashboard layout JSON in Superset.
    def update_banner_on_dashboard(
        self, dashboard_id: int, chart_id: int, content: str
    ) -> dict:
        with belief_scope(
            "SupersetDashboardsWriteMixin.update_banner_on_dashboard",
            f"dashboard_id={dashboard_id}, chart_id={chart_id}",
        ):
            app_logger.reason(
                "Updating banner content on dashboard",
                extra={"dashboard_id": dashboard_id, "chart_id": chart_id, "len": len(content)},
            )
            try:
                dashboard = cast(dict, self.network.request(
                    method="GET", endpoint=f"/dashboard/{dashboard_id}"
                ))
                result = dashboard.get("result", dashboard)
                position_json = parse_position_json(result.get("position_json", "{}"))
                markdown_key = f"MARKDOWN-banner-{chart_id}"
                update_banner_markdown_content(position_json, markdown_key, content)
                response = cast(dict, self.network.request(
                    method="PUT", endpoint=f"/dashboard/{dashboard_id}",
                    json={"position_json": json.dumps(position_json)},
                ))
                app_logger.reflect(
                    "Banner content updated on dashboard",
                    extra={"dashboard_id": dashboard_id, "chart_id": chart_id},
                )
                return response
            except Exception as e:
                app_logger.explore(
                    "Update banner content failed",
                    extra={"dashboard_id": dashboard_id},
                    error=str(e),
                )
                raise
    # #endregion update_banner_on_dashboard


    # #region get_dashboard_layout [C:3] [TYPE Function]
    # @BRIEF Fetch the position_json layout of a dashboard.
    # @PRE dashboard_id exists.
    # @POST Returns the dashboard layout dict.
    def get_dashboard_layout(self, dashboard_id: int) -> dict:
        with belief_scope("SupersetDashboardsWriteMixin.get_dashboard_layout", f"dashboard_id={dashboard_id}"):
            app_logger.reason("Fetching layout", extra={"dashboard_id": dashboard_id})
            try:
                dashboard = cast(dict, self.network.request(method="GET", endpoint=f"/dashboard/{dashboard_id}"))
                result = dashboard.get("result", dashboard)
                layout = parse_position_json(result.get("position_json", "{}"))
                app_logger.reflect("Layout fetched", extra={"dashboard_id": dashboard_id, "items": len(layout)})
                return layout
            except Exception as e:
                app_logger.explore("Fetch layout failed", extra={"dashboard_id": dashboard_id}, error=str(e))
                raise
    # #endregion get_dashboard_layout

    # #region _resolve_markdown_datasource [C:2] [TYPE Function]
    # @BRIEF Find a valid datasource_id for markdown chart creation.
    # @PRE dashboard_id exists.
    # @POST Returns an integer datasource_id.
    def _resolve_markdown_datasource(self, dashboard_id: int) -> int:
        with belief_scope("_resolve_markdown_datasource", f"dashboard_id={dashboard_id}"):
            try:
                datasets_response = cast(dict, self.network.request(
                    method="GET", endpoint=f"/dashboard/{dashboard_id}/datasets"
                ))
                datasets = datasets_response.get("result", [])
                if datasets:
                    ds_id = datasets[0].get("id")
                    if ds_id:
                        return int(ds_id)
            except Exception:
                app_logger.explore("Dashboard datasets fetch failed, falling back",
                                   extra={"dashboard_id": dashboard_id}, error="Dashboard datasets endpoint failed")
            try:
                all_ds = cast(dict, self.network.request(
                    method="GET", endpoint="/dataset/",
                    params={"q": json.dumps({"columns": ["id"], "page_size": 1, "page": 0})},
                ))
                ds_list = all_ds.get("result", [])
                if ds_list:
                    ds_id = ds_list[0].get("id")
                    if ds_id:
                        return int(ds_id)
            except Exception:
                app_logger.explore("No datasets available", extra={}, error="Global dataset list failed")
            raise RuntimeError("Cannot create markdown chart: no datasets available in Superset.")
    # #endregion _resolve_markdown_datasource

# #endregion SupersetDashboardsWriteMixin
# #endregion SupersetDashboardsWriteMixin
