"""Workflow-definition revision history viewer (docs/provenance/00, Phase 4a)."""

from __future__ import annotations

import json
from typing import Any, List

from typing import Callable, Optional

from ..qt_compat import (
    QAbstractItemView,
    QDialog,
    QHBoxLayout,
    QHeaderView,
    QLabel,
    QMessageBox,
    QPushButton,
    QSplitter,
    QTableWidget,
    QTableWidgetItem,
    QTextEdit,
    QVBoxLayout,
    Qt,
)
from ..translator import tr


class WorkflowHistoryDialog(QDialog):
    """Lists the immutable revisions of an Analysis's workflow definition."""

    def __init__(
        self,
        analysis_name: str,
        revisions: List[Any],
        parent=None,
        restore_callback: Optional[Callable[[Any], bool]] = None,
    ):
        super().__init__(parent)
        # Newest first for display.
        self._revisions = sorted(revisions, key=lambda r: r.revision_number, reverse=True)
        self._restore_callback = restore_callback
        self.setWindowTitle(tr("provenance.workflow_history_title", name=analysis_name))
        self.resize(820, 560)
        self._build()

    def _build(self) -> None:
        layout = QVBoxLayout()
        self.setLayout(layout)

        header = QLabel(f"<b>{tr('provenance.history_header', count=len(self._revisions))}</b>")
        header.setTextFormat(Qt.TextFormat.RichText)
        layout.addWidget(header)

        splitter = QSplitter(Qt.Orientation.Vertical)
        layout.addWidget(splitter, 1)

        self.table = QTableWidget()
        columns = [
            tr("provenance.col_rev"), tr("provenance.col_when"), tr("provenance.col_by"),
            tr("provenance.col_change"), tr("provenance.col_hash"),
        ]
        self.table.setColumnCount(len(columns))
        self.table.setHorizontalHeaderLabels(columns)
        self.table.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
        self.table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
        self.table.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
        self.table.setRowCount(len(self._revisions))
        for row_idx, rev in enumerate(self._revisions):
            cells = [
                str(rev.revision_number),
                rev.created_at or "",
                rev.created_by or "",
                rev.change_summary or "",
                (rev.payload_sha256 or "")[:12],
            ]
            for col_idx, value in enumerate(cells):
                self.table.setItem(row_idx, col_idx, QTableWidgetItem(value))
        head = self.table.horizontalHeader()
        head.setSectionResizeMode(3, QHeaderView.ResizeMode.Stretch)
        for col in (0, 1, 2, 4):
            head.setSectionResizeMode(col, QHeaderView.ResizeMode.ResizeToContents)
        self.table.itemSelectionChanged.connect(self._on_selection_changed)
        splitter.addWidget(self.table)

        self.payload_view = QTextEdit()
        self.payload_view.setReadOnly(True)
        self.payload_view.setPlaceholderText(tr("provenance.history_payload_placeholder"))
        splitter.addWidget(self.payload_view)
        splitter.setSizes([260, 280])

        row = QHBoxLayout()
        if self._restore_callback is not None:
            self.restore_button = QPushButton(tr("provenance.btn_restore"))
            self.restore_button.setToolTip(tr("provenance.tip_restore"))
            self.restore_button.clicked.connect(self._on_restore)
            row.addWidget(self.restore_button)
        row.addStretch()
        close_button = QPushButton(tr("provenance.btn_close"))
        close_button.clicked.connect(self.close)
        row.addWidget(close_button)
        layout.addLayout(row)

        if self._revisions:
            self.table.selectRow(0)

    def _selected_revision(self):
        rows = self.table.selectionModel().selectedRows() if self.table.selectionModel() else []
        if not rows:
            return None
        return self._revisions[rows[0].row()]

    def _on_restore(self) -> None:
        rev = self._selected_revision()
        if rev is None:
            QMessageBox.information(self, tr("provenance.mbox_restore"), tr("provenance.restore_select"))
            return
        confirm = QMessageBox.question(
            self,
            tr("provenance.mbox_restore"),
            tr("provenance.restore_confirm", n=rev.revision_number),
        )
        if confirm != QMessageBox.StandardButton.Yes:
            return
        try:
            ok = bool(self._restore_callback(rev))
        except Exception as exc:
            QMessageBox.warning(self, tr("provenance.mbox_restore"),
                                tr("provenance.restore_failed", error=exc))
            return
        if ok:
            QMessageBox.information(self, tr("provenance.mbox_restore"),
                                   tr("provenance.restore_done", n=rev.revision_number))
            self.accept()
        else:
            QMessageBox.warning(self, tr("provenance.mbox_restore"), tr("provenance.restore_incomplete"))

    def _on_selection_changed(self) -> None:
        rows = self.table.selectionModel().selectedRows() if self.table.selectionModel() else []
        if not rows:
            return
        rev = self._revisions[rows[0].row()]
        try:
            self.payload_view.setPlainText(json.dumps(rev.payload, indent=2, default=str))
        except Exception:
            self.payload_view.setPlainText(str(rev.payload))
