from __future__ import annotations

from pathlib import Path

from PySide6.QtCore import Qt, QThread, QTimer, Signal
from PySide6.QtGui import QTextOption
from PySide6.QtWidgets import (
    QFrame,
    QHBoxLayout,
    QLabel,
    QPushButton,
    QScrollArea,
    QSizePolicy,
    QSplitter,
    QTextEdit,
    QVBoxLayout,
    QWidget,
)

from aura.config import ThinkingMode
from aura.drones.build_spec import DroneBuildBrief
from aura.drones.workshop_runner import DroneWorkshopResponse, DroneWorkshopRunner
from aura.gui.cards.assistant_card import AssistantCard
from aura.gui.cards.user_card import UserCard
from aura.gui.cards._helpers import _fade_in_widget
from aura.gui.theme import (
    ACCENT,
    BG,
    BG_ALT,
    BG_RAISED,
    BORDER,
    FG,
    FG_DIM,
    FG_ITALIC,
    FG_MUTED,
)
from aura.gui.widgets.aura_glow import AuraWidget


class _WorkshopTextEdit(QTextEdit):
    """Multiline auto-growing text edit for the Drone Workshop."""

    submitted = Signal()

    MAX_LINES = 8

    def __init__(self, parent: QWidget | None = None) -> None:
        super().__init__(parent)
        self.setPlaceholderText(
            "Describe the Drone you need\u2026\nCtrl+Enter to send, Enter for newline"
        )
        self.setAcceptRichText(False)
        self.setWordWrapMode(QTextOption.WrapMode.WordWrap)
        self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
        self.document().contentsChanged.connect(self._adjust_height)
        self._adjust_height()

    def _adjust_height(self) -> None:
        line_h = self.fontMetrics().lineSpacing()
        doc_h = int(self.document().size().height())
        target = min(line_h * self.MAX_LINES, max(line_h, doc_h)) + 14
        self.setFixedHeight(target)

    def keyPressEvent(self, event) -> None:
        if event.key() in (Qt.Key.Key_Return, Qt.Key.Key_Enter):
            if event.modifiers() & (
                Qt.KeyboardModifier.ControlModifier
                | Qt.KeyboardModifier.MetaModifier
            ):
                self.submitted.emit()
                return
        super().keyPressEvent(event)


