"""Cleave TUI main screen - Interactive task decomposition interface."""

from pathlib import Path
from typing import ClassVar

from textual.app import ComposeResult
from textual.binding import Binding, BindingType
from textual.containers import Container, Vertical
from textual.screen import Screen
from textual.widgets import Footer, Header, Static

from cleave.tui.services.calf import CalfManager
from cleave.tui.services.cancellation import CancellationToken
from cleave.tui.services.sdk import (
    CleaveExecutor,
    CleaveSkillError,
    InterrogationSession,
    Message,
    SDKSession,
)
from cleave.tui.widgets.chat_panel import ChatPanel
from cleave.tui.widgets.control_panel import CleaveParams, ControlPanel
from cleave.tui.widgets.progress_panel import ProgressPanel


# Retro CRT banner with ASCII styling
CLEAVE_BANNER = "╔══ CLEAVE TUI ══╗ Recursive Task Decomposition │ Interactive Interface"


class HighlightedPanel(Vertical):
    """Simple panel wrapper with title.

    NOTE: This is a simplified version for standalone operation.
    Future integration may extract to styrene-core library.
    """

    DEFAULT_CSS = """
    HighlightedPanel {
        border: heavy #a855f7;
        padding: 0;
        background: #160028;
    }

    HighlightedPanel > .panel-title {
        dock: top;
        background: #7c3aed;
        color: #ffffff;
        text-style: bold;
        padding: 0 1;
        width: 100%;
        height: auto;
    }
    """

    def __init__(
        self,
        *children,
        title: str = "",
        name: str | None = None,
        id: str | None = None,
        classes: str | None = None,
    ) -> None:
        super().__init__(name=name, id=id, classes=classes)
        self._title = title
        self._children = children

    def compose(self) -> ComposeResult:
        """Compose title and content."""
        if self._title:
            yield Static(self._title, classes="panel-title")
        yield from self._children


