# *************************************************************************
#
#  Copyright (c) 2026 - Datatailr Inc.
#  All Rights Reserved.
#
#  This file is part of Datatailr and subject to the terms and conditions
#  defined in 'LICENSE.txt'. Unauthorized copying and/or distribution
#  of this file, in parts or full, via any medium is strictly prohibited.
# *************************************************************************

from __future__ import annotations

import math
import datetime
from typing import Callable

from datatailr import Environment
from datatailr.wrapper import dt__Job, dt__Log
from datatailr.scheduler.batch import Workflow
from datatailr.scheduler.arguments_cache import ArgumentsCache

_WIDGET_DEPS_MISSING: list[str] = []
try:
    import networkx as nx  # type: ignore[import-untyped, import-not-found]
except ImportError:
    _WIDGET_DEPS_MISSING.append("networkx")
try:
    from ipycytoscape import CytoscapeWidget  # type: ignore[import-not-found]
except ImportError:
    _WIDGET_DEPS_MISSING.append("ipycytoscape")
try:
    import ipywidgets as widgets  # type: ignore[import-untyped, import-not-found]
except ImportError:
    _WIDGET_DEPS_MISSING.append("ipywidgets")
try:
    from IPython.display import display, HTML  # type: ignore[import-not-found]
except ImportError:
    _WIDGET_DEPS_MISSING.append("IPython")

__job_client__ = dt__Job()
__log_client__ = dt__Log()

_H = "28px"

_STATE_COLORS = {
    "completed": "#3aceac",
    "failed": "#ff4344",
    "failed_after": "#ff4344",
    "out_of_memory": "#ff4344",
    "expired": "#ff4344",
    "stopped": "#ff4344",
    "created": "#ff4344",
    "unknown": "#ff4344",
    "running": "hsl(50, 65%, 65%)",
    "pending": "hsl(300, 60%, 70%)",
    "starting": "hsl(300, 60%, 85%)",
    "building": "hsl(300, 60%, 70%)",
    "ready": "hsl(200, 65%, 65%)",
    "scheduled": "#3aceac",
    "did_not_run": "hsl(220, 0%, 65%)",
}

_DARK_TEXT_STATES = {
    "running",
    "pending",
    "starting",
    "building",
    "ready",
    "did_not_run",
}

