"""AI usage statistics window — PyQt6 QDialog.

Two tabs:
  Overview — summary counters + daily-token line chart + provider bar chart
  Details  — paginated table of individual requests

Actions: Export CSV, Clear old records, period selector.
"""

from __future__ import annotations

import logging
from datetime import datetime, timedelta, timezone

UTC = timezone.utc
from typing import TYPE_CHECKING

from PyQt6.QtCore import Qt, pyqtSignal
from PyQt6.QtWidgets import (
    QComboBox,
    QDialog,
    QFileDialog,
    QGroupBox,
    QHBoxLayout,
    QHeaderView,
    QInputDialog,
    QLabel,
    QMessageBox,
    QPushButton,
    QTableWidget,
    QTableWidgetItem,
    QTabWidget,
    QVBoxLayout,
    QWidget,
)

from ..i18n import _

if TYPE_CHECKING:
    from ..stats.stats_manager import StatsManager

log = logging.getLogger(__name__)

_PERIOD_KEYS = ["day", "week", "month", "all"]

try:
    import pyqtgraph as pg

    pg.setConfigOption("background", "#1e1e2e")
    pg.setConfigOption("foreground", "#cdd6f4")
    _HAS_PG = True
except ImportError:
    _HAS_PG = False
    log.warning("pyqtgraph not installed — charts disabled in stats window")

_CHART_COLORS = ["#89b4fa", "#a6e3a1", "#fab387", "#f38ba8", "#cba6f7"]


def _period_labels() -> list[str]:
    return [
        _("stats.period_day"),
        _("stats.period_week"),
        _("stats.period_month"),
        _("stats.period_all"),
    ]


