import json
import os
import re
import xml.etree.ElementTree as ET

import xbmc
import xbmcaddon
import xbmcgui
import xbmcvfs


JET_GUIDE_IMPORTED_PATH = xbmcvfs.translatePath(
    "special://userdata/addon_data/plugin.video.jet_guide/jet_guide_imported.json"
)


def debug_log(msg, level=xbmc.LOGINFO):
    xbmc.log(f"[jet_guide] {msg}", level)


def browse_addon_plugin_folders(addon_id, start_path=None):
    plugin_url = f"plugin://{addon_id}/" if not start_path else start_path

    params = {
        "jsonrpc": "2.0",
        "method": "Files.GetDirectory",
        "id": 1,
        "params": {"directory": plugin_url, "media": "files"},
    }
    response = xbmc.executeJSONRPC(json.dumps(params))
    data = json.loads(response)
    items = data.get("result", {}).get("files", [])

    if not items:
        xbmcgui.Dialog().ok("Browse Addon", "No items found in this folder.")
        return None

    display_names = [item.get("label", item.get("file", "")) for item in items]
    item_urls = [item.get("file", "") for item in items]
    is_folder = [item.get("filetype", "") == "directory" for item in items]

    while True:
        choice = xbmcgui.Dialog().select("Browse Addon", display_names + ["[Save this link]", "[Go Back]"])
        if choice < 0 or choice == len(display_names) + 1:
            return None
        if choice == len(display_names):
            title = xbmcgui.Dialog().input("Enter a name for this folder/link", defaultt=plugin_url)
            if title:
                save_link_to_jet_guide({"title": title, "link": plugin_url})
                xbmcgui.Dialog().ok("Saved", f"Link saved:\n{title}")
            continue
        if is_folder[choice]:
            browse_addon_plugin_folders(addon_id, item_urls[choice])
            return

        title = xbmcgui.Dialog().input("Enter a name for this link", defaultt=display_names[choice])
        if title:
            save_link_to_jet_guide({"title": title, "link": item_urls[choice]})
            xbmcgui.Dialog().ok("Saved", f"Link saved:\n{title}")


def save_link_to_jet_guide(link_obj):
    folders_base_path = "special://userdata/addon_data/plugin.video.jet_guide/jet_guide_folders"
    dialog = xbmcgui.Dialog()
    choices = ["Create new folder", "Add to existing folder", "Add to jet_guide_imported"]
    choice = dialog.select("Save link - Choose destination", choices)

    if choice == 0:
        suggested_name = link_obj.get("title", "New Folder")
        folder_name = dialog.input("Enter folder name", defaultt=suggested_name)
        if not folder_name:
            return
        folder_path = xbmcvfs.translatePath(folders_base_path + "/" + folder_name)
        if not xbmcvfs.exists(folder_path):
            xbmcvfs.mkdirs(folder_path)
        links_file = folder_path + "/links.json"
        try:
            if xbmcvfs.exists(links_file):
                with xbmcvfs.File(links_file, "r") as f:
                    links = json.loads(f.read())
            else:
                links = []
        except Exception:
            links = []
        links = [l for l in links if isinstance(l, dict) and "title" in l and "link" in l]
        if isinstance(link_obj, dict) and not any(l.get("link") == link_obj["link"] for l in links):
            links.append(link_obj)
            with xbmcvfs.File(links_file, "w") as f:
                f.write(json.dumps(links, indent=2))
        return

    if choice == 1:
        folder_base = xbmcvfs.translatePath(folders_base_path)
        if not xbmcvfs.exists(folder_base):
            try:
                xbmcvfs.mkdirs(folder_base)
            except Exception as e:
                debug_log(f"DEBUG: mkdirs failed for {folder_base}: {e}", level=xbmc.LOGERROR)

        try:
            folders = [f for f in os.listdir(folder_base) if os.path.isdir(os.path.join(folder_base, f))]
        except Exception as e:
            debug_log(f"DEBUG: os.listdir failed for {folder_base}: {e}", level=xbmc.LOGERROR)
            folders = []

        if not folders:
            dialog.notification("No folders found", "Create a folder first", xbmcgui.NOTIFICATION_INFO)
            return

        filtered_folders = folders
        while True:
            search_term = dialog.input("Search folders (leave blank to show all)")
            if search_term:
                filtered_folders = [f for f in folders if search_term.lower() in f.lower()]
                if not filtered_folders:
                    dialog.notification("No matching folders", "Try another search", xbmcgui.NOTIFICATION_INFO)
                    continue
            selected = dialog.select("Select folder", filtered_folders)
            if selected == -1:
                exit_choice = dialog.yesno("Cancel", "Do you want to exit folder selection?", "No = Search again", "Yes = Exit")
                if exit_choice:
                    return
                continue

            folder_path = folder_base + "/" + filtered_folders[selected]
            links_file = folder_path + "/links.json"
            try:
                if xbmcvfs.exists(links_file):
                    with xbmcvfs.File(links_file, "r") as f:
                        links = json.loads(f.read())
                else:
                    links = []
            except Exception:
                links = []
            links = [l for l in links if isinstance(l, dict) and "title" in l and "link" in l]
            if isinstance(link_obj, dict) and not any(l.get("link") == link_obj["link"] for l in links):
                links.append(link_obj)
                with xbmcvfs.File(links_file, "w") as f:
                    f.write(json.dumps(links, indent=2))
            return

    try:
        if xbmcvfs.exists(JET_GUIDE_IMPORTED_PATH):
            with xbmcvfs.File(JET_GUIDE_IMPORTED_PATH, "r") as f:
                links = json.loads(f.read())
        else:
            links = []
    except Exception:
        links = []
    links = [l for l in links if isinstance(l, dict) and "title" in l and "link" in l]

    if isinstance(link_obj, dict) and not any(l.get("link") == link_obj["link"] for l in links):
        links.append(link_obj)
        with xbmcvfs.File(JET_GUIDE_IMPORTED_PATH, "w") as f:
            f.write(json.dumps(links, indent=2))


