# File: /activities/ShowExceptionActivity.py
import traceback
from loguru import logger

from .. import Keys
from ..Activity import Activity
from ..EventTypes import KeyStroke, StopApplication
from ..printers.BottomBar import BottomBar as PBottomBar
from ..printers.HorizontalBar import HorizontalBar
from ..printers.TopBar import TopBar
from ..printers.printers import make_multiline_text


class ShowExceptionActivity(Activity):
    """
    Displays an unhandled exception traceback.

    When ESC is pressed we try to “heal” the stack:

      1. Remove (stop & unsubscribe) the activity *beneath* this one
         - that's the activity that actually raised.
      2. If something still remains underneath, we simply pop ourselves
         so the user lands in a healthy activity.
      3. If nothing remains, we shut the application down gracefully.
    """

    def __init__(self, exc: Exception):
        super().__init__()
        self.exc = exc

    def on_start(self):
        super().on_start()
        self.application.subscribe(KeyStroke, self, self.on_key_stroke)

        tb_lines = traceback.format_exception(
            type(self.exc), self.exc, self.exc.__traceback__
        )
        tb_text = "".join(tb_lines).rstrip().split("\n")

        bottom_ctx = PBottomBar.display_state()
        bottom_ctx["items"]["message"] = "Press ESC to continue or exit"

        self.display_state = {
            "top_bar": TopBar.display_state(
                items={
                    "title": "Unhandled Exception",
                    "help": "Press ESC to dismiss",
                }
            ),
            "horizontal_bar": HorizontalBar.display_state(),
            "traceback": {
                "lines": tb_text,
                "focused": False,
                "layout": {"flex": 1, "min_height": 3},
                "line_generator": make_multiline_text,
            },
            "bottom_bar": bottom_ctx,
        }

    def _remove_offending_activity(self):
        """
        Remove the activity *below* us on the stack (the one that raised).
        Returns True if something was removed.
        """
        stack = self.application.stack
        if len(stack) >= 2:
            offending = stack[-2] # -1 == self
            logger.info(
                "[ShowExceptionActivity] Removing offending activity: %s", offending
            )
            self.application._stop_activity(offending)  # graceful tear-down
            stack.remove(offending)                     # drop it from the stack

    def on_key_stroke(self, event: KeyStroke):
        if event.key != Keys.ESC:
            return

        # Try to remove the crashing activity
        self._remove_offending_activity()

        # If something healthy remains, just pop ourselves
        if len(self.application.stack) > 1:
            self.application.pop_activity()
        else:
            # Nothing left – shut down cleanly
            self.application.event_queue.put(StopApplication())