class DroneWorkshopPanel(QWidget):
    """Reusable panel with the full Drone Workshop UI and conversation logic."""

    drone_build_requested = Signal(object)  # emits DroneBuildBrief
    cancelled = Signal()
    cancelled_and_back_requested = Signal()

    def __init__(
        self,
        workspace_root: Path | None = None,
        provider_id: str = "deepseek",
        model: str = "",
        thinking: ThinkingMode = "disabled",
        temperature: float = 0.4,
        parent: QWidget | None = None,
    ) -> None:
        super().__init__(parent)
        self._workspace_root = workspace_root
        self._provider_id = provider_id
        self._model = model
        self._thinking = thinking
        self._temperature = temperature

        self._conversation: list[dict[str, str]] = []
        self._last_valid_brief: DroneBuildBrief | None = None
        self._runner_thread: QThread | None = None
        self._runner: DroneWorkshopRunner | None = None
        self._thinking_card: AssistantCard | None = None
        self._empty_hint: QLabel | None = None
        self._aura_wrapper: AuraWidget | None = None
        self._response_received = False

        self._build_ui()

    # -- UI construction --

    def _build_ui(self) -> None:
        layout = QVBoxLayout(self)
        layout.setContentsMargins(16, 16, 16, 16)
        layout.setSpacing(12)

        # -- Header --
        title = QLabel("Drone Workshop")
        title.setStyleSheet(
            "font-size: 21px; font-weight: 700;"
            f" color: {FG}; background: transparent;"
        )
        layout.addWidget(title)

        # -- Splitter: conversation (top) | brief panel (bottom) --
        self._splitter = QSplitter(Qt.Orientation.Vertical)
        self._splitter.setHandleWidth(3)

        # -- Conversation area --
        conversation_widget = QWidget()
        conv_layout = QVBoxLayout(conversation_widget)
        conv_layout.setContentsMargins(0, 0, 0, 0)
        conv_layout.setSpacing(8)

        # Message column (scrollable)
        self._msg_scroll = QScrollArea()
        self._msg_scroll.setWidgetResizable(True)
        self._msg_scroll.setHorizontalScrollBarPolicy(
            Qt.ScrollBarPolicy.ScrollBarAlwaysOff
        )
        self._msg_scroll.setStyleSheet(
            f"QScrollArea {{ border: none; background: {BG}; }}"
        )

        self._msg_column = QWidget()
        self._msg_column.setStyleSheet(f"background: {BG};")
        self._msg_layout = QVBoxLayout(self._msg_column)
        self._msg_layout.setContentsMargins(8, 8, 8, 8)
        self._msg_layout.setSpacing(10)

        self._empty_hint = QLabel("Tell Aura what kind of Drone you want to build.")
        self._empty_hint.setStyleSheet(f"color: {FG_ITALIC}; font-style: italic;")
        self._empty_hint.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self._msg_layout.addWidget(self._empty_hint)

        self._msg_layout.addStretch()

        self._msg_scroll.setWidget(self._msg_column)

        conv_layout.addWidget(self._msg_scroll, 1)

        # -- Input row --
        input_frame = QFrame()
        input_frame.setStyleSheet(
            f"QFrame {{"
            f"  background: rgba(34, 34, 40, 0.65);"
            f"  border: 1px solid rgba(255, 255, 255, 0.08);"
            f"  border-radius: 16px;"
            f"}}"
        )
        input_frame_layout = QHBoxLayout(input_frame)
        input_frame_layout.setContentsMargins(14, 8, 8, 10)
        input_frame_layout.setSpacing(8)

        self._input_edit = _WorkshopTextEdit()
        self._input_edit.setStyleSheet(
            f"QTextEdit {{ background: transparent; border: none; "
            f"padding: 4px 6px; color: {FG}; }}"
        )
        self._input_edit.submitted.connect(self._on_send)
        input_frame_layout.addWidget(self._input_edit, 1)

        self._send_btn = QPushButton("\u2192")
        font = self._send_btn.font()
        font.setPointSize(16)
        self._send_btn.setFont(font)
        self._send_btn.setObjectName("primary")
        self._send_btn.setCursor(Qt.CursorShape.PointingHandCursor)
        self._send_btn.setStyleSheet(
            f"QPushButton#primary {{ background: {ACCENT}; color: {BG}; "
            f"border: 1px solid {ACCENT}; border-radius: 6px; "
            f"padding: 6px 14px; font-weight: 600; font-size: 16px; }}"
        )
        self._send_btn.clicked.connect(self._on_send)
        input_frame_layout.addWidget(self._send_btn)

        conv_layout.addWidget(input_frame)

        self._splitter.addWidget(conversation_widget)

        # -- Brief panel --
        brief_panel = QWidget()
        brief_layout = QVBoxLayout(brief_panel)
        brief_layout.setContentsMargins(0, 0, 0, 0)
        brief_layout.setSpacing(8)

        brief_title = QLabel("DRONE BUILD BRIEF")
        brief_title.setStyleSheet(
            f"font-size: 11px; font-weight: 700; color: {FG_DIM}; "
            f"letter-spacing: 0.08em; background: transparent;"
        )
        brief_layout.addWidget(brief_title)

        # Compact build brief card
        self._brief_card = QFrame()
        self._brief_card.setStyleSheet(
            f"QFrame {{ background: {BG_RAISED}; border: 1px solid {BORDER}; "
            f"border-left: 3px solid {ACCENT}; border-radius: 8px; padding: 12px; }}"
        )
        card_layout = QVBoxLayout(self._brief_card)
        card_layout.setContentsMargins(12, 8, 12, 8)
        card_layout.setSpacing(4)

        # Empty state
        self._brief_empty = QLabel(
            "No build brief yet \u2014 describe your Drone in the conversation above."
        )
        self._brief_empty.setWordWrap(True)
        self._brief_empty.setStyleSheet(
            f"color: {FG_MUTED}; font-size: 13px; background: transparent;"
        )
        card_layout.addWidget(self._brief_empty)

        # Valid brief content (hidden initially)
        self._brief_valid_widget = QWidget()
        valid_layout = QVBoxLayout(self._brief_valid_widget)
        valid_layout.setContentsMargins(0, 0, 0, 0)
        valid_layout.setSpacing(2)

        self._brief_name = QLabel()
        self._brief_name.setStyleSheet(
            f"font-size: 15px; font-weight: 700; color: {FG}; background: transparent;"
        )
        valid_layout.addWidget(self._brief_name)

        self._brief_description = QLabel()
        self._brief_description.setWordWrap(True)
        self._brief_description.setStyleSheet(
            f"font-size: 12px; color: {FG_DIM}; background: transparent;"
        )
        valid_layout.addWidget(self._brief_description)

        self._brief_tools = QLabel()
        self._brief_tools.setStyleSheet(
            f"font-size: 11px; color: {FG_MUTED}; background: transparent;"
        )
        valid_layout.addWidget(self._brief_tools)

        self._brief_permissions = QLabel()
        self._brief_permissions.setStyleSheet(
            f"font-size: 11px; color: {FG_MUTED}; background: transparent;"
        )
        valid_layout.addWidget(self._brief_permissions)

        self._brief_output = QLabel()
        self._brief_output.setStyleSheet(
            f"font-size: 11px; color: {FG_MUTED}; background: transparent;"
        )
        valid_layout.addWidget(self._brief_output)

        self._brief_valid_widget.setVisible(False)
        card_layout.addWidget(self._brief_valid_widget)

        brief_layout.addWidget(self._brief_card)

        self._splitter.addWidget(brief_panel)

        # Stretch: 3 parts conversation, 1 part brief
        self._splitter.setStretchFactor(0, 3)
        self._splitter.setStretchFactor(1, 1)

        layout.addWidget(self._splitter, 1)

        # -- Bottom buttons --
        button_row = QHBoxLayout()
        button_row.setSpacing(8)
        button_row.addStretch(1)

        cancel_btn = QPushButton("Cancel")
        cancel_btn.setCursor(Qt.CursorShape.PointingHandCursor)
        cancel_btn.setStyleSheet(
            f"QPushButton {{ background: transparent; color: {FG}; "
            f"border: 1px solid {BORDER}; border-radius: 6px; "
            f"padding: 6px 20px; font-weight: 600; }}"
        )
        cancel_btn.clicked.connect(self.cancel)
        button_row.addWidget(cancel_btn)

        self._build_btn = QPushButton("Build this Drone")
        self._build_btn.setObjectName("primary")
        self._build_btn.setCursor(Qt.CursorShape.PointingHandCursor)
        self._build_btn.setEnabled(False)
        self._build_btn.setStyleSheet(
            f"QPushButton#primary {{ background: {ACCENT}; color: {BG}; "
            f"border: 1px solid {ACCENT}; border-radius: 6px; "
            f"padding: 6px 20px; font-weight: 600; }}"
            f"QPushButton#primary:disabled {{ background: #2a2a30; color: #555566; "
            f"border: 1px solid #333340; }}"
        )
        self._build_btn.clicked.connect(self._on_approve_build)
        button_row.addWidget(self._build_btn)

        layout.addLayout(button_row)

    # -- Send behavior --

    def _on_send(self) -> None:
        text = self._input_edit.toPlainText().strip()
        if not text:
            return
        if self._runner_thread is not None and self._runner_thread.isRunning():
            return  # runner already active

        self._response_received = False

        # Add user message card to column
        user_card = UserCard(text, parent=self._msg_column)
        self._add_message_card(user_card)
        self._conversation.append({"role": "user", "content": text})
        self._input_edit.clear()

        # Disable input and build button while running; show thinking state
        self._input_edit.setEnabled(False)
        self._send_btn.setEnabled(False)
        self._send_btn.setText("\u2026")
        self._build_btn.setEnabled(False)
        self._send_btn.setStyleSheet(
            "QPushButton { background: #2a2a30; color: #555566; "
            "border: 1px solid #333340; border-radius: 6px; "
            "padding: 6px 18px; font-weight: 600; font-size: 13px; }"
        )

        try:
            # Start assistant message \u2014 show thinking card
            self._thinking_card = AssistantCard(parent=self._msg_column)
            self._thinking_card.show_thinking_message("Aura is thinking\u2026")
            self._aura_wrapper = AuraWidget(self._thinking_card, glow_color=ACCENT, glow_spread=14, parent=self._msg_column)
            self._add_message_card(self._aura_wrapper)
            self._aura_wrapper.start_aura()
            self._aura_wrapper.set_glow_state("thinking")

            self._runner = DroneWorkshopRunner(parent=None)
            self._runner_thread = QThread(self)
            self._runner.moveToThread(self._runner_thread)

            # Connect signals
            self._runner.responseReady.connect(self._on_response_ready)
            self._runner.apiError.connect(self._on_api_error)
            self._runner.finished.connect(self._on_runner_finished)

            self._runner.configure(
                conversation=self._conversation,
                provider_id=self._provider_id,
                model=self._model,
                thinking=self._thinking,
                temperature=self._temperature,
            )
            self._runner.contentDelta.connect(self._on_content_delta)
            self._runner_thread.started.connect(self._runner.do_run)
            self._runner_thread.start()
        except Exception as exc:
            if self._aura_wrapper is not None:
                self._aura_wrapper.stop_aura()
                self._aura_wrapper = None
            if self._thinking_card is None:
                self._thinking_card = AssistantCard(parent=self._msg_column)
                self._add_message_card(self._thinking_card)
            self._thinking_card.set_error(f"Error: {exc}")
            self._input_edit.setEnabled(True)
            self._send_btn.setEnabled(True)
            self._send_btn.setText("\u2192")
            self._send_btn.setStyleSheet(
                f"QPushButton#primary {{ background: {ACCENT}; color: {BG}; "
                f"border: 1px solid {ACCENT}; border-radius: 6px; "
                f"padding: 6px 14px; font-weight: 600; font-size: 16px; }}"
            )

    def _on_content_delta(self, text: str) -> None:
        """Handle streaming text delta from the runner."""
        if self._aura_wrapper is not None and self._thinking_card is not None:
            self._thinking_card._stop_thinking_animation()
            self._thinking_card.set_content("Drafting response\u2026")

    def _on_response_ready(self, response: DroneWorkshopResponse) -> None:
        if self._aura_wrapper is not None:
            self._aura_wrapper.stop_aura()
            self._aura_wrapper = None
        # Belt-and-suspenders: ensure thinking dots stop
        if self._thinking_card is not None:
            self._thinking_card._stop_thinking_animation()
        self._response_received = True
        if response.kind == "error":
            if self._thinking_card:
                self._thinking_card.set_error(f"Error: {response.message}")
            self._conversation.append({"role": "assistant", "content": response.message})
            self._build_btn.setEnabled(False)
            self._build_btn.setText("Build this Drone")
            return

        text = response.message or ""
        if text:
            if self._thinking_card:
                self._thinking_card.set_content(text)

        if response.kind == "question":
            display = response.message or "Got it. Tell me more."
            self._conversation.append({"role": "assistant", "content": display})
            # Brief card unchanged; build button stays disabled

        elif response.kind == "brief":
            display = response.message or "Here's the build brief."
            self._conversation.append({"role": "assistant", "content": display})
            if response.brief is not None:
                self._last_valid_brief = response.brief
                self._update_brief_card(response.brief)
                if response.brief.is_ready_to_build():
                    self._build_btn.setEnabled(True)
                    self._build_btn.setText("\u2713 Build This Drone")
                else:
                    self._build_btn.setEnabled(False)
                    self._build_btn.setText("Build this Drone")
            else:
                self._build_btn.setEnabled(False)
                self._build_btn.setText("Build this Drone")

    def _on_api_error(self, status_code: int, message: str) -> None:
        if self._aura_wrapper is not None:
            self._aura_wrapper.stop_aura()
            self._aura_wrapper = None
        self._response_received = True
        if self._thinking_card:
            self._thinking_card.set_error(f"API Error ({status_code}): {message}")
        self._build_btn.setEnabled(False)
        self._build_btn.setText("Build this Drone")

    def _on_runner_finished(self) -> None:
        if self._aura_wrapper is not None:
            self._aura_wrapper.stop_aura()
            self._aura_wrapper = None

        # If no response was received, show a generic error
        if not self._response_received and self._thinking_card is not None:
            self._thinking_card.set_error(
                "No response received \u2014 the conversation ended unexpectedly."
            )

        # Re-enable input; restore Send button
        self._input_edit.setEnabled(True)
        self._send_btn.setEnabled(True)
        self._send_btn.setText("\u2192")
        self._send_btn.setStyleSheet(
            f"QPushButton#primary {{ background: {ACCENT}; color: {BG}; "
            f"border: 1px solid {ACCENT}; border-radius: 6px; "
            f"padding: 6px 14px; font-weight: 600; font-size: 16px; }}"
        )
        # Re-enable build button if a valid brief is available
        if self._last_valid_brief is not None and self._last_valid_brief.is_ready_to_build():
            self._build_btn.setEnabled(True)
            self._build_btn.setText("\u2713 Build This Drone")
        # Clean up thread and runner \u2014 non-blocking
        if self._runner_thread is not None:
            thread = self._runner_thread
            runner = self._runner
            self._runner_thread = None
            self._runner = None
            thread.quit()
            thread.finished.connect(thread.deleteLater)
            if runner is not None:
                thread.finished.connect(runner.deleteLater)

    def _on_approve_build(self) -> None:
        """User clicked Build this Drone \u2014 emit signal only."""
        if self._last_valid_brief is not None:
            self.drone_build_requested.emit(self._last_valid_brief)

    # -- Public API --

    def cancel(self) -> None:
        """Cancel the runner if running, clear the last valid brief, and request back to palette."""
        if self._runner is not None:
            self._runner.cancel()
        self._last_valid_brief = None
        self.cancelled.emit()
        self.cancelled_and_back_requested.emit()

    def reset_workshop_state(self) -> None:
        """Clear conversation, brief editor, and cancel any active runner."""
        # Cancel active runner
        if self._runner is not None:
            self._runner.cancel()
        if self._runner_thread is not None:
            self._runner_thread.quit()
            self._runner_thread = None
        self._runner = None

        # Clear conversation
        self._conversation.clear()
        self._last_valid_brief = None

        # Remove all message cards from the column (keep empty hint and stretch)
        while self._msg_layout.count():
            item = self._msg_layout.takeAt(0)
            w = item.widget()
            if w is not None and w is not self._empty_hint:
                w.deleteLater()

        # Reset empty hint visibility
        if self._empty_hint is not None:
            self._empty_hint.setVisible(True)
        self._msg_layout.addStretch()

        # Reset brief card to empty state
        self._brief_valid_widget.setVisible(False)
        self._brief_empty.setVisible(True)

        # Reset build button
        self._build_btn.setEnabled(False)
        self._build_btn.setText("Build this Drone")

        # Clean up thinking/aural state if any
        if self._aura_wrapper is not None:
            self._aura_wrapper.stop_aura()
            self._aura_wrapper = None
        if self._thinking_card is not None:
            self._thinking_card._stop_thinking_animation()
            self._thinking_card = None

        # Re-enable input
        self._input_edit.setEnabled(True)
        self._send_btn.setEnabled(True)
        self._send_btn.setText("\u2192")
        self._send_btn.setStyleSheet(
            f"QPushButton#primary {{ background: {ACCENT}; color: {BG}; "
            f"border: 1px solid {ACCENT}; border-radius: 6px; "
            f"padding: 6px 14px; font-weight: 600; font-size: 16px; }}"
        )

    def result_brief(self) -> DroneBuildBrief | None:
        """Return the last valid build brief."""
        return self._last_valid_brief

    # -- Private helpers --

    def _add_message_card(self, card: QWidget) -> None:
        """Add a card to the message column and auto-scroll."""
        if self._empty_hint is not None:
            self._empty_hint.setVisible(False)
        # Remove the bottom stretch spacer
        if self._msg_layout.count():
            last = self._msg_layout.itemAt(self._msg_layout.count() - 1)
            if last and last.spacerItem():
                self._msg_layout.removeItem(last)
        self._msg_layout.addWidget(card)
        _fade_in_widget(card)
        # Add stretch back to keep messages at top
        self._msg_layout.addStretch()
        self._scroll_to_bottom()

    def _scroll_to_bottom(self) -> None:
        QTimer.singleShot(
            0,
            lambda: self._msg_scroll.verticalScrollBar().setValue(
                self._msg_scroll.verticalScrollBar().maximum()
            ),
        )

    def _update_brief_card(self, brief: DroneBuildBrief) -> None:
        """Update the compact brief card with build brief information."""
        self._brief_empty.setVisible(False)
        self._brief_valid_widget.setVisible(True)

        text = brief.build_brief.strip()
        lines = text.split("\n")

        # First line as title
        title = lines[0].strip() if lines else "Build Brief"
        if len(title) > 60:
            title = title[:57] + "..."
        self._brief_name.setText(title)

        # Remaining lines as description
        desc = "\n".join(lines[1:]).strip() if len(lines) > 1 else ""
        if not desc:
            desc = text[:200] if text else ""
        if len(desc) > 200:
            desc = desc[:197] + "..."
        self._brief_description.setText(desc)
        self._brief_description.setVisible(bool(desc))

        # Tools \u2014 not available in current data model, hide
        self._brief_tools.setVisible(False)

        # Permissions / readiness badge
        if brief.is_ready_to_build():
            self._brief_permissions.setText("\u2713 Ready to build")
            self._brief_permissions.setStyleSheet(
                "font-size: 11px; color: #4caf50; background: transparent; font-weight: 600;"
            )
        else:
            self._brief_permissions.setText("In progress \u2014 more details needed")
            self._brief_permissions.setStyleSheet(
                "font-size: 11px; color: #ff9800; background: transparent; font-weight: 600;"
            )
        self._brief_permissions.setVisible(True)

        # Output format \u2014 not available in current data model, hide
        self._brief_output.setVisible(False)
