"""Modal state management for proper terminal state isolation.

This module provides comprehensive terminal state management for modals,
ensuring complete isolation from the conversation system and proper
restoration of terminal state when modals are closed.
"""

import logging
import re
from typing import List, Dict, Any, Optional, Tuple
from dataclasses import dataclass, field
from enum import Enum

from ..io.terminal_state import TerminalState

logger = logging.getLogger(__name__)


class ModalDisplayMode(Enum):
    """Modal display modes for different rendering strategies."""
    OVERLAY = "overlay"        # Modal overlays existing content
    FULLSCREEN = "fullscreen"  # Modal takes full screen
    INLINE = "inline"          # Modal appears inline (not recommended)


@dataclass
class TerminalSnapshot:
    """Complete snapshot of terminal state before modal display."""
    cursor_position: Tuple[int, int] = (0, 0)
    cursor_visible: bool = True
    terminal_size: Tuple[int, int] = (80, 24)
    screen_buffer: List[str] = field(default_factory=list)
    raw_mode_active: bool = False
    saved_termios: Any = None

    def __post_init__(self):
        """Post-initialization validation."""
        if not isinstance(self.screen_buffer, list):
            self.screen_buffer = []


@dataclass
class ModalLayout:
    """Modal layout configuration for positioning and sizing."""
    width: int = 80
    height: int = 20
    start_row: int = 5
    start_col: int = 10
    center_horizontal: bool = True
    center_vertical: bool = True
    padding: int = 2
    border_style: str = "box"  # "box", "simple", "none"


