# -*- coding: utf-8 -*-
"""网格视图 + 异步缩略图加载。

- AssetCard 网格，响应式列数（随宽度自适应）。
- 缩略图缺失时丢入线程池后台生成，完成后原地刷新对应卡片。
- 分页控件由主窗口持有，本模块只负责渲染当前页。
"""
from __future__ import annotations

from pathlib import Path

from PySide6.QtCore import QObject, QRunnable, QThreadPool, Qt, Signal
from PySide6.QtWidgets import QGridLayout, QScrollArea, QVBoxLayout, QWidget

from .. import thumbnail as thumb_mod
from ..models import Asset
from .widgets import AssetCard, EmptyState

PAGE_SIZE = 60


class ThumbJob(QRunnable):
    """后台生成单张缩略图。"""

    def __init__(self, asset_id: int, file_path: str, thumb_root: Path, emitter: "ThumbEmitter"):
        super().__init__()
        self.asset_id = asset_id
        self.file_path = file_path
        self.thumb_root = thumb_root
        self.emitter = emitter
        self.setAutoDelete(True)

    def run(self):
        thumb_mod.make_thumb(self.file_path, self.asset_id, self.thumb_root)
        self.emitter.done.emit(self.asset_id)


class ThumbEmitter(QObject):
    """把线程池结果转发为 Qt 信号（跨线程安全）。"""
    done = Signal(int)


class GridView(QScrollArea):
    """资产网格视图。"""

    asset_selected = Signal(int)
    asset_double_clicked = Signal(int)

    def __init__(self, thumb_root: Path | None = None, parent=None):
        super().__init__(parent)
        self.setWidgetResizable(True)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)

        self.thumb_root = thumb_root
        self.assets: list[Asset] = []
        self._cards: dict[int, AssetCard] = {}

        self._pool = QThreadPool.globalInstance()
        self._emitter = ThumbEmitter()
        self._emitter.done.connect(self._on_thumb_done)

        self._outer = QWidget()
        lay = QVBoxLayout(self._outer)
        lay.setContentsMargins(0, 0, 0, 0)
        lay.setSpacing(0)

        self._grid = QWidget()
        self._grid_lay = QGridLayout(self._grid)
        self._grid_lay.setContentsMargins(14, 12, 14, 12)
        self._grid_lay.setSpacing(10)
        lay.addWidget(self._grid)

        self._empty = EmptyState(
            icon="🎬", title="这里还没有资产",
            hint="点击工具栏「导入」按钮，或拖拽图片文件夹进来\n支持漫画页、封面、角色/场景设定、剧本、分镜、音频",
        )
        self._empty.hide()
        lay.addWidget(self._empty)

        lay.addStretch(1)
        self.setWidget(self._outer)

    # ------------------------------------------------------------------
    def set_assets(self, assets: list[Asset]):
        """渲染一批资产（当前页）。"""
        self.assets = assets
        self._clear_cards()

        if not assets:
            self._grid.hide()
            self._empty.show()
            return
        self._grid.show()
        self._empty.hide()

        for a in assets:
            card = AssetCard(a, thumb_root=self.thumb_root)
            card.selected.connect(self.asset_selected.emit)
            card.doubleClicked.connect(self.asset_double_clicked.emit)
            self._cards[a.id] = card
            self._grid_lay.addWidget(card)

        self._repack()
        self._kick_missing_thumbs()

    def _repack(self):
        """按当前宽度重新排布网格。"""
        cols = self._col_count()
        row = 0
        for i, a in enumerate(self.assets):
            card = self._cards[a.id]
            self._grid_lay.addWidget(card, row, i % cols)
            if (i + 1) % cols == 0:
                row += 1
        self._grid_lay.setRowStretch(row + 1, 1)
        self._grid_lay.setColumnStretch(cols, 1)

    def _col_count(self) -> int:
        w = self.viewport().width() - 20 - 8
        return max(1, w // (AssetCard.CARD_W + 10))

    def resizeEvent(self, e):  # noqa: N802
        super().resizeEvent(e)
        if self._cards:
            self._repack()

    def _kick_missing_thumbs(self):
        """为没有缩略图的资产提交后台任务。"""
        if not self.thumb_root:
            return
        for a in self.assets:
            if a.id is None or a.is_text:
                continue
            if thumb_mod.thumb_path(a.id, self.thumb_root).exists():
                continue
            self._pool.start(ThumbJob(a.id, a.file_path, self.thumb_root, self._emitter))

    def _on_thumb_done(self, asset_id: int):
        card = self._cards.get(asset_id)
        if card is not None:
            card.refresh_thumb()

    def _clear_cards(self):
        self._cards.clear()
        while self._grid_lay.count():
            item = self._grid_lay.takeAt(0)
            w = item.widget()
            if w is not None:
                w.deleteLater()

    def clear(self):
        self.assets = []
        self._clear_cards()
        self._grid.hide()
        self._empty.show()

    def highlight(self, asset_id: int | None):
        """刷新选中态。"""
        for aid, card in self._cards.items():
            if aid == asset_id:
                card._apply_style("selected")
            else:
                card._apply_style("normal")