def import_channels_from_favourites():
    debug_log("JetGuide DEBUG: Starting import_channels_from_favourites()", level=xbmc.LOGINFO)
    fav_path = xbmcvfs.translatePath("special://userdata/favourites.xml")
    if not xbmcvfs.exists(fav_path):
        debug_log("JetGuide DEBUG: favourites.xml not found at path: " + fav_path, level=xbmc.LOGERROR)
        xbmcgui.Dialog().ok("Import Favourites", "No favourites.xml found.")
        return
    try:
        tree = ET.parse(fav_path)
        root = tree.getroot()
        imported = []
        for item in root.findall(".//favourite"):
            name = item.get("name", "Unknown")
            url = item.text.strip() if item.text else ""
            m = re.search(r'PlayMedia\("([^"]+)"\)', url)
            if m:
                play_url = m.group(1)
                if play_url.startswith("http") or play_url.endswith(".m3u8") or play_url.startswith("plugin://"):
                    imported.append({"title": name, "link": play_url})
            elif url.startswith("http") or url.endswith(".m3u8") or url.startswith("plugin://"):
                imported.append({"title": name, "link": url})

        if not imported:
            debug_log("JetGuide DEBUG: No playable channels found in favourites.xml", level=xbmc.LOGINFO)
            xbmcgui.Dialog().ok("Import Favourites", "No playable channels found in favourites.")
            return

        profile_path = xbmcvfs.translatePath(xbmcaddon.Addon().getAddonInfo('profile'))
        save_path = profile_path + "jet_guide_imported.json"
        if xbmcvfs.exists(save_path):
            with xbmcvfs.File(save_path, 'r') as f:
                existing = json.loads(f.read())
        else:
            existing = []

        for ch in imported:
            if not any(e['link'] == ch['link'] for e in existing):
                existing.append(ch)

        with xbmcvfs.File(save_path, 'w') as f:
            f.write(json.dumps(existing, indent=2, ensure_ascii=False))

        debug_log(f"JetGuide DEBUG: Successfully imported {len(imported)} channels from favourites.", level=xbmc.LOGINFO)
        xbmcgui.Dialog().ok(
            "Import Favourites",
            f"Successfully imported [COLOR yellow]{len(imported)}[/COLOR] channels from  KODI favourites.",
        )
    except Exception as e:
        import traceback

        tb = traceback.format_exc()
        debug_log(f"JetGuide DEBUG: Exception in import_channels_from_favourites: {str(e)}\n{tb}", level=xbmc.LOGERROR)
        xbmcgui.Dialog().ok("Import Favourites", f"Error importing favourites:\n{str(e)}")