class ModalStateManager:
    """Manages terminal state isolation for modal displays.

    This class provides complete terminal state management for modals,
    ensuring that modal display and interaction never interferes with
    the underlying conversation or terminal state.
    """

    def __init__(self, terminal_state: TerminalState):
        """Initialize modal state manager.

        Args:
            terminal_state: TerminalState instance for terminal control.
        """
        self.terminal_state = terminal_state
        self.modal_active = False
        self.display_mode = ModalDisplayMode.OVERLAY
        self.saved_snapshot: Optional[TerminalSnapshot] = None
        self.current_layout: Optional[ModalLayout] = None
        self.modal_content_cache: List[str] = []

    def _strip_ansi(self, text: str) -> str:
        """Remove ANSI escape codes from text.

        Args:
            text: Text with potential ANSI codes.

        Returns:
            Text with ANSI codes removed.
        """
        return re.sub(r'\033\[[0-9;]*m', '', text)

    def prepare_modal_display(self, layout: ModalLayout,
                            display_mode: ModalDisplayMode = ModalDisplayMode.OVERLAY) -> bool:
        """Prepare terminal for modal display by saving current state.

        Args:
            layout: Modal layout configuration.
            display_mode: How modal should be displayed.

        Returns:
            True if preparation was successful.
        """
        try:
            if self.modal_active:
                logger.warning("Modal already active, closing previous modal first")
                self.restore_terminal_state()

            # Save current terminal state
            self.saved_snapshot = self._capture_terminal_snapshot()
            if not self.saved_snapshot:
                logger.error("Failed to capture terminal snapshot")
                return False

            # Store modal configuration
            self.current_layout = layout
            self.display_mode = display_mode

            # Calculate final layout positions
            self._calculate_modal_position(layout)

            # Prepare terminal for modal rendering
            self._prepare_modal_area()

            self.modal_active = True
            logger.info(f"Modal display prepared in {display_mode.value} mode")
            return True

        except Exception as e:
            logger.error(f"Failed to prepare modal display: {e}")
            return False

    def render_modal_content(self, content_lines: List[str]) -> bool:
        """Render modal content using isolated terminal output.

        Args:
            content_lines: Modal content lines to display.

        Returns:
            True if rendering was successful.
        """
        try:
            if not self.modal_active or not self.current_layout:
                logger.error("Modal not active or layout not configured")
                return False

            # Cache content for refresh operations
            self.modal_content_cache = content_lines.copy()

            # Clear previous modal content
            self._clear_modal_content_area()

            # Render new content using direct terminal output
            success = self._render_content_direct(content_lines)

            if success:
                logger.debug(f"Modal content rendered: {len(content_lines)} lines")
            else:
                logger.error("Failed to render modal content")

            return success

        except Exception as e:
            logger.error(f"Failed to render modal content: {e}")
            return False

    def refresh_modal_display(self) -> bool:
        """Refresh modal display without state changes.

        This method re-renders the current modal content without
        affecting any terminal state or conversation buffers.

        Returns:
            True if refresh was successful.
        """
        try:
            if not self.modal_active:
                return False

            # Re-render cached content
            return self.render_modal_content(self.modal_content_cache)

        except Exception as e:
            logger.error(f"Failed to refresh modal display: {e}")
            return False

    def restore_terminal_state(self) -> bool:
        """Restore terminal state to pre-modal condition.

        Returns:
            True if restoration was successful.
        """
        try:
            if not self.modal_active:
                return True

            # Clear modal content area
            self._clear_modal_content_area()

            # Restore terminal state from snapshot
            if self.saved_snapshot:
                self._restore_from_snapshot(self.saved_snapshot)

            # Reset modal state
            self._reset_modal_state()

            logger.info("Terminal state restored after modal")
            return True

        except Exception as e:
            logger.error(f"Failed to restore terminal state: {e}")
            return False

    def update_modal_layout(self, new_layout: ModalLayout) -> bool:
        """Update modal layout and re-render.

        Args:
            new_layout: New layout configuration.

        Returns:
            True if layout update was successful.
        """
        try:
            if not self.modal_active:
                return False

            # Clear current modal area
            self._clear_modal_content_area()

            # Update layout
            self.current_layout = new_layout
            self._calculate_modal_position(new_layout)

            # Re-render with new layout
            return self.render_modal_content(self.modal_content_cache)

        except Exception as e:
            logger.error(f"Failed to update modal layout: {e}")
            return False

    def _capture_terminal_snapshot(self) -> Optional[TerminalSnapshot]:
        """Capture complete terminal state snapshot.

        Returns:
            TerminalSnapshot or None if capture failed.
        """
        try:

            # Get current terminal dimensions
            width, height = self.terminal_state.get_size()

            # Check cursor hidden state
            cursor_hidden = getattr(self.terminal_state, '_cursor_hidden', False)

            # Check current mode
            current_mode = getattr(self.terminal_state, 'current_mode', None)

            mode_value = current_mode.value if current_mode and hasattr(current_mode, 'value') else 'unknown'

            # Check original termios
            original_termios = getattr(self.terminal_state, 'original_termios', None)

            # SWITCH TO ALTERNATE SCREEN BUFFER (automatically saves entire screen)
            alternate_buffer_success = self.terminal_state.write_raw("\033[?1049h")

            # Create minimal snapshot (alternate buffer handles everything)
            snapshot = TerminalSnapshot(
                cursor_position=(0, 0),  # Not needed - alternate buffer preserves this
                cursor_visible=not cursor_hidden,
                terminal_size=(width, height),
                screen_buffer=[],  # Not needed - alternate buffer handles screen content
                raw_mode_active=mode_value == "raw",
                saved_termios=original_termios
            )

            return snapshot

        except Exception as e:
            logger.error(f"Failed to capture terminal snapshot: {e}")
            import traceback
            logger.error(f"Full traceback: {traceback.format_exc()}")
            return None

    def _restore_from_snapshot(self, snapshot: TerminalSnapshot) -> bool:
        """Restore terminal state from snapshot.

        Args:
            snapshot: TerminalSnapshot to restore from.

        Returns:
            True if restoration was successful.
        """
        try:
            # SWITCH BACK FROM ALTERNATE SCREEN BUFFER (automatically restores entire screen)
            restore_buffer_success = self.terminal_state.write_raw("\033[?1049l")

            # Restore cursor visibility (alternate buffer preserves position automatically)
            if snapshot.cursor_visible:
                self.terminal_state.show_cursor()
            else:
                self.terminal_state.hide_cursor()

            return True

        except Exception as e:
            logger.error(f"Failed to restore from snapshot: {e}")
            return False

    def _calculate_modal_position(self, layout: ModalLayout) -> None:
        """Calculate modal position based on layout configuration.

        Args:
            layout: ModalLayout configuration.
        """
        width, height = self.terminal_state.get_size()

        if layout.center_horizontal:
            layout.start_col = max(0, (width - layout.width) // 2)

        if layout.center_vertical:
            layout.start_row = max(0, (height - layout.height) // 2)


    def _prepare_modal_area(self) -> bool:
        """Prepare terminal area for modal rendering.

        Returns:
            True if preparation was successful.
        """
        try:
            # Hide cursor for clean modal display
            self.terminal_state.hide_cursor()

            # FIXED: Always clear alternate buffer for clean modal display
            # Clear entire alternate buffer and position cursor at top-left
            self.terminal_state.write_raw("\033[2J\033[H")

            # Additional preparation based on display mode
            if self.display_mode == ModalDisplayMode.FULLSCREEN:
                # Already cleared above, but add any fullscreen-specific setup here
                pass

            logger.debug("Terminal area prepared for modal")
            return True

        except Exception as e:
            logger.error(f"Failed to prepare modal area: {e}")
            return False

    def _render_content_direct(self, content_lines: List[str]) -> bool:
        """Render content using direct terminal output.

        Args:
            content_lines: Content lines to render.

        Returns:
            True if rendering was successful.
        """
        try:
            if not self.current_layout:
                return False

            layout = self.current_layout

            # Render each line at calculated position
            for i, line in enumerate(content_lines):
                if i >= layout.height:
                    break  # Don't exceed modal height

                # Calculate position for this line
                row = layout.start_row + i + 1  # 1-based positioning
                col = layout.start_col + 1      # 1-based positioning

                # Position cursor and write line
                self.terminal_state.write_raw(f"\033[{row};{col}H")

                # Truncate line if too wide
                # Don't truncate here - lines should already be properly sized by modal renderer
                # Just write the line as-is

                self.terminal_state.write_raw(line)

            logger.debug(f"Modal content rendered: {len(content_lines)} lines")
            return True

        except Exception as e:
            logger.error(f"Failed to render content directly: {e}")
            return False

    def _clear_modal_content_area(self) -> bool:
        """Clear the modal content area.

        Returns:
            True if area was cleared successfully.
        """
        try:
            if not self.current_layout:
                return True

            layout = self.current_layout

            # Clear each line of the modal area with spaces (overwrite modal content)
            for i in range(layout.height):
                row = layout.start_row + i + 1  # 1-based row positioning
                col = layout.start_col + 1      # 1-based col positioning

                # Position cursor at start of this modal line
                self.terminal_state.write_raw(f"\033[{row};{col}H")

                # Write spaces to overwrite modal content for this line
                spaces = " " * layout.width
                self.terminal_state.write_raw(spaces)

            logger.debug("Modal content area cleared")
            return True

        except Exception as e:
            logger.error(f"Failed to clear modal content area: {e}")
            return False

    def _reset_modal_state(self) -> None:
        """Reset modal state variables."""
        self.modal_active = False
        self.saved_snapshot = None
        self.current_layout = None
        self.modal_content_cache = []
        self.display_mode = ModalDisplayMode.OVERLAY

    def get_modal_state_info(self) -> Dict[str, Any]:
        """Get current modal state information.

        Returns:
            Dictionary with modal state details.
        """
        return {
            "modal_active": self.modal_active,
            "display_mode": self.display_mode.value if self.display_mode else None,
            "has_saved_snapshot": self.saved_snapshot is not None,
            "content_lines_cached": len(self.modal_content_cache),
            "current_layout": {
                "width": self.current_layout.width if self.current_layout else 0,
                "height": self.current_layout.height if self.current_layout else 0,
                "position": (
                    self.current_layout.start_row if self.current_layout else 0,
                    self.current_layout.start_col if self.current_layout else 0
                )
            } if self.current_layout else None,
            "terminal_size": self.terminal_state.get_size()
        }