# -*- coding: utf-8 -*-
"""预览组件：大图查看器 + 音频播放器 + 文本查看器。"""
from __future__ import annotations

import os

from PySide6.QtCore import QPoint, QRectF, Qt, QUrl, QTimer, Signal
from PySide6.QtGui import QPainter, QPixmap
from PySide6.QtMultimedia import QAudioOutput, QMediaPlayer
from PySide6.QtWidgets import (
    QHBoxLayout,
    QLabel,
    QPushButton,
    QScrollArea,
    QSlider,
    QTextEdit,
    QVBoxLayout,
    QWidget,
)

from .. import thumbnail as thumb_mod
from .theme import BG_CARD, BG_INPUT, BORDER, FG, FG_DIM, FG_FAINT, RADIUS


# ---------------------------------------------------------------------------
# 大图查看器（独立窗口，支持缩放 / 平移 / 翻页）
# ---------------------------------------------------------------------------
class _Canvas(QWidget):
    """可缩放平移的图片画布。"""

    def __init__(self, parent=None):
        super().__init__(parent)
        self._pix = QPixmap()
        self._zoom = 1.0
        self._offset = QPoint(0, 0)
        self._drag = False
        self._last = QPoint()
        self.setMinimumSize(400, 300)
        self.setStyleSheet(f"background: #0E0F13; border-radius: 8px;")
        self.setMouseTracking(True)

    def set_image(self, pix: QPixmap):
        self._pix = pix
        self._zoom = 1.0
        self._fit()
        self.update()

    def _fit(self):
        if self._pix.isNull() or self.width() < 10:
            return
        s = min(self.width() / self._pix.width(), self.height() / self._pix.height())
        self._zoom = min(s, 1.0)
        self._center()

    def _center(self):
        w = self._pix.width() * self._zoom
        h = self._pix.height() * self._zoom
        self._offset = QPoint((self.width() - w) // 2, (self.height() - h) // 2)

    def wheelEvent(self, e):
        delta = e.angleDelta().y()
        factor = 1.15 if delta > 0 else 1 / 1.15
        self.set_zoom(self._zoom * factor)
        e.accept()

    def set_zoom(self, z: float):
        self._zoom = max(0.05, min(z, 20.0))
        self.update()

    def paintEvent(self, e):
        p = QPainter(self)
        p.setRenderHint(QPainter.RenderHint.SmoothPixmapTransform)
        if self._pix.isNull():
            p.setPen(FG_FAINT)
            p.drawText(self.rect(), Qt.AlignmentFlag.AlignCenter, "无图片")
            return
        target_w = self._pix.width() * self._zoom
        target_h = self._pix.height() * self._zoom
        p.drawPixmap(QRectF(self._offset.x(), self._offset.y(), target_w, target_h),
                     self._pix, self._pix.rect())

    def mousePressEvent(self, e):
        if e.button() == Qt.MouseButton.LeftButton:
            self._drag = True
            self._last = e.position().toPoint()

    def mouseMoveEvent(self, e):
        if self._drag:
            d = e.position().toPoint() - self._last
            self._offset += d
            self._last = e.position().toPoint()
            self.update()

    def mouseReleaseEvent(self, e):
        self._drag = False

    def resizeEvent(self, e):
        if self._pix and self._zoom <= 1.0 and not self._drag:
            self._fit()
            self.update()
        super().resizeEvent(e)


class ImageViewer(QWidget):
    """图片预览容器：画布 + 工具条（放大/缩小/适应/原始/翻页）。"""

    prev_clicked = Signal()
    next_clicked = Signal()
    zoom_changed = Signal(float)

    def __init__(self, parent=None):
        super().__init__(parent)
        lay = QVBoxLayout(self)
        lay.setContentsMargins(0, 0, 0, 0)
        lay.setSpacing(4)

        self.canvas = _Canvas(self)
        lay.addWidget(self.canvas, 1)

        bar = QWidget(self)
        bl = QHBoxLayout(bar)
        bl.setContentsMargins(8, 4, 8, 4)
        bl.setSpacing(4)

        def btn(text, slot, tip=""):
            b = QPushButton(text, bar)
            b.setObjectName("Ghost")
            b.setFixedHeight(26)
            b.setToolTip(tip)
            b.clicked.connect(slot)
            return b

        bl.addWidget(btn("‹", self.prev_clicked.emit, "上一页 (←)"))
        bl.addWidget(btn("−", self._zoom_out, "缩小"))
        self.zoom_lbl = QLabel("100%", bar)
        self.zoom_lbl.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.zoom_lbl.setMinimumWidth(46)
        self.zoom_lbl.setStyleSheet(f"color: {FG_DIM}; font-size: 11px;")
        bl.addWidget(self.zoom_lbl)
        bl.addWidget(btn("+", self._zoom_in, "放大"))
        bl.addWidget(btn("适应", self._fit, "适应窗口 (F)"))
        bl.addWidget(btn("原始", self._actual, "原始大小 (1)"))
        bl.addStretch(1)
        bl.addWidget(btn("›", self.next_clicked.emit, "下一页 (→)"))

        lay.addWidget(bar)
        self._player = None

    def show_image(self, path: str):
        pix = QPixmap(path)
        if pix.isNull():
            self.canvas.set_image(QPixmap())
            self.info = ""
        else:
            self.canvas.set_image(pix)
            self.info = f"{pix.width()} × {pix.height()}"
        self.zoom_changed.emit(self.canvas._zoom)
        self.zoom_lbl.setText(f"{self.canvas._zoom * 100:.0f}%")

    def _zoom_in(self):
        self.canvas.set_zoom(self.canvas._zoom * 1.25)
        self.zoom_lbl.setText(f"{self.canvas._zoom * 100:.0f}%")
        self.zoom_changed.emit(self.canvas._zoom)

    def _zoom_out(self):
        self.canvas.set_zoom(self.canvas._zoom / 1.25)
        self.zoom_lbl.setText(f"{self.canvas._zoom * 100:.0f}%")
        self.zoom_changed.emit(self.canvas._zoom)

    def _fit(self):
        self.canvas._fit()
        self.canvas.update()
        self.zoom_lbl.setText(f"{self.canvas._zoom * 100:.0f}%")

    def _actual(self):
        self.canvas._zoom = 1.0
        self.canvas._center()
        self.canvas.update()
        self.zoom_lbl.setText("100%")


# ---------------------------------------------------------------------------
# 音频播放器
# ---------------------------------------------------------------------------
class AudioPlayer(QWidget):
    """音频播放器：进度条 + 播放/暂停 + 时间 + 音量。

    基于 QMediaPlayer；文件不可播放时降级为提示。
    """

    def __init__(self, path: str = "", parent=None):
        super().__init__(parent)
        self.setFixedHeight(108)
        self.setStyleSheet(f"background: {BG_CARD}; border: 1px solid {BORDER};"
                            f" border-radius: {RADIUS}px;")
        lay = QVBoxLayout(self)
        lay.setContentsMargins(14, 10, 14, 10)
        lay.setSpacing(8)

        top = QHBoxLayout()
        self.name_lbl = QLabel("音频", self)
        self.name_lbl.setStyleSheet(f"color: {FG}; font-weight: 600; font-size: 13px;")
        self.dur_lbl = QLabel("—", self)
        self.dur_lbl.setStyleSheet(f"color: {FG_FAINT}; font-size: 11px;")
        self.dur_lbl.setAlignment(Qt.AlignmentFlag.AlignRight)
        top.addWidget(self.name_lbl, 1)
        top.addWidget(self.dur_lbl)
        lay.addLayout(top)

        row = QHBoxLayout()
        row.setSpacing(8)
        self.btn_play = QPushButton("▶ 播放", self)
        self.btn_play.setFixedWidth(88)
        self.btn_play.setFixedHeight(28)
        self.btn_play.clicked.connect(self.toggle)

        self.time_lbl = QLabel("00:00", self)
        self.time_lbl.setStyleSheet(f"color: {FG_DIM}; font-size: 11px;")
        self.time_lbl.setFixedWidth(40)

        self.scrubber = QSlider(Qt.Orientation.Horizontal, self)
        self.scrubber.setFixedHeight(20)
        self.scrubber.setRange(0, 0)
        self.scrubber.valueChanged.connect(self._on_scrub)

        row.addWidget(self.btn_play)
        row.addWidget(self.time_lbl)
        row.addWidget(self.scrubber, 1)
        lay.addLayout(row)

        self._player = QMediaPlayer()
        self._output = QAudioOutput()
        self._player.setAudioOutput(self._output)
        self._player.durationChanged.connect(self._on_duration)
        self._player.positionChanged.connect(self._on_position)
        self._player.errorOccurred.connect(self._on_error)
        self._player.mediaStatusChanged.connect(self._on_status)
        self._volume_slider = QSlider(Qt.Orientation.Horizontal, self)
        self._volume_slider.setRange(0, 100)
        self._volume_slider.setValue(80)
        self._volume_slider.setFixedWidth(90)
        self._volume_slider.valueChanged.connect(
            lambda v: self._output.setVolume(v / 100.0))
        self._volume_slider.setFixedHeight(14)

        lay.addLayout(self._build_volume_row())
        self._seeking = False
        self._path = ""
        if path:
            self.load(path)

    def _build_volume_row(self):
        r = QHBoxLayout()
        lbl = QLabel("🔊", self)
        lbl.setStyleSheet(f"color: {FG_DIM}; font-size: 12px;")
        r.addWidget(lbl)
        r.addWidget(self._volume_slider)
        r.addStretch(1)
        return r

    def load(self, path: str):
        self._path = path
        self.name_lbl.setText(os.path.basename(path) or "音频")
        d = thumb_mod.audio_duration(path)
        self.dur_lbl.setText(f"时长 {thumb_mod._format_duration(d)}" if d else "")
        if os.path.exists(path):
            self._player.setSource(QUrl.fromLocalFile(path))

    def toggle(self):
        if not self._path:
            return
        if self._player.playbackState() == QMediaPlayer.PlaybackState.PlayingState:
            self._player.pause()
        else:
            self._player.play()

    def _sync_button(self):
        if self._player.playbackState() == QMediaPlayer.PlaybackState.PlayingState:
            self.btn_play.setText("⏸ 暂停")
        else:
            self.btn_play.setText("▶ 播放")

    def _on_duration(self, ms):
        self._player.positionChanged.disconnect(self._on_position)
        self.scrubber.setRange(0, ms)
        self._player.positionChanged.connect(self._on_position)
        self.dur_lbl.setText(f"时长 {thumb_mod._format_duration(ms / 1000)}")

    def _on_position(self, ms):
        if not self._seeking:
            self.scrubber.setValue(ms)
        self.time_lbl.setText(thumb_mod._format_duration(ms / 1000))
        self._sync_button()

    def _on_scrub(self, v):
        if self._player.playbackState() == QMediaPlayer.PlaybackState.PlayingState:
            self._seeking = True
            self._player.setPosition(v)
            QTimer.singleShot(150, lambda: setattr(self, "_seeking", False))

    def _on_error(self, error, msg):
        self.dur_lbl.setText("无法播放")
        self.btn_play.setEnabled(False)

    def _on_status(self, status):
        self._sync_button()

    def stop(self):
        if self._player:
            self._player.stop()


# ---------------------------------------------------------------------------
# 文本查看器
# ---------------------------------------------------------------------------
class TextViewer(QScrollArea):
    """文本内容查看器（只读）。"""

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWidgetResizable(True)
        w = QWidget()
        w.setStyleSheet(f"background: {BG_INPUT}; border-radius: 8px;")
        lay = QVBoxLayout(w)
        lay.setContentsMargins(0, 0, 0, 0)
        self.edit = QTextEdit(w)
        self.edit.setReadOnly(True)
        self.edit.setStyleSheet(f"""
            QTextEdit {{
                background: {BG_INPUT}; color: {FG}; border: none;
                font-family: "SF Mono", Menlo, Consolas, monospace; font-size: 12px;
                padding: 12px 14px; line-height: 1.6;
            }}
        """)
        lay.addWidget(self.edit)
        self.setWidget(w)

    def set_text(self, text: str):
        self.edit.setPlainText(text or "(空)")

    def toPlainText(self) -> str:
        """返回纯文本内容（与 QTextEdit 接口对齐，便于外部读取）。"""
        return self.edit.toPlainText()

    def text(self) -> str:
        return self.toPlainText()

    def copy_to_clipboard(self):
        self.edit.copy()