_DT_CSS = """
<style>
.dt-w {
    font-family: 'Inter','Open Sans',system-ui,sans-serif; font-size:13px;
    --dt-fg:       var(--jp-ui-font-color1, #596571);
    --dt-fg-muted: var(--jp-ui-font-color2, #848e98);
    --dt-fg-bold:  var(--jp-ui-font-color0, #3c4249);
    --dt-bg:       var(--jp-layout-color1, #fff);
    --dt-bg-alt:   var(--jp-layout-color2, #f5f6f8);
    --dt-border:   var(--jp-border-color1, #e8eaed);
    --dt-border-light: var(--jp-border-color2, #f0f1f3);
    --dt-input-bg: var(--jp-layout-color1, #fff);
    --dt-input-border: var(--jp-border-color1, #d2d9e1);
    color: var(--dt-fg);
}
.dt-w * { box-sizing:border-box; }

/* inputs */
.dt-w .widget-dropdown>select,
.dt-w .widget-datepicker>input,
.dt-w .widget-timepicker>input,
.dt-w .widget-inttext input {
    border-radius:6px!important; border:1px solid var(--dt-input-border)!important;
    background:var(--dt-input-bg)!important; color:var(--dt-fg)!important;
    font-family:inherit!important; font-size:12px!important;
    height:28px!important; padding:0 7px!important;
}
.dt-w .widget-dropdown>select { height:28px!important; }
.dt-w .widget-dropdown>label,
.dt-w .widget-inline-hbox>label,
.dt-w .widget-inttext>label {
    font-family:inherit!important; font-size:12px!important;
    color:var(--dt-fg-muted)!important; font-weight:500!important;
    line-height:28px!important; padding-right:4px!important;
}

/* buttons */
.dt-w .widget-button {
    border-radius:6px!important; border:1px solid var(--dt-input-border)!important;
    background:var(--dt-bg)!important; font-family:inherit!important;
    font-size:11px!important; font-weight:500!important;
    color:var(--dt-fg)!important; height:28px!important; padding:0 8px!important;
    cursor:pointer!important;
    display:inline-flex!important; align-items:center!important;
    justify-content:center!important; line-height:1!important;
}
.dt-w .widget-button:hover { background:var(--dt-bg-alt)!important; border-color:var(--dt-fg-muted)!important; }
.dt-w .dt-accent {
    background:#3aceac!important; border-color:#3aceac!important;
    color:#fff!important; font-size:12px!important;
}
.dt-w .dt-accent:hover { background:#2fb893!important; border-color:#2fb893!important; }

/* labels */
.dt-w .widget-label {
    font-family:inherit!important; font-size:13px!important; color:var(--dt-fg)!important;
}

/* run table */
.dt-w .dt-table {
    border:1px solid var(--dt-border)!important; border-radius:10px!important;
    overflow:hidden!important;
}

/* hint box */
.dt-w .dt-hint {
    background:var(--dt-bg-alt)!important; border-radius:8px!important;
    padding:10px 14px!important; border:1px solid var(--dt-border)!important;
}
.dt-w .dt-hint .widget-label {
    font-family:Monaco,'Courier New',monospace!important;
    font-size:12px!important; color:var(--dt-fg-bold)!important;
}

/* tabs */
.dt-w .widget-tab>.p-TabBar .p-TabBar-tab {
    font-family:inherit!important; font-size:12px!important; font-weight:500!important;
}

/* cytoscape graph - transparent background */
[class*="cytoscape"] { background:transparent!important; }
[class*="cytoscape"] > div { background:transparent!important; }
[class*="cytoscape"] canvas { background:transparent!important; }

/* scrollable tab pane */
.dt-scroll-pane { max-height:400px!important; overflow-y:auto!important; overflow-x:auto!important; }
.dt-scroll-pane .widget-output { overflow:visible!important; }
</style>
"""