class CleaveMainScreen(Screen[None]):
    """Main Cleave TUI screen for directive management and execution.

    Layout:
    - Left sidebar: Unified control panel (file list + cleave params)
    - Main area: Chat panel (dominates screen)
    - Bottom: Progress panel (hidden when idle)

    Modes:
    - Idle: Normal state, waiting for user action
    - Interrogation: Active Calf Raises session with Claude
    - Execution: Running Cleave on a directive
    """

    BINDINGS: ClassVar[list[BindingType]] = [
        Binding("q", "quit", "Quit", show=True),
        Binding("r", "refresh_files", "Refresh", show=True),
        Binding("c", "focus_chat", "Chat", show=True),
        Binding("t", "cycle_theme", "Theme", show=True),
        Binding("escape", "cancel", "Cancel", show=True),
        Binding("ctrl+c", "interrupt", "Interrupt", show=False),
        Binding("tab", "focus_next", "Next", show=False),
        Binding("shift+tab", "focus_previous", "Prev", show=False),
        Binding("f1", "focus_control", "Controls", show=False),
        Binding("f2", "focus_chat", "Chat", show=False),
    ]

    CSS = """
    CleaveMainScreen {
        layout: horizontal;
    }

    /* Left sidebar: controls */
    #control-panel {
        width: 40;
        height: 100%;
    }

    /* Main area: chat dominates */
    #main-area {
        width: 1fr;
        height: 100%;
        layout: vertical;
    }

    #banner {
        height: 1;
        text-align: center;
        color: $success;
        padding: 0;
    }

    /* Chat panel takes all remaining space */
    #chat-panel {
        height: 1fr;
    }

    /* Progress panel at bottom when active */
    #progress-panel {
        height: auto;
        display: none;
    }

    #progress-panel.visible {
        display: block;
    }
    """

    def __init__(
        self,
        working_directory: Path | None = None,
        name: str | None = None,
        id: str | None = None,
        classes: str | None = None,
    ) -> None:
        super().__init__(name=name, id=id, classes=classes)
        self.working_directory = working_directory or Path.cwd()

        # Services
        self._calf_manager = CalfManager(self.working_directory)

        # Session state
        self._interrogation: InterrogationSession | None = None
        self._executor: CleaveExecutor | None = None
        self._mode: str = "idle"  # idle, interrogation, execution
        self._editing_file: Path | None = None  # For fatten mode

        # Cancellation support
        self._cancel_token: CancellationToken | None = None

    def compose(self) -> ComposeResult:
        """Compose the main screen layout.

        Layout:
        - Left sidebar: Unified control panel
        - Main area: Banner + Chat (chat dominates)
        """
        yield Header()

        # Left sidebar: unified control panel
        yield HighlightedPanel(
            ControlPanel(id="control-widget"),
            title="[bold green]Slaughter[/] House",
            id="control-panel",
        )

        # Main area: banner + chat
        with Container(id="main-area"):
            yield Static(CLEAVE_BANNER, id="banner")

            yield HighlightedPanel(
                ChatPanel(id="chat-widget"),
                title="Chat",
                id="chat-panel",
            )

            # Progress panel at bottom (hidden when idle)
            yield HighlightedPanel(
                ProgressPanel(id="progress-widget"),
                title="Progress",
                id="progress-panel",
            )

        yield Footer()

    def on_mount(self) -> None:
        """Initialize on mount."""
        # Set up the control panel with working directory
        control = self.query_one("#control-widget", ControlPanel)
        control.directory = self.working_directory

        # Wire up callbacks
        self._wire_callbacks()

        # Check auth status
        chat = self.query_one("#chat-widget", ChatPanel)
        is_auth, auth_msg = SDKSession.check_auth()

        # Welcome message with instructions
        chat.add_message(
            "system",
            "[bold]Cleave TUI[/] — Task decomposition interface\n\n"
            "[dim]• Select a .calf and [green]Fatten[/green] to refine\n"
            "• Or [green]Raise a Calf[/green] to create new\n"
            "• [blue]CLEAVE[/blue] to execute[/]",
        )

        # Auth status
        if is_auth:
            chat.add_message("system", "[green]✓[/] Claude authenticated")
        else:
            chat.add_message("system", f"[yellow]⚠[/] {auth_msg}")

    def _wire_callbacks(self) -> None:
        """Wire up widget callbacks for integration."""
        # Chat submission
        chat = self.query_one("#chat-widget", ChatPanel)
        chat.on_submit = self._on_chat_submit

        # Control panel callbacks
        control = self.query_one("#control-widget", ControlPanel)
        control.on_file_selected = self._on_file_selected
        control.on_calf_workflow = self._on_calf_workflow
        control.on_cleave = self._on_cleave

    def _on_chat_submit(self, message: str) -> None:
        """Handle chat message submission."""
        if self._mode == "interrogation" and self._interrogation:
            # Continue interrogation flow
            self.run_worker(self._continue_interrogation(message))
        elif self._mode == "idle":
            # No active session - could start a simple query
            chat = self.query_one("#chat-widget", ChatPanel)
            chat.add_message(
                "system",
                "Start 'Calf Raises' to create a directive, or select a .calf file to execute.",
            )
        # During execution, chat input is typically ignored

    def _on_file_selected(self, path: Path) -> None:
        """Handle .calf file selection."""
        # Read and show preview in chat
        chat = self.query_one("#chat-widget", ChatPanel)
        try:
            content = self._calf_manager.read_calf(path)
            chat.add_message("system", f"Selected: {path.name}")
            chat.add_message("system", f"[dim]{content[:300]}{'...' if len(content) > 300 else ''}[/]")
        except Exception as e:
            chat.add_message("system", f"[red]Error reading file: {e}[/]")

    def _on_calf_workflow(self, mode: str, selected_file: Path | None) -> None:
        """Handle calf workflow button - raise (new) or fatten (edit)."""
        if self._mode != "idle":
            chat = self.query_one("#chat-widget", ChatPanel)
            chat.add_message("system", "Finish current operation first.")
            return

        self._mode = "interrogation"
        chat = self.query_one("#chat-widget", ChatPanel)
        chat.clear_history()

        # Read existing directive for fatten mode
        existing_directive = None
        if mode == "fatten" and selected_file:
            try:
                existing_directive = self._calf_manager.read_calf(selected_file)
                chat.add_message("system", f"Fattening: {selected_file.name}")
            except Exception as e:
                chat.add_message("system", f"[red]Error reading file: {e}[/]")
                self._mode = "idle"
                return
        else:
            chat.add_message("system", "Raising a new calf...")

        # Store selected file for later (fatten mode overwrites)
        self._editing_file = selected_file if mode == "fatten" else None

        # Create cancellation token for this operation
        self._cancel_token = CancellationToken()

        # Start session with mode
        self.run_worker(self._start_interrogation(mode, existing_directive))

    async def _start_interrogation(
        self, mode: str = "raise", existing_directive: str | None = None
    ) -> None:
        """Start the interrogation session."""
        chat = self.query_one("#chat-widget", ChatPanel)
        chat.set_loading(True)  # Show loading indicator

        try:
            self._interrogation = InterrogationSession(
                working_directory=self.working_directory,
                mode=mode,
                existing_directive=existing_directive,
            )

            async for msg in self._interrogation.start():
                # Check for cancellation
                if self._cancel_token and self._cancel_token.is_cancelled:
                    break

                chat.set_loading(False)  # Hide once streaming starts
                self._display_message(msg)

        except Exception as e:
            chat.set_loading(False)
            self._handle_error(e, "Failed to start interrogation session")
            self._mode = "idle"
            self._interrogation = None

    async def _continue_interrogation(self, user_input: str) -> None:
        """Continue the interrogation with user input."""
        if not self._interrogation:
            return

        chat = self.query_one("#chat-widget", ChatPanel)
        chat.set_loading(True)  # Show loading indicator

        # Create new cancellation token for this response
        self._cancel_token = CancellationToken()

        try:
            async for msg in self._interrogation.respond(user_input):
                # Check for cancellation
                if self._cancel_token and self._cancel_token.is_cancelled:
                    break

                chat.set_loading(False)  # Hide once streaming starts
                self._display_message(msg)

            # Check if directive was extracted
            if self._interrogation.is_complete and self._interrogation.directive:
                directive = self._interrogation.directive

                # Fatten mode: overwrite existing file
                # Raise mode: create new file
                if self._editing_file is not None:
                    # Overwrite existing
                    self._calf_manager.write_calf(self._editing_file, directive)
                    chat.add_message("system", f"Updated: {self._editing_file.name}")
                else:
                    # Create new
                    filename = self._calf_manager.generate_filename(directive[:30])
                    self._calf_manager.write_calf(filename, directive)
                    chat.add_message("system", f"Saved: {filename.name}")

                # Refresh file list
                control = self.query_one("#control-widget", ControlPanel)
                control.refresh_files()

                # Clean up
                await self._interrogation.close()
                self._interrogation = None
                self._editing_file = None
                self._mode = "idle"

        except Exception as e:
            chat.set_loading(False)
            self._handle_error(e, "Failed to continue interrogation")
            if self._interrogation:
                await self._interrogation.close()
            self._interrogation = None
            self._editing_file = None
            self._mode = "idle"

    def _on_cleave(self, params: CleaveParams) -> None:
        """Handle CLEAVE button press."""
        if self._mode != "idle":
            chat = self.query_one("#chat-widget", ChatPanel)
            chat.add_message("system", "Please finish the current operation first.")
            return

        chat = self.query_one("#chat-widget", ChatPanel)

        if params.selected_calf is None:
            chat.add_message("system", "Please select a .calf file first.")
            return

        # Read the directive
        try:
            directive = self._calf_manager.read_calf(params.selected_calf)
        except Exception as e:
            chat.add_message("system", f"[red]Error reading directive: {e}[/]")
            return

        self._mode = "execution"
        chat.add_message(
            "system",
            f"Executing Cleave on: {params.selected_calf.name}\n"
            f"Model: {params.model}, Depth: {params.max_depth}, "
            f"Parallel: {params.parallel}, Dry run: {params.dry_run}",
        )

        # Create cancellation token for this operation
        self._cancel_token = CancellationToken()

        # Start execution
        self.run_worker(self._execute_cleave(directive, params))

    async def _execute_cleave(self, directive: str, params: CleaveParams) -> None:
        """Execute the directive through Cleave."""
        chat = self.query_one("#chat-widget", ChatPanel)
        progress = self.query_one("#progress-widget", ProgressPanel)
        chat.set_loading(True)  # Show loading indicator

        try:
            self._executor = CleaveExecutor(
                directive=directive,
                model=params.model,
                max_depth=params.max_depth,
                parallel=params.parallel,
                dry_run=params.dry_run,
                working_directory=self.working_directory,
            )

            async for msg in self._executor.execute():
                # Check for cancellation
                if self._cancel_token and self._cancel_token.is_cancelled:
                    break

                chat.set_loading(False)  # Hide once streaming starts
                self._display_message(msg)

                # Update progress
                current, total = self._executor.progress
                if total > 0:
                    progress.set_progress(current, total, self._executor.current_task)

            chat.set_loading(False)
            chat.add_message("system", "Cleave execution complete.")
            progress.set_progress(0, 0, "Complete")

        except CleaveSkillError as e:
            chat.set_loading(False)
            chat.add_message(
                "system",
                f"[red]Cleave skill not available:[/] {e}\n"
                "[dim]Install the Cleave skill to ~/.claude/skills/cleave/[/]",
            )

        except Exception as e:
            chat.set_loading(False)
            self._handle_error(e, "Execution failed")

        finally:
            self._executor = None
            self._mode = "idle"

    def _display_message(self, msg: Message) -> None:
        """Display a message in the chat panel.

        Handles both complete messages and streaming tokens.
        """
        chat = self.query_one("#chat-widget", ChatPanel)

        # Check if this is a streaming message (from backend.Message)
        if hasattr(msg, "message_type"):
            from cleave.tui.backends.base import MessageType

            if msg.message_type == MessageType.STREAM_START:
                chat.set_loading(False)  # Stop loading, start streaming
                chat.start_streaming(msg.role)
                return
            elif msg.message_type == MessageType.STREAM_DELTA:
                chat.add_streaming_token(msg.content)
                return
            elif msg.message_type == MessageType.STREAM_END:
                chat.finalize_streaming()
                return

        # Complete message (non-streaming or legacy sdk.Message)
        chat.add_message(msg.role, msg.content)

    def _handle_error(self, error: Exception, context: str = "Operation failed") -> None:
        """Handle errors with user-friendly messages.

        Args:
            error: The exception that occurred.
            context: Context description for the error.
        """
        chat = self.query_one("#chat-widget", ChatPanel)

        # Import backend exceptions
        try:
            from cleave.tui.backends.base import (
                BackendAuthError,
                BackendConnectionError,
                BackendQueryError,
            )

            # Handle specific backend errors
            if isinstance(error, BackendAuthError):
                chat.add_message("system", f"[bold red]Authentication Error[/]\n\n{error}")
                return
            elif isinstance(error, BackendConnectionError):
                chat.add_message("system", f"[bold red]Connection Error[/]\n\n{error}")
                return
            elif isinstance(error, BackendQueryError):
                chat.add_message("system", f"[bold red]Query Error[/]\n\n{error}")
                return
        except ImportError:
            pass

        # Handle CleaveSkillError separately (already handled in _execute_cleave)
        if isinstance(error, CleaveSkillError):
            chat.add_message(
                "system",
                f"[red]Cleave skill not available:[/] {error}\n"
                "[dim]Install the Cleave skill to ~/.claude/skills/cleave/[/]",
            )
            return

        # Generic error with context
        error_msg = str(error)
        chat.add_message(
            "system",
            f"[bold red]{context}[/]\n\n"
            f"[dim]{error_msg}[/]\n\n"
            "[yellow]Tip:[/] Check the error message for specific guidance.",
        )

    def action_refresh_files(self) -> None:
        """Refresh the .calf file list."""
        control = self.query_one("#control-widget", ControlPanel)
        control.refresh_files()

    def action_focus_chat(self) -> None:
        """Focus the chat input."""
        chat = self.query_one("#chat-widget", ChatPanel)
        chat_input = chat.query_one("#chat-input")
        chat_input.focus()

    def action_cancel(self) -> None:
        """Cancel the current operation (Escape key)."""
        if self._mode == "idle":
            return

        self._do_cancel("Cancelled.")

    def action_interrupt(self) -> None:
        """Interrupt the current operation (Ctrl+C)."""
        if self._mode == "idle":
            return

        self._do_cancel("Interrupted (Ctrl+C).")

    def _do_cancel(self, message: str) -> None:
        """Perform cancellation with the given message."""
        chat = self.query_one("#chat-widget", ChatPanel)
        chat.set_loading(False)
        chat.add_message("system", message)

        # Signal cancellation to running operations
        if self._cancel_token:
            self._cancel_token.cancel()
            self._cancel_token = None

        # Clean up sessions
        if self._interrogation:
            # Use run_worker for async cleanup
            self.run_worker(self._interrogation.close())
            self._interrogation = None

        self._executor = None
        self._editing_file = None
        self._mode = "idle"

    def action_focus_control(self) -> None:
        """Focus the control panel (F1)."""
        control = self.query_one("#control-widget", ControlPanel)
        control.focus()

    def action_cycle_theme(self) -> None:
        """Cycle to the next theme."""
        from cleave.tui.app import CleaveTUI
        if isinstance(self.app, CleaveTUI):
            self.app.cycle_theme()

    def action_quit(self) -> None:
        """Quit the application."""
        self.app.exit()
