"""Bookmarks browser widget with folder support."""

from __future__ import annotations

import logging
import threading
import asyncio
from pathlib import Path

from PySide6.QtCore import Qt, Signal, QObject
from PySide6.QtGui import QPixmap
from PySide6.QtWidgets import (
    QWidget,
    QVBoxLayout,
    QHBoxLayout,
    QLineEdit,
    QPushButton,
    QLabel,
    QComboBox,
    QMenu,
    QApplication,
    QInputDialog,
    QMessageBox,
)

from ..core.db import Database, Bookmark
from ..core.cache import download_thumbnail
from .grid import ThumbnailGrid

log = logging.getLogger("booru")


class BookmarkThumbSignals(QObject):
    thumb_ready = Signal(int, str)


class BookmarksView(QWidget):
    """Browse and search local bookmarks with folder support."""

    bookmark_selected = Signal(object)
    bookmark_activated = Signal(object)

    def __init__(self, db: Database, parent: QWidget | None = None) -> None:
        super().__init__(parent)
        self._db = db
        self._bookmarks: list[Bookmark] = []
        self._signals = BookmarkThumbSignals()
        self._signals.thumb_ready.connect(self._on_thumb_ready, Qt.ConnectionType.QueuedConnection)

        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)

        # Top bar: folder selector + search
        top = QHBoxLayout()

        self._folder_combo = QComboBox()
        self._folder_combo.setMinimumWidth(120)
        self._folder_combo.currentTextChanged.connect(lambda _: self.refresh())
        top.addWidget(self._folder_combo)

        manage_btn = QPushButton("+ Folder")
        manage_btn.setToolTip("New folder")
        manage_btn.setFixedWidth(65)
        manage_btn.clicked.connect(self._new_folder)
        top.addWidget(manage_btn)

        self._search_input = QLineEdit()
        self._search_input.setPlaceholderText("Search bookmarks by tag...")
        self._search_input.returnPressed.connect(self._do_search)
        top.addWidget(self._search_input, stretch=1)

        search_btn = QPushButton("Search")
        search_btn.clicked.connect(self._do_search)
        top.addWidget(search_btn)

        top.setContentsMargins(0, 0, 0, 0)

        layout.addLayout(top)

        # Count label
        self._count_label = QLabel()
        layout.addWidget(self._count_label)

        # Grid
        self._grid = ThumbnailGrid()
        self._grid.post_selected.connect(self._on_selected)
        self._grid.post_activated.connect(self._on_activated)
        self._grid.context_requested.connect(self._on_context_menu)
        self._grid.multi_context_requested.connect(self._on_multi_context_menu)
        layout.addWidget(self._grid)

    def _refresh_folders(self) -> None:
        current = self._folder_combo.currentText()
        self._folder_combo.blockSignals(True)
        self._folder_combo.clear()
        self._folder_combo.addItem("All Bookmarks")
        self._folder_combo.addItem("Unfiled")
        for folder in self._db.get_folders():
            self._folder_combo.addItem(folder)
        # Restore selection
        idx = self._folder_combo.findText(current)
        if idx >= 0:
            self._folder_combo.setCurrentIndex(idx)
        self._folder_combo.blockSignals(False)

    def refresh(self, search: str | None = None) -> None:
        self._refresh_folders()

        folder_text = self._folder_combo.currentText()
        folder_filter = None
        if folder_text == "Unfiled":
            folder_filter = ""  # sentinel for NULL folder
        elif folder_text not in ("All Bookmarks", ""):
            folder_filter = folder_text

        if folder_filter == "":
            # Get unfiled: folder IS NULL
            self._bookmarks = [
                f for f in self._db.get_bookmarks(search=search, limit=500)
                if f.folder is None
            ]
        elif folder_filter:
            self._bookmarks = self._db.get_bookmarks(search=search, folder=folder_filter, limit=500)
        else:
            self._bookmarks = self._db.get_bookmarks(search=search, limit=500)

        self._count_label.setText(f"{len(self._bookmarks)} bookmarks")
        thumbs = self._grid.set_posts(len(self._bookmarks))

        from ..core.config import saved_dir, saved_folder_dir, MEDIA_EXTENSIONS
        for i, (fav, thumb) in enumerate(zip(self._bookmarks, thumbs)):
            thumb.set_bookmarked(True)
            # Check if saved to library
            saved = False
            if fav.folder:
                saved = any(
                    (saved_folder_dir(fav.folder) / f"{fav.post_id}{ext}").exists()
                    for ext in MEDIA_EXTENSIONS
                )
            else:
                saved = any(
                    (saved_dir() / f"{fav.post_id}{ext}").exists()
                    for ext in MEDIA_EXTENSIONS
                )
            thumb.set_saved_locally(saved)
            if fav.preview_url:
                self._load_thumb_async(i, fav.preview_url)
            elif fav.cached_path and Path(fav.cached_path).exists():
                pix = QPixmap(fav.cached_path)
                if not pix.isNull():
                    thumb.set_pixmap(pix)

    def _load_thumb_async(self, index: int, url: str) -> None:
        async def _dl():
            try:
                path = await download_thumbnail(url)
                self._signals.thumb_ready.emit(index, str(path))
            except Exception as e:
                log.warning(f"Bookmark thumb {index} failed: {e}")
        threading.Thread(target=lambda: asyncio.run(_dl()), daemon=True).start()

    def _on_thumb_ready(self, index: int, path: str) -> None:
        thumbs = self._grid._thumbs
        if 0 <= index < len(thumbs):
            pix = QPixmap(path)
            if not pix.isNull():
                thumbs[index].set_pixmap(pix)

    def _do_search(self) -> None:
        text = self._search_input.text().strip()
        self.refresh(search=text if text else None)

    def _on_selected(self, index: int) -> None:
        if 0 <= index < len(self._bookmarks):
            self.bookmark_selected.emit(self._bookmarks[index])

    def _on_activated(self, index: int) -> None:
        if 0 <= index < len(self._bookmarks):
            self.bookmark_activated.emit(self._bookmarks[index])

    def _copy_to_library_unsorted(self, fav: Bookmark) -> None:
        """Copy a bookmarked image to the unsorted library folder."""
        from ..core.config import saved_dir
        if fav.cached_path and Path(fav.cached_path).exists():
            import shutil
            src = Path(fav.cached_path)
            dest = saved_dir() / f"{fav.post_id}{src.suffix}"
            if not dest.exists():
                shutil.copy2(src, dest)

    def _copy_to_library(self, fav: Bookmark, folder: str) -> None:
        """Copy a bookmarked image to the library folder on disk."""
        from ..core.config import saved_folder_dir
        if fav.cached_path and Path(fav.cached_path).exists():
            import shutil
            src = Path(fav.cached_path)
            dest = saved_folder_dir(folder) / f"{fav.post_id}{src.suffix}"
            if not dest.exists():
                shutil.copy2(src, dest)

    def _new_folder(self) -> None:
        name, ok = QInputDialog.getText(self, "New Folder", "Folder name:")
        if ok and name.strip():
            self._db.add_folder(name.strip())
            self._refresh_folders()

    def _on_context_menu(self, index: int, pos) -> None:
        if index < 0 or index >= len(self._bookmarks):
            return
        fav = self._bookmarks[index]

        from PySide6.QtGui import QDesktopServices
        from PySide6.QtCore import QUrl
        from .dialogs import save_file

        menu = QMenu(self)

        open_default = menu.addAction("Open in Default App")
        menu.addSeparator()
        save_as = menu.addAction("Save As...")

        # Save to Library submenu
        save_lib_menu = menu.addMenu("Save to Library")
        save_lib_unsorted = save_lib_menu.addAction("Unsorted")
        save_lib_menu.addSeparator()
        save_lib_folders = {}
        for folder in self._db.get_folders():
            a = save_lib_menu.addAction(folder)
            save_lib_folders[id(a)] = folder
        save_lib_menu.addSeparator()
        save_lib_new = save_lib_menu.addAction("+ New Folder...")

        copy_url = menu.addAction("Copy Image URL")
        copy_tags = menu.addAction("Copy Tags")

        # Move to folder submenu
        menu.addSeparator()
        move_menu = menu.addMenu("Move to Folder")
        move_none = move_menu.addAction("Unfiled")
        move_menu.addSeparator()
        folder_actions = {}
        for folder in self._db.get_folders():
            a = move_menu.addAction(folder)
            folder_actions[id(a)] = folder
        move_menu.addSeparator()
        move_new = move_menu.addAction("+ New Folder...")

        menu.addSeparator()
        remove_bookmark = menu.addAction("Remove Bookmark")

        action = menu.exec(pos)
        if not action:
            return

        if action == save_lib_unsorted:
            self._copy_to_library_unsorted(fav)
            self.refresh()
        elif action == save_lib_new:
            name, ok = QInputDialog.getText(self, "New Folder", "Folder name:")
            if ok and name.strip():
                self._db.add_folder(name.strip())
                self._copy_to_library(fav, name.strip())
                self._db.move_bookmark_to_folder(fav.id, name.strip())
                self.refresh()
        elif id(action) in save_lib_folders:
            folder_name = save_lib_folders[id(action)]
            self._copy_to_library(fav, folder_name)
            self.refresh()
        elif action == open_default:
            if fav.cached_path and Path(fav.cached_path).exists():
                QDesktopServices.openUrl(QUrl.fromLocalFile(fav.cached_path))
        elif action == save_as:
            if fav.cached_path and Path(fav.cached_path).exists():
                src = Path(fav.cached_path)
                dest = save_file(self, "Save Image", f"post_{fav.post_id}{src.suffix}", f"Images (*{src.suffix})")
                if dest:
                    import shutil
                    shutil.copy2(src, dest)
        elif action == copy_url:
            QApplication.clipboard().setText(fav.file_url)
        elif action == copy_tags:
            QApplication.clipboard().setText(fav.tags)
        elif action == move_none:
            self._db.move_bookmark_to_folder(fav.id, None)
            self.refresh()
        elif action == move_new:
            name, ok = QInputDialog.getText(self, "New Folder", "Folder name:")
            if ok and name.strip():
                self._db.add_folder(name.strip())
                self._db.move_bookmark_to_folder(fav.id, name.strip())
                self._copy_to_library(fav, name.strip())
                self.refresh()
        elif id(action) in folder_actions:
            folder_name = folder_actions[id(action)]
            self._db.move_bookmark_to_folder(fav.id, folder_name)
            self._copy_to_library(fav, folder_name)
            self.refresh()
        elif action == remove_bookmark:
            self._db.remove_bookmark(fav.site_id, fav.post_id)
            self.refresh()

    def _on_multi_context_menu(self, indices: list, pos) -> None:
        favs = [self._bookmarks[i] for i in indices if 0 <= i < len(self._bookmarks)]
        if not favs:
            return

        menu = QMenu(self)
        save_all = menu.addAction(f"Save All ({len(favs)}) to Library")
        unsave_all = menu.addAction(f"Unsave All ({len(favs)}) from Library")
        menu.addSeparator()

        move_menu = menu.addMenu(f"Move All ({len(favs)}) to Folder")
        move_none = move_menu.addAction("Unfiled")
        move_menu.addSeparator()
        folder_actions = {}
        for folder in self._db.get_folders():
            a = move_menu.addAction(folder)
            folder_actions[id(a)] = folder

        menu.addSeparator()
        remove_all = menu.addAction(f"Remove All Bookmarks ({len(favs)})")

        action = menu.exec(pos)
        if not action:
            return

        if action == save_all:
            for fav in favs:
                if fav.folder:
                    self._copy_to_library(fav, fav.folder)
                else:
                    self._copy_to_library_unsorted(fav)
            self.refresh()
        elif action == unsave_all:
            from ..core.cache import delete_from_library
            for fav in favs:
                delete_from_library(fav.post_id, fav.folder)
            self.refresh()
        elif action == move_none:
            for fav in favs:
                self._db.move_bookmark_to_folder(fav.id, None)
            self.refresh()
        elif id(action) in folder_actions:
            folder_name = folder_actions[id(action)]
            for fav in favs:
                self._db.move_bookmark_to_folder(fav.id, folder_name)
                self._copy_to_library(fav, folder_name)
            self.refresh()
        elif action == remove_all:
            for fav in favs:
                self._db.remove_bookmark(fav.site_id, fav.post_id)
            self.refresh()
