"""
Right-side panel: tabbed previews for Sync XML, POST JSON, block details,
warnings, and live log output.
"""
from __future__ import annotations

import json as _json
from datetime import datetime

from PySide6.QtCore import Signal
from PySide6.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QHBoxLayout,
    QTabWidget, QTextEdit, QPushButton, QLabel,
)
from PySide6.QtGui import QFont, QColor, QPalette, QTextCursor, QTextCharFormat

from src.gui.adapters import BlockRow


_MONO = QFont("Courier New", 9)

# Tab indices (keep in sync with addTab order below)
_TAB_DETAILS  = 0
_TAB_WARNINGS = 1
_TAB_XML      = 2
_TAB_JSON     = 3
_TAB_LOG      = 4


class PreviewPanel(QWidget):
    # Emitted when the user edits POST JSON and clicks Apply.
    # Payload is the parsed dict (guaranteed valid JSON).
    post_json_edited = Signal(dict)

    def __init__(self, parent: QWidget | None = None):
        super().__init__(parent)
        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)

        self.tabs = QTabWidget()
        layout.addWidget(self.tabs)

        self._detail_edit = self._make_edit(
            "Click a block in the scheme, plot or table to see details..."
        )
        self.tabs.addTab(self._detail_edit, "Block Details")   # 0

        self._warn_edit = self._make_edit("No warnings yet.")
        self.tabs.addTab(self._warn_edit, "Warnings")           # 1

        self._xml_edit = self._make_edit(
            "Run interpretation to populate XML preview..."
        )
        self.tabs.addTab(self._xml_edit, "Sync XML")            # 2

        # POST JSON tab — editable, with Apply button
        json_container = QWidget()
        json_lay = QVBoxLayout(json_container)
        json_lay.setContentsMargins(0, 0, 0, 0)
        json_lay.setSpacing(2)

        # Toolbar row: status label + Apply button
        json_toolbar = QWidget()
        json_tb_lay  = QHBoxLayout(json_toolbar)
        json_tb_lay.setContentsMargins(4, 2, 4, 2)
        json_tb_lay.setSpacing(6)
        self._json_status_lbl = QLabel("Редактируйте JSON и нажмите Применить")
        self._json_status_lbl.setStyleSheet("font-size: 10px; color: #888;")
        json_tb_lay.addWidget(self._json_status_lbl, stretch=1)
        self._json_apply_btn = QPushButton("Применить")
        self._json_apply_btn.setFixedHeight(22)
        self._json_apply_btn.setToolTip(
            "Применить изменения из редактора к _post_info\n"
            "и синхронизировать контролы"
        )
        self._json_apply_btn.clicked.connect(self._on_json_apply)
        json_tb_lay.addWidget(self._json_apply_btn)
        json_lay.addWidget(json_toolbar)

        self._json_edit = QTextEdit()
        self._json_edit.setFont(_MONO)
        self._json_edit.setLineWrapMode(QTextEdit.NoWrap)
        self._json_edit.setPlaceholderText(
            "Запустите интерпретацию, чтобы заполнить POST JSON..."
        )
        self._json_edit.textChanged.connect(self._on_json_text_changed)
        json_lay.addWidget(self._json_edit, stretch=1)

        self.tabs.addTab(json_container, "POST JSON")           # 3

        self._log_edit = self._make_edit("")
        self._log_edit.setLineWrapMode(QTextEdit.WidgetWidth)
        self.tabs.addTab(self._log_edit, "Log")                 # 4

    # -- block details ---------------------------------------------------------

    def show_block_details(self, row: BlockRow | None) -> None:
        if row is None:
            self._detail_edit.clear()
            return
        lines = [
            f"Sync index    : {row.sync_index}",
            f"Orig index    : {row.orig_index if row.orig_index >= 0 else '- (inserted)'}",
            f"Type          : {row.block_type}",
            f"Duration      : {row.duration * 1e6:.4f} uss",
            f"T start       : {row.t_start * 1e6:.4f} uss",
            f"T end         : {row.t_end * 1e6:.4f} uss",
            f"Is delay      : {row.is_delay}  ({row.delay_type or '-'})",
            "-" * 32,
            f"Gate RF       : {row.gate_rf}",
            f"Gate ADC      : {row.gate_adc}",
            f"Gate TR       : {row.gate_tr}",
            "-" * 32,
            f"Has RF        : {row.has_rf}",
            f"Has ADC       : {row.has_adc}",
            f"Has Grad      : {row.has_grad}",
        ]
        self._detail_edit.setPlainText("\n".join(lines))
        self.tabs.setCurrentIndex(_TAB_DETAILS)

    # -- warnings --------------------------------------------------------------

    def set_warnings(self, warnings: list[str]) -> None:
        if warnings:
            self._warn_edit.setPlainText("\n".join(f"WARN  {w}" for w in warnings))
            self.tabs.setTabText(_TAB_WARNINGS, f"Warnings ({len(warnings)})")
        else:
            self._warn_edit.setPlainText("No warnings.")
            self.tabs.setTabText(_TAB_WARNINGS, "Warnings")

    def add_error(self, msg: str) -> None:
        current = self._warn_edit.toPlainText()
        self._warn_edit.setPlainText(
            (current + "\n" if current else "") + f"ERR  {msg}"
        )
        n = self._warn_edit.toPlainText().count("\n") + 1
        self.tabs.setTabText(_TAB_WARNINGS, f"Warnings ({n})")
        self.tabs.setCurrentIndex(_TAB_WARNINGS)

    # -- xml / json previews ---------------------------------------------------

    def set_xml_text(self, text: str) -> None:
        self._xml_edit.setPlainText(text)

    def set_post_json(self, data: dict) -> None:
        self._json_edit.blockSignals(True)
        self._json_edit.setPlainText(_json.dumps(data, indent=2, ensure_ascii=False))
        self._json_edit.blockSignals(False)
        self._set_json_status("ok")

    def set_post_json_text(self, text: str) -> None:
        self._json_edit.blockSignals(True)
        self._json_edit.setPlainText(text)
        self._json_edit.blockSignals(False)
        self._set_json_status("ok")

    def _on_json_text_changed(self) -> None:
        """Validate JSON on every keystroke and update status indicator."""
        try:
            _json.loads(self._json_edit.toPlainText())
            self._set_json_status("ok")
        except _json.JSONDecodeError:
            self._set_json_status("error")

    def _on_json_apply(self) -> None:
        """Parse and emit the edited JSON dict."""
        try:
            data = _json.loads(self._json_edit.toPlainText())
            self._set_json_status("applied")
            self.post_json_edited.emit(data)
        except _json.JSONDecodeError as exc:
            self._set_json_status("error", str(exc))

    def _set_json_status(self, state: str, detail: str = "") -> None:
        if state == "ok":
            self._json_status_lbl.setText("JSON корректен")
            self._json_status_lbl.setStyleSheet("font-size: 10px; color: #4caf50;")
            self._json_apply_btn.setEnabled(True)
        elif state == "applied":
            self._json_status_lbl.setText("Применено")
            self._json_status_lbl.setStyleSheet("font-size: 10px; color: #2196f3;")
            self._json_apply_btn.setEnabled(True)
        else:
            msg = f"Ошибка JSON: {detail}" if detail else "Ошибка JSON"
            self._json_status_lbl.setText(msg)
            self._json_status_lbl.setStyleSheet("font-size: 10px; color: #f44336;")
            self._json_apply_btn.setEnabled(False)

    # -- log -------------------------------------------------------------------

    def append_log(self, msg: str, error: bool = False) -> None:
        ts   = datetime.now().strftime("%H:%M:%S")
        line = f"[{ts}] {msg}"
        cursor = self._log_edit.textCursor()
        cursor.movePosition(QTextCursor.End)
        fmt = QTextCharFormat()
        if error:
            fmt.setForeground(QColor("#ef5350"))
        else:
            fmt.setForeground(QApplication.palette().color(QPalette.Text))
        cursor.setCharFormat(fmt)
        cursor.insertText(line + "\n")
        self._log_edit.setTextCursor(cursor)
        self._log_edit.ensureCursorVisible()

    def clear_log(self) -> None:
        self._log_edit.clear()

    # -- helpers ---------------------------------------------------------------

    @staticmethod
    def _make_edit(placeholder: str = "") -> QTextEdit:
        edit = QTextEdit()
        edit.setReadOnly(True)
        edit.setFont(_MONO)
        edit.setLineWrapMode(QTextEdit.NoWrap)
        if placeholder:
            edit.setPlaceholderText(placeholder)
        return edit