class ResultViewerWidget:
    def __init__(self, environment: Environment = Environment.DEV):
        self._available = not _WIDGET_DEPS_MISSING
        if not self._available:
            pkgs = ", ".join(_WIDGET_DEPS_MISSING)
            req = " ".join(_WIDGET_DEPS_MISSING)
            print(
                f"\033[33m"
                f"The workflow results explorer requires packages that are not installed: {pkgs}\n"
                f"Add them to python_requirements in your workstation definition:\n\n"
                f'    python_requirements="{req}"\033[0m'
            )
            return
        self.environment = environment
        self.batch: Workflow | None = None
        self.all_runs: list[dict] = []
        self._current_run: dict = {}

        h = _H
        self.workflow_dropdown = widgets.Dropdown(
            description="Workflow:",
            layout=widgets.Layout(width="340px", height=h),
        )
        self.env_dropdown = widgets.Dropdown(
            options=[
                ("Dev", Environment.DEV),
                ("Pre", Environment.PRE),
                ("Prod", Environment.PROD),
            ],
            value=self.environment,
            description="Env:",
            layout=widgets.Layout(width="140px", height=h),
        )
        self.refresh_button = widgets.Button(
            description="\u21bb Refresh", layout=widgets.Layout(width="90px", height=h)
        )
        self.refresh_button.on_click(lambda btn: self._on_workflow_selected(None))
        self.env_dropdown.observe(self._on_environment_changed, names="value")
        self.workflow_dropdown.observe(self._on_workflow_selected, names="value")

        self.start_date_picker = widgets.DatePicker(
            layout=widgets.Layout(width="130px", height=h)
        )
        self.start_time_picker = widgets.TimePicker(
            value=datetime.time(0, 0), layout=widgets.Layout(width="90px", height=h)
        )
        self.end_date_picker = widgets.DatePicker(
            layout=widgets.Layout(width="130px", height=h)
        )
        self.end_time_picker = widgets.TimePicker(
            value=datetime.time(0, 0), layout=widgets.Layout(width="90px", height=h)
        )
        self.apply_button = widgets.Button(
            description="Apply", layout=widgets.Layout(width="56px", height=h)
        )

        self.apply_button.on_click(lambda btn: self._load_display_runs())

        self.runs_per_page = 8
        self.n_runs = 0
        self.page = 1

        self.prev_button = widgets.Button(
            description="\u276e", layout=widgets.Layout(width="28px", height=h)
        )
        self.next_button = widgets.Button(
            description="\u276f", layout=widgets.Layout(width="28px", height=h)
        )
        self.page_html = widgets.HTML("")
        self._wire_pagination()

        self.run_table_output = widgets.Output()
        self.graph_output = widgets.Output()
        self.result_output = widgets.Output()
        self.stdout_output = widgets.Output()
        self.stderr_output = widgets.Output()
        stdout_pane = widgets.VBox([self.stdout_output])
        stderr_pane = widgets.VBox([self.stderr_output])
        result_pane = widgets.VBox([self.result_output])
        for pane in (stdout_pane, stderr_pane, result_pane):
            pane.add_class("dt-scroll-pane")
        self.preview_tabs = widgets.Tab(
            titles=["Stdout", "Stderr", "Result"],
            children=[stdout_pane, stderr_pane, result_pane],
            layout=widgets.Layout(visibility="hidden"),
        )
        self.tab_switch_handler: Callable[[dict], None] | None = None

        self._load_workflow_list()

    # ------------------------------------------------------------------

    def _html_label(self, text: str) -> widgets.HTML:
        return widgets.HTML(
            f'<span style="font-size:12px;color:var(--dt-fg-muted,#848e98);font-weight:500;'
            f'line-height:{_H};white-space:nowrap;">{text}</span>'
        )

    def display(self):
        if not self._available:
            return
        display(HTML(_DT_CSS))
        self.refresh_button.add_class("dt-accent")
        self.apply_button.add_class("dt-accent")

        top_row = widgets.HBox(
            [self.workflow_dropdown, self.env_dropdown, self.refresh_button],
            layout=widgets.Layout(align_items="center", gap="6px"),
        )
        filter_row = widgets.HBox(
            [
                self._html_label("From"),
                self.start_date_picker,
                self.start_time_picker,
                self._html_label("To"),
                self.end_date_picker,
                self.end_time_picker,
                self.apply_button,
            ],
            layout=widgets.Layout(align_items="center", gap="4px"),
        )
        page_row = widgets.HBox(
            [self.prev_button, self.page_html, self.next_button],
            layout=widgets.Layout(align_items="center", gap="4px"),
        )

        left_panel = widgets.VBox(
            [filter_row, self.run_table_output, page_row],
            layout=widgets.Layout(flex="0 0 auto", gap="6px"),
        )
        right_panel = widgets.VBox(
            [self.graph_output],
            layout=widgets.Layout(flex="1 1 auto"),
        )
        upper_row = widgets.HBox(
            [left_panel, right_panel],
            layout=widgets.Layout(gap="20px"),
        )

        container = widgets.VBox(
            [top_row, upper_row, self.preview_tabs],
            layout=widgets.Layout(gap="10px"),
        )
        container.add_class("dt-w")
        display(container)

    # ------------------------------------------------------------------
    # Workflow loading
    # ------------------------------------------------------------------

    def _load_workflow_list(self):
        try:
            jobs = __job_client__.ls(
                filter=f"type=batch,environment={self.environment}"
            )
            if isinstance(jobs, list):
                names = sorted({j.get("display_name", j.get("name", "")) for j in jobs})
            else:
                names = []
        except Exception:
            names = []

        if names:
            self.workflow_dropdown.options = [("-- select workflow --", None)] + [
                (n, n) for n in names
            ]
        else:
            self.workflow_dropdown.options = [("No workflows found", None)]
        self.workflow_dropdown.value = None

    def select_workflow(self, name: str):
        """Programmatically select a workflow by display name."""
        if not self._available:
            return
        options = [v for _, v in self.workflow_dropdown.options if v is not None]
        if name in options:
            self.workflow_dropdown.value = name
        else:
            self.workflow_dropdown.value = None
            self.run_table_output.clear_output()
            with self.run_table_output:
                display(widgets.Label(f"Workflow '{name}' not found"))

    def _on_environment_changed(self, change):
        self.environment = change["new"]
        self._load_workflow_list()

    def _on_workflow_selected(self, change):
        selected = self.workflow_dropdown.value
        if not selected:
            self.batch = None
            self.all_runs = []
            self.run_table_output.clear_output()
            self.graph_output.clear_output()
            self.preview_tabs.layout.visibility = "hidden"
            return
        try:
            self.batch = Workflow(
                name=selected, environment=self.environment, get_existing=True
            )
            self.all_runs = self.batch.runs(refresh=True)
        except Exception as e:
            self.batch = None
            self.all_runs = []
            self.run_table_output.clear_output()
            with self.run_table_output:
                display(widgets.Label(f"Could not load workflow: {e}"))
            return

        self.page = 1
        self.n_runs = 0
        self._load_display_runs()

    # ------------------------------------------------------------------
    # Pagination
    # ------------------------------------------------------------------

    def _wire_pagination(self):
        def update():
            if self.n_runs == 0:
                self.page_html.value = '<span style="font-size:12px;color:var(--dt-fg-muted,#848e98);line-height:28px;">0 of 0</span>'
            else:
                lo = (self.page - 1) * self.runs_per_page + 1
                hi = min(self.page * self.runs_per_page, self.n_runs)
                self.page_html.value = (
                    f'<span style="font-size:12px;color:var(--dt-fg,#596571);line-height:28px;">'
                    f"<b>{lo}\u2013{hi}</b> of {self.n_runs}</span>"
                )

        self.update_page_label = update

        def on_next(btn):
            if self.page < math.ceil(self.n_runs / self.runs_per_page):
                self.page += 1
                self._load_display_runs()
                update()

        def on_prev(btn):
            if self.page > 1:
                self.page -= 1
                self._load_display_runs()
                update()

        self.prev_button.on_click(on_prev)
        self.next_button.on_click(on_next)
        update()

    # ------------------------------------------------------------------
    # Run table
    # ------------------------------------------------------------------

    def _apply_date_filter(self, runs: list[dict]) -> list[dict]:
        range_start = None
        range_end = None
        if self.start_date_picker.value:
            range_start = datetime.datetime.combine(
                self.start_date_picker.value,
                self.start_time_picker.value or datetime.time(0, 0),
            )
        if self.end_date_picker.value:
            range_end = datetime.datetime.combine(
                self.end_date_picker.value,
                self.end_time_picker.value or datetime.time(0, 0),
            )
        if not range_start and not range_end:
            return runs
        filtered = []
        for r in runs:
            st = r.get("start_time")
            if not isinstance(st, datetime.datetime):
                continue
            if range_start and st < range_start:
                continue
            if range_end and st > range_end:
                continue
            filtered.append(r)
        return filtered

    def _load_display_runs(self):
        self.run_table_output.clear_output(wait=True)
        if not self.batch:
            with self.run_table_output:
                display(widgets.Label("Select a workflow to view runs"))
            return
        try:
            runs = self._apply_date_filter(self.all_runs)
        except Exception as e:
            with self.run_table_output:
                display(widgets.Label(f"Could not load runs. Reason: {e}"))
            return
        if not runs:
            with self.run_table_output:
                display(widgets.Label("No runs found"))
            self.n_runs = 0
            self.update_page_label()
            return

        if self.n_runs != len(runs):
            self.page = 1
            self.n_runs = len(runs)
            self.update_page_label()
        page_runs = runs[
            (self.page - 1) * self.runs_per_page : self.page * self.runs_per_page
        ]
        runs_table = self._build_run_table(page_runs)
        with self.run_table_output:
            display(runs_table)

    @staticmethod
    def _badge(state: str) -> str:
        color = _STATE_COLORS.get(state, "hsl(220,0%,65%)")
        fg = "#3c4249" if state in _DARK_TEXT_STATES else "#fff"
        label = state.replace("_", " ")
        return (
            f'<span style="background:{color};color:{fg};border-radius:9999px;'
            f"padding:2px 9px;font-size:11px;font-weight:600;"
            f'font-family:inherit;white-space:nowrap;">{label}</span>'
        )

    def _build_run_table(self, runs):
        if not runs:
            return widgets.Label("No runs found")

        n_cols = 4
        rh = "32px"
        hdr_css = (
            "font-size:10px;font-weight:600;color:var(--dt-fg-muted,#848e98);text-transform:uppercase;"
            "letter-spacing:.5px;line-height:32px;padding:0 10px;white-space:nowrap;"
            "background:var(--dt-bg-alt,#f9fafb);border-bottom:1px solid var(--dt-border,#e8eaed);"
        )
        cell_css = "font-size:13px;color:var(--dt-fg-bold,#3c4249);line-height:32px;padding:0 10px;white-space:nowrap;"

        empty_hdr = "line-height:32px;background:var(--dt-bg-alt,#f9fafb);border-bottom:1px solid var(--dt-border,#e8eaed);"
        cells: list[widgets.Widget] = [
            widgets.HTML(f'<span style="{hdr_css}">Start Time</span>'),
            widgets.HTML(f'<span style="{empty_hdr}">&nbsp;</span>'),
            widgets.HTML(f'<span style="{empty_hdr}">&nbsp;</span>'),
            widgets.HTML(f'<span style="{empty_hdr}">&nbsp;</span>'),
        ]

        for i, run in enumerate(runs):
            bdr = (
                ""
                if i == len(runs) - 1
                else "border-bottom:1px solid var(--dt-border-light,#f0f1f3);"
            )

            st = run.get("start_time")
            t = (
                st.strftime("%Y-%m-%d %H:%M:%S")
                if isinstance(st, datetime.datetime)
                else "\u2014"
            )
            cells.append(widgets.HTML(f'<span style="{cell_css}{bdr}">{t}</span>'))

            cells.append(
                widgets.HTML(
                    f'<span style="line-height:{rh};padding:0 10px;display:flex;align-items:center;{bdr}">'
                    f'{self._badge(run.get("state", ""))}</span>'
                )
            )

            v = run.get("job_version")
            v_text = f"v{v}" if v is not None else "\u2014"
            cells.append(widgets.HTML(f'<span style="{cell_css}{bdr}">{v_text}</span>'))

            pb = widgets.Button(
                description="Preview",
                layout=widgets.Layout(width="64px", height="24px"),
            )
            pb.add_class("dt-accent")
            pb.on_click(lambda btn, r=run: self._preview_batch_run(r))
            cells.append(pb)

        grid = widgets.GridBox(
            cells,
            layout=widgets.Layout(
                grid_template_columns=f"repeat({n_cols}, auto)",
                grid_auto_rows="auto",
                width="max-content",
                align_items="center",
            ),
        )
        grid.add_class("dt-table")
        return grid

    # ------------------------------------------------------------------
    # Graph display (DAG from task dependencies)
    # ------------------------------------------------------------------

    def _preview_batch_run(self, run: dict):
        self._current_run = run
        self.graph_output.clear_output(wait=True)
        tasks = run.get("tasks", [])
        if not tasks:
            with self.graph_output:
                display(widgets.Label("No task data available for this run"))
            self.preview_tabs.layout.visibility = "hidden"
            return
        self.preview_tabs.layout.visibility = "hidden"
        self._load_display_graph(tasks)

    def _load_display_graph(self, tasks: list[dict]):
        task_id_to_name = {t["task_id"]: t["name"] for t in tasks if "task_id" in t}

        nodes = []
        edges = []
        roots = []
        statuses = {}
        for t in tasks:
            name = t["name"]
            nodes.append(name)
            statuses[name] = t.get("state", "pending")
            deps = t.get("dependencies", [])
            if not deps:
                roots.append(name)
            for dep_id in deps:
                dep_name = task_id_to_name.get(dep_id)
                if dep_name:
                    edges.append((dep_name, name))

        G: nx.DiGraph = nx.DiGraph()
        G.add_nodes_from(nodes)
        G.add_edges_from(edges)

        for node in G.nodes():
            G.nodes[node]["status"] = statuses.get(node, "pending")
            task = next((t for t in tasks if t["name"] == node), None)
            G.nodes[node]["task_name"] = node
            G.nodes[node]["task_id"] = (
                task["task_id"] if task and "task_id" in task else None
            )

        cyto_widget: CytoscapeWidget = CytoscapeWidget()
        cyto_widget.graph.add_graph_from_networkx(G)

        cyto_widget.set_layout(
            name="klay",
            roots=roots,
            spacingFactor=1.1,
            padding=5,
            nodeDimensionsIncludeLabels=True,
            klay={"compactComponents": True},
        )

        styles: list[dict] = [
            {
                "selector": "core",
                "style": {
                    "active-bg-size": 0,
                },
            },
            {
                "selector": "node",
                "style": {
                    "label": "data(id)",
                    "font-family": "Inter, Open Sans, sans-serif",
                    "font-size": "11px",
                    "font-weight": "500",
                    "text-valign": "center",
                    "text-halign": "center",
                    "text-wrap": "wrap",
                    "text-max-width": "140px",
                    "color": "#fff",
                    "background-color": "hsl(220, 0%, 50%)",
                    "shape": "roundrectangle",
                    "width": "label",
                    "height": "label",
                    "padding-left": "10px",
                    "padding-right": "10px",
                    "padding-top": "8px",
                    "padding-bottom": "8px",
                    "border-width": 0,
                    "border-radius": "8px",
                },
            },
            {
                "selector": "edge",
                "style": {
                    "line-color": "#888",
                    "width": 2,
                    "target-arrow-shape": "triangle",
                    "target-arrow-color": "#888",
                    "curve-style": "bezier",
                    "source-endpoint": "90deg",
                },
            },
        ]
        for state, color in _STATE_COLORS.items():
            styles.append(
                {
                    "selector": f'node[status = "{state}"]',
                    "style": {
                        "background-color": color,
                        "border-color": color,
                        "color": "#3c4249" if state in _DARK_TEXT_STATES else "#fff",
                    },
                }
            )
        cyto_widget.set_style(styles)

        cyto_widget.zooming_enabled = True
        cyto_widget.min_zoom = 0.1
        cyto_widget.max_zoom = 10.0
        cyto_widget.wheel_sensitivity = 0.1

        def on_node_click(node):
            task_name = node["data"].get("task_name")
            task_id = node["data"].get("task_id")
            self._preview_task_run(task_name, task_id)

        cyto_widget.on("node", "click", on_node_click)
        self.graph_output.clear_output()
        with self.graph_output:
            display(cyto_widget)

    # ------------------------------------------------------------------
    # Task preview (logs + result)
    # ------------------------------------------------------------------

    def _preview_task_run(self, task_name: str, task_id: int | None):
        for tab in self.preview_tabs.children:
            if isinstance(tab, (widgets.HBox, widgets.VBox)) and tab.children:
                tab.children[0].clear_output()
            elif isinstance(tab, widgets.Output):
                tab.clear_output()
        self.preview_tabs.layout.visibility = "visible"
        if self.tab_switch_handler:
            self.preview_tabs.unobserve(self.tab_switch_handler, names="selected_index")
        tab_is_loaded = [False] * 3

        def on_preview_change(change):
            new_tab = change["new"]
            if new_tab < len(tab_is_loaded) and not tab_is_loaded[new_tab]:
                if new_tab == 0:
                    self._load_display_logs(task_name, task_id, "stdout")
                elif new_tab == 1:
                    self._load_display_logs(task_name, task_id, "stderr")
                elif new_tab == 2:
                    self._load_display_task_result(task_name, task_id)
                tab_is_loaded[new_tab] = True

        on_preview_change({"new": self.preview_tabs.selected_index})
        self.tab_switch_handler = on_preview_change
        self.preview_tabs.observe(
            handler=on_preview_change, names="selected_index", type="change"
        )

    # ------------------------------------------------------------------
    # Logs via dt__Log
    # ------------------------------------------------------------------

    def _load_display_logs(self, task_name: str, task_id: int | None, log_type: str):
        output = self.stdout_output if log_type == "stdout" else self.stderr_output
        output.clear_output()
        if not self.batch or not self._current_run:
            with output:
                display(widgets.Label("Cannot determine job for logs"))
            return
        job_name = self._current_run.get("run_name", self.batch._internal_name)
        run_id = self._current_run.get("run_id")
        try:
            kwargs: dict = {"run_id": run_id}
            if task_id is not None:
                kwargs["child_num"] = task_id
            if log_type == "stderr":
                kwargs["stderr"] = True
            logs = __log_client__.read(job_name, **kwargs)
            with output:
                if logs:
                    print(logs if isinstance(logs, str) else str(logs))
                else:
                    print("(no log output)")
        except Exception as e:
            with output:
                display(
                    widgets.VBox(
                        [
                            widgets.Label("Could not load logs. Reason:"),
                            widgets.Label(str(e)),
                        ]
                    )
                )

    # ------------------------------------------------------------------
    # Result via ArgumentsCache
    # ------------------------------------------------------------------

    def _load_display_task_result(self, task_name: str, task_id: int | None):
        status_label = widgets.Label("Downloading result...")
        self.result_output.clear_output()
        result_data_output = widgets.Output()
        with self.result_output:
            display(widgets.VBox([status_label, result_data_output]))

        if not self.batch or not self._current_run:
            status_label.value = "No workflow selected"
            return

        try:
            cache = ArgumentsCache()
            batch_run_id = self._current_run.get("run_id", "")
            run_name = self._current_run.get("run_name", self.batch._internal_name)
            cache_key = f"{run_name}-{task_id}" if task_id is not None else run_name
            result = cache.get_result(batch_run_id, cache_key)
            status_label.value = f"Task: {task_name}"
            code_layout = widgets.Layout(
                padding="0px 10px 0px 10px", margin="0px", height="22px"
            )
            code_style = dict(font_family="Monaco, Courier New, monospace")
            hint = widgets.VBox(
                [
                    widgets.Label("To load this result into memory, run:"),
                    widgets.Label(
                        "from datatailr.scheduler.arguments_cache import ArgumentsCache",
                        layout=code_layout,
                        style=code_style,
                    ),
                    widgets.Label(
                        "cache = ArgumentsCache()", layout=code_layout, style=code_style
                    ),
                    widgets.Label(
                        f'result = cache.get_result({batch_run_id}, "{cache_key}")',
                        layout=code_layout,
                        style=code_style,
                    ),
                ],
                layout=widgets.Layout(width="fit-content", margin="0px 0px 10px 0px"),
            )
            hint.add_class("dt-hint")
            with result_data_output:
                display(hint)
                if result is not None and result != task_name:
                    display(result)
                else:
                    display(widgets.Label("No result stored for this task"))
        except Exception as e:
            status_label.value = f"Error occurred while loading result: {e}"