class StatsWindow(QDialog):
    """AI usage statistics dialog."""

    apply_theme_signal = pyqtSignal(str)

    def __init__(
        self,
        stats_mgr: StatsManager,
        parent: QWidget | None = None,
    ) -> None:
        super().__init__(parent)
        self._mgr = stats_mgr
        self._current_page = 0
        self._page_size = 50

        self.setWindowTitle(_("stats.title"))
        self.setMinimumWidth(720)
        self.setMinimumHeight(520)
        self.setWindowFlags(self.windowFlags() & ~Qt.WindowType.WindowContextHelpButtonHint)

        self._setup_ui()
        self._refresh()
        self.apply_theme_signal.connect(self._do_apply_theme)

    # ------------------------------------------------------------------ #
    # UI build
    # ------------------------------------------------------------------ #

    def _setup_ui(self) -> None:
        root = QVBoxLayout(self)
        root.setSpacing(8)

        # ── Period selector ──────────────────────────────────────────
        top_row = QHBoxLayout()
        self._lbl_period = QLabel(_("stats.period_label"))
        top_row.addWidget(self._lbl_period)

        self._period_combo = QComboBox()
        for label in _period_labels():
            self._period_combo.addItem(label)
        self._period_combo.setCurrentIndex(1)  # "Week" by default
        self._period_combo.currentIndexChanged.connect(self._on_period_changed)
        top_row.addWidget(self._period_combo)
        top_row.addStretch()

        self._btn_refresh = QPushButton(_("stats.btn_refresh"))
        self._btn_refresh.clicked.connect(self._refresh)
        top_row.addWidget(self._btn_refresh)
        root.addLayout(top_row)

        # ── Tabs ─────────────────────────────────────────────────────
        self._tabs = QTabWidget()
        self._tabs.addTab(self._build_overview_tab(), _("stats.tab_overview"))
        self._tabs.addTab(self._build_details_tab(), _("stats.tab_details"))
        root.addWidget(self._tabs)

        # ── Bottom action row ─────────────────────────────────────────
        btn_row = QHBoxLayout()
        self._btn_export = QPushButton(_("stats.btn_export"))
        self._btn_export.clicked.connect(self._export_csv)
        self._btn_clear = QPushButton(_("stats.btn_clear_old"))
        self._btn_clear.setToolTip(_("stats.btn_clear_old_tooltip"))
        self._btn_clear.clicked.connect(self._clear_old)
        self._btn_close = QPushButton(_("stats.btn_close"))
        self._btn_close.clicked.connect(self.close)

        btn_row.addWidget(self._btn_export)
        btn_row.addWidget(self._btn_clear)
        btn_row.addStretch()
        btn_row.addWidget(self._btn_close)
        root.addLayout(btn_row)

    def retranslate_ui(self) -> None:
        """Update all widget texts to the current locale."""
        self.setWindowTitle(_("stats.title"))
        self._lbl_period.setText(_("stats.period_label"))
        self._btn_refresh.setText(_("stats.btn_refresh"))

        # Period combo items
        current_idx = self._period_combo.currentIndex()
        self._period_combo.blockSignals(True)
        self._period_combo.clear()
        for label in _period_labels():
            self._period_combo.addItem(label)
        self._period_combo.setCurrentIndex(current_idx)
        self._period_combo.blockSignals(False)

        # Tab labels
        self._tabs.setTabText(0, _("stats.tab_overview"))
        self._tabs.setTabText(1, _("stats.tab_details"))

        # Bottom buttons
        self._btn_export.setText(_("stats.btn_export"))
        self._btn_clear.setText(_("stats.btn_clear_old"))
        self._btn_clear.setToolTip(_("stats.btn_clear_old_tooltip"))
        self._btn_close.setText(_("stats.btn_close"))

        # Overview tab
        self._summary_box.setTitle(_("stats.summary_group"))
        self._lbl_requests_title.setText(_("stats.counter_requests"))
        self._lbl_in_tok_title.setText(_("stats.counter_in_tokens"))
        self._lbl_out_tok_title.setText(_("stats.counter_out_tokens"))
        self._lbl_avg_dur_title.setText(_("stats.counter_avg_duration"))

        # Table headers
        self._table.setHorizontalHeaderLabels(
            [
                _("stats.table_datetime"),
                _("stats.table_provider"),
                _("stats.table_model"),
                _("stats.table_in_tokens"),
                _("stats.table_out_tokens"),
                _("stats.table_duration"),
                _("stats.table_success"),
                _("stats.table_cancelled"),
            ]
        )

        # Pagination
        self._btn_prev.setText(_("stats.btn_prev"))
        self._btn_next.setText(_("stats.btn_next"))

        # Re-render data with updated strings
        self._refresh()

    def apply_theme(self, theme: str) -> None:
        """Thread-safe: update the window's theme. theme: 'light' | 'dark'."""
        self.apply_theme_signal.emit(theme)

    def _do_apply_theme(self, theme: str) -> None:
        """Re-apply the global QSS so this window refreshes (Qt main thread)."""
        try:
            from .theme_manager import ThemeManager

            qss = ThemeManager.get_instance().load_qss(theme)
            if qss:
                from PyQt6.QtWidgets import QApplication

                app = QApplication.instance()
                if app is not None:
                    app.setStyleSheet(qss)  # type: ignore[attr-defined]
        except (RuntimeError, ImportError):
            pass

    # ─────────────────────────────── Overview tab ─────────────────────

    def _build_overview_tab(self) -> QWidget:
        widget = QWidget()
        layout = QVBoxLayout(widget)
        layout.setSpacing(8)

        # Summary counters
        self._summary_box = QGroupBox(_("stats.summary_group"))
        summary_row = QHBoxLayout(self._summary_box)

        self._lbl_requests, self._lbl_requests_title = self._counter_widget(
            summary_row, _("stats.counter_requests")
        )
        self._lbl_in_tok, self._lbl_in_tok_title = self._counter_widget(
            summary_row, _("stats.counter_in_tokens")
        )
        self._lbl_out_tok, self._lbl_out_tok_title = self._counter_widget(
            summary_row, _("stats.counter_out_tokens")
        )
        self._lbl_avg_dur, self._lbl_avg_dur_title = self._counter_widget(
            summary_row, _("stats.counter_avg_duration")
        )
        layout.addWidget(self._summary_box)

        if _HAS_PG:
            # Line chart: daily token usage
            self._plot_daily = pg.PlotWidget(title=_("stats.chart_daily_title"))
            self._plot_daily.setLabel("left", _("stats.chart_daily_y"))
            self._plot_daily.setLabel("bottom", _("stats.chart_daily_x"))
            self._plot_daily.addLegend()
            self._plot_daily.setMaximumHeight(200)
            layout.addWidget(self._plot_daily)

            # Bar chart: provider breakdown
            self._plot_prov = pg.PlotWidget(title=_("stats.chart_provider_title"))
            self._plot_prov.setLabel("left", _("stats.chart_provider_y"))
            self._plot_prov.setMaximumHeight(170)
            layout.addWidget(self._plot_prov)

            # Line chart: success rate trend (last 30 days)
            self._plot_success = pg.PlotWidget(title=_("stats.chart_success_title"))
            self._plot_success.setLabel("left", _("stats.chart_success_y"))
            self._plot_success.setLabel("bottom", _("stats.chart_daily_x"))
            self._plot_success.setYRange(0, 100)
            self._plot_success.setMaximumHeight(180)
            layout.addWidget(self._plot_success)

            # Bar chart: avg duration trend (last 30 days)
            self._plot_duration = pg.PlotWidget(title=_("stats.chart_duration_title"))
            self._plot_duration.setLabel("left", _("stats.chart_duration_y"))
            self._plot_duration.setLabel("bottom", _("stats.chart_daily_x"))
            self._plot_duration.setMaximumHeight(180)
            layout.addWidget(self._plot_duration)
        else:
            no_chart = QLabel(_("stats.no_pyqtgraph"))
            no_chart.setAlignment(Qt.AlignmentFlag.AlignCenter)
            no_chart.setStyleSheet("color: #888; padding: 20px;")
            layout.addWidget(no_chart)

        # Text breakdown (always shown)
        self._lbl_provider_text = QLabel("")
        self._lbl_provider_text.setWordWrap(True)
        self._lbl_provider_text.setStyleSheet("color: #aaa; font-size: 11px;")
        layout.addWidget(self._lbl_provider_text)
        layout.addStretch()
        return widget

    @staticmethod
    def _counter_widget(parent_layout: QHBoxLayout, title: str) -> tuple[QLabel, QLabel]:
        """Build a titled counter column; return (value_label, title_label)."""
        col = QVBoxLayout()
        title_lbl = QLabel(title)
        title_lbl.setAlignment(Qt.AlignmentFlag.AlignCenter)
        title_lbl.setStyleSheet("color: #888; font-size: 11px;")
        val_lbl = QLabel("—")
        val_lbl.setAlignment(Qt.AlignmentFlag.AlignCenter)
        val_lbl.setStyleSheet("font-size: 20px; font-weight: bold;")
        col.addWidget(title_lbl)
        col.addWidget(val_lbl)
        parent_layout.addLayout(col)
        return val_lbl, title_lbl

    # ─────────────────────────────── Details tab ──────────────────────

    def _build_details_tab(self) -> QWidget:
        widget = QWidget()
        layout = QVBoxLayout(widget)

        self._table = QTableWidget()
        self._table.setColumnCount(8)
        self._table.setHorizontalHeaderLabels(
            [
                _("stats.table_datetime"),
                _("stats.table_provider"),
                _("stats.table_model"),
                _("stats.table_in_tokens"),
                _("stats.table_out_tokens"),
                _("stats.table_duration"),
                _("stats.table_success"),
                _("stats.table_cancelled"),
            ]
        )
        hdr = self._table.horizontalHeader()
        if hdr is not None:
            hdr.setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents)
            hdr.setStretchLastSection(False)
        self._table.setEditTriggers(QTableWidget.EditTrigger.NoEditTriggers)
        self._table.setSelectionBehavior(QTableWidget.SelectionBehavior.SelectRows)
        self._table.setAlternatingRowColors(True)
        layout.addWidget(self._table)

        # Pagination row
        nav = QHBoxLayout()
        self._btn_prev = QPushButton(_("stats.btn_prev"))
        self._btn_prev.clicked.connect(self._prev_page)
        self._btn_next = QPushButton(_("stats.btn_next"))
        self._btn_next.clicked.connect(self._next_page)
        self._lbl_page = QLabel(_("stats.pagination", page=1, total_pages=1, total=0))
        self._lbl_page.setStyleSheet("color: #888; font-size: 11px;")

        nav.addWidget(self._btn_prev)
        nav.addWidget(self._lbl_page)
        nav.addWidget(self._btn_next)
        nav.addStretch()
        layout.addLayout(nav)
        return widget

    # ------------------------------------------------------------------ #
    # Refresh
    # ------------------------------------------------------------------ #

    def _period_key(self) -> str:
        idx = self._period_combo.currentIndex()
        return _PERIOD_KEYS[idx] if 0 <= idx < len(_PERIOD_KEYS) else "week"

    def _on_period_changed(self) -> None:
        self._current_page = 0
        self._refresh()

    def _refresh(self) -> None:
        period = self._period_key()
        stats = self._mgr.get_stats(period=period)
        providers = self._mgr.get_by_provider(period=period)
        daily = self._mgr.get_daily_totals(days=30)
        daily_perf = self._mgr.get_daily_success_duration(days=30)

        # Summary labels
        self._lbl_requests.setText(f"{stats['total_requests']:,}")
        self._lbl_in_tok.setText(f"{stats['total_input_tokens']:,}")
        self._lbl_out_tok.setText(f"{stats['total_output_tokens']:,}")
        avg = stats["avg_duration_ms"]
        self._lbl_avg_dur.setText(_("stats.avg_duration", avg=avg) if avg else "—")

        # Charts
        if _HAS_PG:
            self._update_daily_chart(daily)
            self._update_provider_chart(providers)
            self._update_success_chart(daily_perf)
            self._update_duration_chart(daily_perf)

        # Provider text summary
        if providers:
            lines = [
                _(
                    "stats.provider_summary",
                    provider=p["provider"],
                    total=p["total"],
                    in_tokens=p["in_tokens"],
                    out_tokens=p["out_tokens"],
                )
                for p in providers
            ]
            self._lbl_provider_text.setText("\n".join(lines))
        else:
            self._lbl_provider_text.setText(_("stats.no_data"))

        self._load_table_page()

    def _update_daily_chart(self, daily: list[dict]) -> None:
        self._plot_daily.clear()
        if not daily:
            return
        x = list(range(len(daily)))
        in_v = [d["in_tokens"] for d in daily]
        out_v = [d["out_tokens"] for d in daily]
        self._plot_daily.plot(
            x, in_v, pen=pg.mkPen(_CHART_COLORS[0], width=2), name=_("stats.chart_daily_y") + " ↓"
        )
        self._plot_daily.plot(
            x, out_v, pen=pg.mkPen(_CHART_COLORS[1], width=2), name=_("stats.chart_daily_y") + " ↑"
        )
        ticks = [(i, d["date"][-5:]) for i, d in enumerate(daily)]  # "MM-DD"
        self._plot_daily.getAxis("bottom").setTicks([ticks])

    def _update_provider_chart(self, providers: list[dict]) -> None:
        self._plot_prov.clear()
        if not providers:
            return
        x = list(range(len(providers)))
        y = [p["total"] for p in providers]
        names = [p["provider"] for p in providers]
        brushes = [pg.mkBrush(_CHART_COLORS[i % len(_CHART_COLORS)]) for i in x]
        bars = pg.BarGraphItem(x=x, height=y, width=0.6, brushes=brushes)
        self._plot_prov.addItem(bars)
        self._plot_prov.getAxis("bottom").setTicks([[(i, n) for i, n in enumerate(names)]])

    def _update_success_chart(self, daily_perf: list[dict]) -> None:
        """Plot success rate % per day as a green line with a 95% reference line."""
        self._plot_success.clear()
        if not daily_perf:
            return
        x = list(range(len(daily_perf)))
        y = [d["success_rate"] for d in daily_perf]
        # Green line for success rate
        self._plot_success.plot(
            x,
            y,
            pen=pg.mkPen(_CHART_COLORS[1], width=2),
            name=_("stats.chart_success_y"),
        )
        # Reference line at 95%
        ref_line = pg.InfiniteLine(
            pos=95,
            angle=0,
            pen=pg.mkPen("#f38ba8", width=1, style=pg.QtCore.Qt.PenStyle.DashLine),
            label="95%",
            labelOpts={"color": "#f38ba8", "position": 0.95},
        )
        self._plot_success.addItem(ref_line)
        ticks = [(i, d["date"][-5:]) for i, d in enumerate(daily_perf)]
        self._plot_success.getAxis("bottom").setTicks([ticks])

    def _update_duration_chart(self, daily_perf: list[dict]) -> None:
        """Plot average response duration per day as an orange bar chart."""
        self._plot_duration.clear()
        if not daily_perf:
            return
        x = list(range(len(daily_perf)))
        y = [d["avg_duration_ms"] for d in daily_perf]
        bars = pg.BarGraphItem(
            x=x,
            height=y,
            width=0.6,
            brush=pg.mkBrush(_CHART_COLORS[2]),
        )
        self._plot_duration.addItem(bars)
        ticks = [(i, d["date"][-5:]) for i, d in enumerate(daily_perf)]
        self._plot_duration.getAxis("bottom").setTicks([ticks])

    # ------------------------------------------------------------------ #
    # Details table
    # ------------------------------------------------------------------ #

    def _load_table_page(self) -> None:
        period = self._period_key()
        records = self._mgr.get_detailed_records(
            limit=self._page_size,
            offset=self._current_page * self._page_size,
            period=period,
        )
        total = self._mgr.count_records(period=period)
        total_pages = max(1, (total + self._page_size - 1) // self._page_size)

        self._table.setRowCount(len(records))
        for row_i, rec in enumerate(records):
            values = [
                str(rec["timestamp"])[:19].replace("T", " "),
                rec["provider"],
                rec["model"],
                f"{rec['input_tokens']:,}",
                f"{rec['output_tokens']:,}",
                f"{rec['duration_ms']:,}",
                "✓" if rec["success"] else "✗",
                "✓" if rec["cancelled"] else "",
            ]
            for col_i, val in enumerate(values):
                item = QTableWidgetItem(val)
                item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
                self._table.setItem(row_i, col_i, item)

        page_n = self._current_page + 1
        self._lbl_page.setText(
            _("stats.pagination", page=page_n, total_pages=total_pages, total=total)
        )
        self._btn_prev.setEnabled(self._current_page > 0)
        self._btn_next.setEnabled(self._current_page < total_pages - 1)

    def _prev_page(self) -> None:
        if self._current_page > 0:
            self._current_page -= 1
            self._load_table_page()

    def _next_page(self) -> None:
        self._current_page += 1
        self._load_table_page()

    # ------------------------------------------------------------------ #
    # Actions
    # ------------------------------------------------------------------ #

    def _export_csv(self) -> None:
        period = self._period_key()
        path, _filter = QFileDialog.getSaveFileName(
            self,
            _("stats.export_title"),
            _("stats.export_filename"),
            _("stats.export_filter"),
        )
        if not path:
            return
        try:
            count = self._mgr.export_csv(path, period=period)
            QMessageBox.information(
                self,
                _("stats.export_success_title"),
                _("stats.export_success_msg", count=count, path=path),
            )
        except Exception as exc:
            QMessageBox.warning(self, _("stats.export_error_title"), str(exc))

    def _clear_old(self) -> None:
        days, ok = QInputDialog.getInt(
            self,
            _("stats.clear_old_title"),
            _("stats.clear_old_prompt"),
            value=30,
            min=1,
            max=3650,
        )
        if not ok:
            return
        cutoff = datetime.now(UTC) - timedelta(days=days)
        deleted = self._mgr.clear_old_records(cutoff)
        QMessageBox.information(
            self,
            _("stats.clear_old_done_title"),
            _("stats.clear_old_done_msg", deleted=deleted),
        )
        self._refresh()
