#!/usr/bin/python3

# This script is a GUI for slakfinder <https://slackware.nl/slakfinder/index.php>
# Requires BeautifulSoup4 + (PyQt6 or PyQt5)
# License MIT Anagnostakis Ioannis 2025 GR
#
# --- PyQt6 added in Slackware-current (21/6/2026) ---
# --- PyQt5/PyQt6 dual support ---

import sys
from urllib.parse import urljoin

import requests
from bs4 import BeautifulSoup

# ---------------------------------------------------------------- Qt bindings
try:
    from PyQt6.QtWidgets import (QApplication, QWidget, QVBoxLayout, QLineEdit,
                                 QPushButton, QTableWidget, QTableWidgetItem,
                                 QHeaderView, QMessageBox)
    from PyQt6.QtGui import QDesktopServices, QColor
    from PyQt6.QtCore import QUrl, Qt
    QT_API = "PyQt6"
except ImportError:
    from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QLineEdit,
                                 QPushButton, QTableWidget, QTableWidgetItem,
                                 QHeaderView, QMessageBox)
    from PyQt5.QtGui import QDesktopServices, QColor
    from PyQt5.QtCore import QUrl, Qt
    QT_API = "PyQt5"


def qt_enum(scope, group, name):
    """Return scope.group.name (Qt6 scoped) falling back to scope.name (Qt5 flat)."""
    grp = getattr(scope, group, None)
    if grp is not None:
        val = getattr(grp, name, None)
        if val is not None:
            return val
    return getattr(scope, name)


ALIGN_CENTER = qt_enum(Qt, "AlignmentFlag", "AlignCenter")
ITEM_EDITABLE = qt_enum(Qt, "ItemFlag", "ItemIsEditable")
ITEM_SELECTABLE = qt_enum(Qt, "ItemFlag", "ItemIsSelectable")
ITEM_ENABLED = qt_enum(Qt, "ItemFlag", "ItemIsEnabled")
KEY_RETURN = qt_enum(Qt, "Key", "Key_Return")
KEY_ENTER = qt_enum(Qt, "Key", "Key_Enter")
HDR_STRETCH = qt_enum(QHeaderView, "ResizeMode", "Stretch")

BASE_URL = "https://slackware.nl/slakfinder/"


class SlakfinderApp(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Slackware Package Finder (%s)" % QT_API)
        self.setGeometry(200, 200, 1000, 600)

        layout = QVBoxLayout()
        self.search_bar = QLineEdit(self)
        self.search_bar.setPlaceholderText("Enter package name...")
        self.search_button = QPushButton("Search", self)
        self.search_button.clicked.connect(self.search_packages)

        self.home_button = QPushButton("Slakfinder Web", self)
        self.home_button.clicked.connect(self.open_slakfinder_home)

        self.search_bar.returnPressed.connect(self.search_packages)

        self.table = QTableWidget()
        self.table.setColumnCount(8)
        self.table.setHorizontalHeaderLabels(
            ["Rank", "Package", "Version", "Arch", "Distro",
             "Repository", "Location", "Download"])
        self.table.horizontalHeader().setSectionResizeMode(HDR_STRETCH)
        self.table.cellDoubleClicked.connect(self.open_link)

        layout.addWidget(self.search_bar)
        layout.addWidget(self.search_button)
        layout.addWidget(self.home_button)
        layout.addWidget(self.table)
        self.setLayout(layout)

    def search_packages(self):
        query = self.search_bar.text().strip()
        if not query:
            return

        self.table.setRowCount(0)

        params = {'act': 'search', 'name': query, 'repo': 0}
        try:
            response = requests.get(BASE_URL, params=params, timeout=20)
            response.raise_for_status()
        except requests.RequestException as exc:
            QMessageBox.warning(self, "Network error", str(exc))
            return

        soup = BeautifulSoup(response.text, 'html.parser')

        results = []
        result_table = soup.find('table', {'class': 'results'})

        if result_table:
            rows = result_table.find_all('tr')[1:]  # Skip the header row
            for row in rows:
                cols = row.find_all('td')
                if len(cols) > 6:
                    rank = cols[0].text.strip()
                    package = cols[1].text.strip()
                    version = cols[2].text.strip()
                    arch = cols[3].text.strip()
                    distro = cols[4].text.strip()
                    repository = cols[5].text.strip()
                    location = cols[6].text.strip()

                    download_link = None
                    download_tag = cols[6].find('a', href=True)
                    if download_tag:
                        download_link = urljoin(BASE_URL, download_tag['href'])

                    results.append((rank, package, version, arch, distro,
                                    repository, location, download_link))

        if not results:
            print("No results found for your query.")
            return

        self.table.setRowCount(len(results))
        for row, (rank, package, version, arch, distro,
                  repository, location, download_url) in enumerate(results):
            for col, value in enumerate((rank, package, version, arch,
                                         distro, repository, location)):
                self.table.setItem(row, col, QTableWidgetItem(value))

            if download_url:
                self.table.setItem(row, 7, self.create_clickable_item(download_url))
            else:
                self.table.setItem(row, 7, QTableWidgetItem("No download"))

    def create_clickable_item(self, text):
        item = QTableWidgetItem(text)
        item.setForeground(QColor(0, 0, 255))
        item.setTextAlignment(ALIGN_CENTER)
        item.setFlags((item.flags() & ~ITEM_EDITABLE) | ITEM_SELECTABLE | ITEM_ENABLED)
        return item

    def _open(self, url):
        if url and url != "No download":
            QDesktopServices.openUrl(QUrl(url))

    def open_link(self, row, column):
        if column == 7:
            item = self.table.item(row, column)
            if item:
                self._open(item.text())

    def open_slakfinder_home(self):
        QDesktopServices.openUrl(QUrl("https://slackware.nl/slakfinder/index.php"))

    def keyPressEvent(self, event):
        if event.key() in (KEY_RETURN, KEY_ENTER):
            row = self.table.currentRow()
            col = self.table.currentColumn()
            if col == 7 and row >= 0:
                item = self.table.item(row, col)
                if item:
                    self._open(item.text())
            event.accept()
            return
        super().keyPressEvent(event)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = SlakfinderApp()
    window.show()
    run = getattr(app, "exec", None) or app.exec_
    sys.exit(run())