def browse_saved_links_dialog():
    folders_base_path = "special://userdata/addon_data/plugin.video.jet_guide/jet_guide_folders"
    folders_base = xbmcvfs.translatePath(folders_base_path)
    profile_path = xbmcvfs.translatePath(xbmcaddon.Addon().getAddonInfo('profile'))
    imported_path = profile_path + "jet_guide_imported.json"

    area_choice = xbmcgui.Dialog().select("Browse Links", ["Jet Guide Imported", "Saved Folders", "INFO"])
    if area_choice == 2:
        readme_path = os.path.join(os.path.dirname(__file__), "README_tenbuttons_115.md")
        if os.path.exists(readme_path):
            with open(readme_path, "r", encoding="utf-8") as f:
                directions = f.read()
            xbmcgui.Dialog().textviewer("Directions", directions)
        else:
            xbmcgui.Dialog().ok("Directions", "Directions file not found.")
        return

    if area_choice == 0:
        if xbmcvfs.exists(imported_path):
            with xbmcvfs.File(imported_path, 'r') as f:
                imported = json.loads(f.read())
            if not imported:
                xbmcgui.Dialog().ok('Jet Guide', 'No imported channels saved.')
                return

            titles = [c.get('title', 'Unknown') for c in imported]
            idx = xbmcgui.Dialog().select('Play Imported Channel', titles)
            if idx < 0:
                return
            link = imported[idx].get('link')
            action = xbmcgui.Dialog().select('Choose Action', ['Play', 'Delete', 'Move to Folder'])
            if action == 0 and link:
                xbmc.Player().play(link)
            elif action == 1:
                del imported[idx]
                with xbmcvfs.File(imported_path, 'w') as f:
                    f.write(json.dumps(imported, indent=2))
                xbmcgui.Dialog().ok('Jet Guide', 'Link deleted.')
            elif action == 2:
                _move_imported_link_to_folder(imported, idx, imported_path, folders_base)
        else:
            xbmcgui.Dialog().ok('Jet Guide', 'No imported channels saved.')
        return

    if area_choice == 1:
        _browse_saved_folders(folders_base)


def _move_imported_link_to_folder(imported, idx, imported_path, folders_base):
    try:
        folders = [f for f in os.listdir(folders_base) if os.path.isdir(os.path.join(folders_base, f))]
    except Exception as e:
        debug_log(f"DEBUG: os.listdir failed for {folders_base}: {e}", level=xbmc.LOGERROR)
        folders = []

    if not folders:
        if xbmcgui.Dialog().yesno("No Folders Found", "Would you like to create a new folder?"):
            folder_name = xbmcgui.Dialog().input("Enter folder name")
            if folder_name:
                new_folder_path = os.path.join(folders_base, folder_name)
                try:
                    os.makedirs(new_folder_path, exist_ok=True)
                    links_file = os.path.join(new_folder_path, "links.json")
                    with open(links_file, "w", encoding="utf-8") as f:
                        json.dump([imported[idx]], f, indent=2)
                    del imported[idx]
                    with xbmcvfs.File(imported_path, 'w') as f:
                        f.write(json.dumps(imported, indent=2))
                    xbmcgui.Dialog().ok("Success", f"Link moved to new folder '{folder_name}'.")
                except Exception as e:
                    xbmcgui.Dialog().ok("Error", f"Failed to create folder: {e}")
        return

    folder_options = folders + ["[Create New Folder]"]
    folder_idx = xbmcgui.Dialog().select('Select Folder', folder_options)
    if folder_idx < 0:
        return

    if folder_idx == len(folders):
        folder_name = xbmcgui.Dialog().input("Enter folder name")
        if folder_name:
            new_folder_path = os.path.join(folders_base, folder_name)
            try:
                os.makedirs(new_folder_path, exist_ok=True)
                links_file = os.path.join(new_folder_path, "links.json")
                with open(links_file, "w", encoding="utf-8") as f:
                    json.dump([imported[idx]], f, indent=2)
                del imported[idx]
                with xbmcvfs.File(imported_path, 'w') as f:
                    f.write(json.dumps(imported, indent=2))
                xbmcgui.Dialog().ok("Success", f"Link moved to new folder '{folder_name}'.")
            except Exception as e:
                xbmcgui.Dialog().ok("Error", f"Failed to create folder: {e}")
        return

    folder_path = os.path.join(folders_base, folders[folder_idx])
    links_file = os.path.join(folder_path, "links.json")
    if os.path.exists(links_file):
        with open(links_file, "r", encoding="utf-8") as f:
            folder_links = json.load(f)
    else:
        folder_links = []
    folder_links.append(imported[idx])
    with open(links_file, "w", encoding="utf-8") as f:
        json.dump(folder_links, f, indent=2)
    xbmcgui.Dialog().ok('Jet Guide', 'Link moved to folder.')
    del imported[idx]
    with xbmcvfs.File(imported_path, 'w') as f:
        f.write(json.dumps(imported, indent=2))


