import json
import os
import sys

import xbmc
import xbmcgui

from lib.utils.kodi.settings import get_setting
from lib.utils.kodi.utils import kodilog, set_setting


def choose_external_scraper():
    """Display a dialog to choose an external scraper module.

    Lists all enabled ``xbmc.python.module`` addons, lets the user pick
    one, tests compatibility by importing its ``sources()`` function, and
    stores the selection in settings.
    """
    addons = _list_compatible_modules()
    if not addons:
        xbmcgui.Dialog().notification(
            "Jacktook",
            get_setting("external_scraper_no_modules_msg") or "No compatible modules found",
        )
        return

    items = []
    for addon in addons:
        name = addon.get("name", "")
        icon = addon.get("thumbnail", "")
        li = xbmcgui.ListItem(label=name)
        li.setArt({"icon": icon})
        items.append(li)

    heading = get_setting("external_scraper_choose_heading") or "Choose External Scraper"
    selected = xbmcgui.Dialog().select(heading, items, useDetails=True)
    if selected == -1:
        return

    chosen = addons[selected]
    module_id = chosen["addonid"]
    module_name = chosen["name"]

    # Test compatibility
    if not _test_module_compatibility(chosen):
        error_msg = (
            get_setting("external_scraper_incompatible_msg")
            or "The selected module is not compatible. Please choose a different one."
        )
        xbmcgui.Dialog().ok("Jacktook", error_msg)
        # Let user try again
        choose_external_scraper()
        return

    # Success — persist selection
    set_setting("external_scraper_module", module_id)
    set_setting("external_scraper_module_name", module_name)
    set_setting("external_scraper_enabled", "true")

    success_msg = (
        get_setting("external_scraper_success_msg")
        or f"Success!\n{module_name} set as External Scraper"
    )
    xbmcgui.Dialog().ok("Jacktook", success_msg)


def open_external_scraper_settings():
    """Open Kodi's settings window for the currently selected scraper."""
    module_id = get_setting("external_scraper_module")
    kodilog(f"ExternalScraper: open settings requested, module={module_id}")
    if not module_id:
        xbmcgui.Dialog().notification("Jacktook", "No external scraper selected")
        return
    try:
        # When this action is launched from Jacktook's settings window, the
        # current modal settings dialog can stay in front of (or block) the
        # external addon's settings window. Close it first, then open the
        # selected scraper settings.
        xbmc.executebuiltin("Dialog.Close(addonsettings)")
        xbmc.sleep(300)
        xbmc.executebuiltin(f"Addon.OpenSettings({module_id})")
        xbmc.sleep(500)
    except Exception as exc:
        kodilog(f"ExternalScraper: Addon.OpenSettings failed: {exc}")
        xbmcgui.Dialog().notification("Jacktook", f"Unable to open settings: {module_id}")


# ------------------------------------------------------------------
# Internal helpers
# ------------------------------------------------------------------


def _list_compatible_modules() -> list:
    """Return a list of enabled ``xbmc.python.module`` addons."""
    try:
        response = xbmc.executeJSONRPC(
            json.dumps(
                {
                    "jsonrpc": "2.0",
                    "method": "Addons.GetAddons",
                    "params": {
                        "type": "xbmc.python.module",
                        "enabled": True,
                        "properties": ["name", "thumbnail", "path"],
                    },
                    "id": 1,
                }
            )
        )
        data = json.loads(response)
        addons = data.get("result", {}).get("addons", [])
        # Exclude Kodi's own system modules
        return [a for a in addons if not a["addonid"].startswith(("xbmc.", "kodi."))]
    except Exception as exc:
        kodilog(f"ExternalScraper: failed to list modules: {exc}")
        return []


def _test_module_compatibility(addon: dict) -> bool:
    """Try importing ``sources()`` from *addon* to verify compatibility."""
    module_id = addon["addonid"]
    module_name = module_id.split(".")[-1]
    addon_path = addon.get("path", "")

    lib_path = os.path.join(addon_path, "lib")
    if not os.path.isdir(lib_path):
        kodilog(f"ExternalScraper: no lib dir for {module_id}")
        return False

    # Temporarily add to sys.path (we leave it there since the scraper
    # will need it at search time anyway).
    if lib_path not in sys.path:
        sys.path.insert(0, lib_path)

    try:
        module = __import__(module_name, fromlist=["sources"])
        source_dict = module.sources(specified_folders=["torrents"])
        if not source_dict:
            kodilog(f"ExternalScraper: {module_id} returned no providers")
            return False
        return True
    except Exception as exc:
        kodilog(f"ExternalScraper: {module_id} compatibility test failed: {exc}")
        return False