def _browse_saved_folders(folders_base):
    try:
        folders = [f for f in os.listdir(folders_base) if os.path.isdir(os.path.join(folders_base, f))]
    except Exception as e:
        debug_log(f"DEBUG: os.listdir failed for {folders_base}: {e}", level=xbmc.LOGERROR)
        folders = []

    if not folders:
        if xbmcgui.Dialog().yesno("No Folders Found", "Would you like to create a new folder?"):
            folder_name = xbmcgui.Dialog().input("Enter folder name")
            if folder_name:
                new_folder_path = os.path.join(folders_base, folder_name)
                try:
                    os.makedirs(new_folder_path, exist_ok=True)
                    links_file = os.path.join(new_folder_path, "links.json")
                    with open(links_file, "w", encoding="utf-8") as f:
                        json.dump([], f)
                    xbmcgui.Dialog().ok("Success", f"Folder '{folder_name}' created.")
                except Exception as e:
                    xbmcgui.Dialog().ok("Error", f"Failed to create folder: {e}")
        return

    folder_options = folders + ["[Create New Folder]"]
    folder_idx = xbmcgui.Dialog().select('Select Folder', folder_options)
    if folder_idx < 0:
        return

    if folder_idx == len(folders):
        folder_name = xbmcgui.Dialog().input("Enter folder name")
        if folder_name:
            new_folder_path = os.path.join(folders_base, folder_name)
            try:
                os.makedirs(new_folder_path, exist_ok=True)
                links_file = os.path.join(new_folder_path, "links.json")
                with open(links_file, "w", encoding="utf-8") as f:
                    json.dump([], f)
                xbmcgui.Dialog().ok("Success", f"Folder '{folder_name}' created.")
            except Exception as e:
                xbmcgui.Dialog().ok("Error", f"Failed to create folder: {e}")
        return

    folder_path = os.path.join(folders_base, folders[folder_idx])
    links_file = os.path.join(folder_path, "links.json")
    if not os.path.exists(links_file):
        xbmcgui.Dialog().ok('Jet Guide', 'No links.json found in folder.')
        return

    with open(links_file, "r", encoding="utf-8") as f:
        links = json.load(f)
    if not links:
        xbmcgui.Dialog().ok('Jet Guide', 'No links found in folder.')
        return

    titles = [c.get('title', 'Unknown') for c in links]
    idx = xbmcgui.Dialog().select('Play Folder Link', titles)
    if idx < 0:
        return

    link = links[idx].get('link')
    action = xbmcgui.Dialog().select('Choose Action', ['Play', 'Delete'])
    if action == 0 and link:
        xbmc.Player().play(link)
    elif action == 1:
        del links[idx]
        with open(links_file, "w", encoding="utf-8") as f:
            json.dump(links, f, indent=2)
        xbmcgui.Dialog().ok('Jet Guide', 'Link deleted.')


def browse_installed_video_addons():
    """Browse installed video addons and return selected addon ID."""
    addons_dir = xbmcvfs.translatePath('special://home/addons')
    addon_ids = []
    addon_names = []
    for addon_id in os.listdir(addons_dir):
        addon_xml = os.path.join(addons_dir, addon_id, 'addon.xml')
        if os.path.isfile(addon_xml):
            try:
                with open(addon_xml, encoding='utf-8') as f:
                    xml = f.read()
                if 'extension point="xbmc.python.pluginsource"' in xml and '<provides>video</provides>' in xml:
                    addon_ids.append(addon_id)
                    m = re.search(r'name="([^"]+)"', xml)
                    addon_names.append(m.group(1) if m else addon_id)
            except Exception:
                continue
    if not addon_ids:
        xbmcgui.Dialog().ok('Kodi Addons', 'No video addons found.')
        return None
    choice = xbmcgui.Dialog().select('Select Kodi Addon', addon_names)
    if choice < 0:
        return None
    return addon_ids[choice]


def save_widget_link(link_obj):
    """Save a link object to widgets.json for widget display."""
    widgets_path = xbmcvfs.translatePath("special://userdata/addon_data/plugin.video.jet_guide/widgets.json")
    try:
        if xbmcvfs.exists(widgets_path):
            with xbmcvfs.File(widgets_path, "r") as f:
                links = json.loads(f.read())
        else:
            links = []
    except Exception:
        links = []

    links = [l for l in links if isinstance(l, dict) and "title" in l and ("link" in l or "source_folder" in l)]

    def get_widget_key(w):
        return w.get("link") or w.get("source_folder")

    new_key = get_widget_key(link_obj)
    if isinstance(link_obj, dict) and new_key and not any(get_widget_key(l) == new_key for l in links):
        links.append(link_obj)
        with xbmcvfs.File(widgets_path, "w") as f:
            f.write(json.dumps(links, indent=2))
