import os
import threading
import json
import urllib.request
import urllib.parse

class HollowSteamBackend:
    def __init__(self):
        self.log_output = ""
        self._search_results = []
        self.current_app_id = "-"
        self.current_game_name = "-"
        self.current_depots_count = "-"
        self.current_dlcs_count = "-"
        self.add_to_steam_enabled = False
        self.add_to_cart_enabled = False
        self.cart_count = 0
        self.cart = []
        self._current_packages = []
        self.is_searching = False
        self.is_fetching_details = False

        self.config_dir = os.path.expanduser("~/.config/protocol7")
        os.makedirs(self.config_dir, exist_ok=True)
        self.settings_file = os.path.join(self.config_dir, "settings.json")
        
        self.settings_cache = self._load_settings()

    def append_log(self, msg):
        self.log_output += msg + "\n"

    def clear_search_results(self):
        self._search_results = []
        self.current_app_id = "-"
        self.current_game_name = "-"
        self.current_depots_count = "-"
        self.current_dlcs_count = "-"
        self.add_to_steam_enabled = False
        self.add_to_cart_enabled = False
        self.is_searching = False
        self.is_fetching_details = False

    def _load_settings(self):
        try:
            if os.path.exists(self.settings_file):
                with open(self.settings_file, "r") as f:
                    return json.load(f)
        except Exception:
            pass
        return {
            "add_to_additional_apps": True,
            "theme_color": "#1d2020",
            "accent_color": "#93d2d0"
        }

    def _save_settings(self, data):
        self.settings_cache.update(data)
        try:
            with open(self.settings_file, "w") as f:
                json.dump(self.settings_cache, f, indent=2)
        except Exception as e:
            self.append_log(f"Failed to save settings: {e}")

    def _sync_toggle_additional_apps(self):
        current = self.settings_cache.get("add_to_additional_apps", True)
        new_val = not current
        self._save_settings({"add_to_additional_apps": new_val})
        print(f"Toggled 'Add to AdditionalApps' to: {new_val}")

    def perform_search(self, query):
        if not query:
            return
            
        self.add_to_steam_enabled = False
        self.add_to_cart_enabled = False
        self.is_searching = True
        self.append_log(f"Searching Steam Store for '{query}'...")
        thread = threading.Thread(target=self._search_steam_store_thread, args=(query,))
        thread.start()

    def _search_steam_store_thread(self, query):
        try:
            encoded_query = urllib.parse.quote(query)
            url = f"https://store.steampowered.com/api/storesearch/?term={encoded_query}&l=english&cc=US"
            req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
            with urllib.request.urlopen(req, timeout=15) as response:
                data = json.loads(response.read())

            items = data.get("items", [])
            if not items:
                self.append_log("No results found.")
                self.clear_search_results()
                return

            results = []
            for item in items:
                results.append({
                    "app_id": str(item["id"]),
                    "title": item["name"]
                })

            self._search_results = results
            self.append_log(f"Found {len(results)} results.")
        except Exception as e:
            self.append_log(f"Search error: {e}")
        finally:
            self.is_searching = False

    def select_result(self, index):
        if 0 <= index < len(self._search_results):
            result = self._search_results[index]
            self.current_app_id = str(result["app_id"])
            self.current_game_name = result["title"]
            self.append_log(f"Selected: {result['title']} ({result['app_id']})")
            
            self.is_fetching_details = True
            thread = threading.Thread(target=self._fetch_game_details_thread, args=(result["app_id"],))
            thread.start()

    def _fetch_game_details_thread(self, app_id):
        try:
            url = f"https://api.steamcmd.net/v1/info/{app_id}"
            req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
            with urllib.request.urlopen(req, timeout=15) as response:
                data = json.loads(response.read())

            app_data = data.get("data", {}).get(app_id, {})
            depots = app_data.get("depots", {})
            self.current_depots_count = str(len(depots))
            self.current_dlcs_count = "0"  # Simplify DLC count for now
            self.add_to_steam_enabled = True
            self.add_to_cart_enabled = True
        except Exception as e:
            self.append_log(f"Failed to fetch details from SteamCMD: {e}")
            self.current_depots_count = "?"
            self.current_dlcs_count = "?"
            
        packages = []
        try:
            url = f"https://store.steampowered.com/api/appdetails?appids={app_id}"
            req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
            with urllib.request.urlopen(req, timeout=15) as response:
                data = json.loads(response.read())
            
            if data and str(app_id) in data and data[str(app_id)].get("success"):
                packages = data[str(app_id)]["data"].get("packages", [])
                if packages:
                    self.append_log(f"Found {len(packages)} packages.")
        except Exception as e:
            self.append_log(f"Failed to fetch packages from Steam: {e}")
            
        self._current_packages = packages
        self.add_to_steam_enabled = True # Allow adding anyway
        self.add_to_cart_enabled = True
        self.is_fetching_details = False

    def add_to_steam(self):
        if self.current_app_id == "-" or self.current_game_name == "-":
            return
        
        self.add_to_steam_enabled = False
        thread = threading.Thread(target=self._add_to_sls_thread, args=(self.current_app_id, self.current_game_name, self._current_packages))
        thread.start()

    def _sync_search(self, query):
        print(f"Searching Steam Store for '{query}'...")
        encoded_query = urllib.parse.quote(query)
        url = f"https://store.steampowered.com/api/storesearch/?term={encoded_query}&l=english&cc=US"
        try:
            req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
            with urllib.request.urlopen(req, timeout=15) as response:
                data = json.loads(response.read())

            items = data.get("items", [])
            if not items:
                print("No results found.")
                return []

            results = []
            for item in items:
                results.append({
                    "app_id": str(item["id"]),
                    "title": item["name"]
                })
            return results
        except Exception as e:
            print(f"Search error: {e}")
            return []

    def _sync_install(self, target):
        if target.isdigit():
            app_id = target
            title = "Unknown (Direct Install)"
        else:
            results = self._sync_search(target)
            if not results:
                print(f"Could not find any game matching '{target}'.")
                return
            app_id = results[0]["app_id"]
            title = results[0]["title"]
            print(f"Found match: {title} ({app_id})")

        print("Fetching app details...")
        packages = []
        try:
            url = f"https://store.steampowered.com/api/appdetails?appids={app_id}"
            req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
            with urllib.request.urlopen(req, timeout=15) as response:
                data = json.loads(response.read())
            
            if data and str(app_id) in data and data[str(app_id)].get("success"):
                app_data = data[str(app_id)]["data"]
                packages = app_data.get("packages", [])
                
                if title == "Unknown (Direct Install)":
                    title = app_data.get("name", title)
                    print(f"Resolved name: {title}")
        except Exception as e:
            print(f"Failed to fetch app details: {e}")

        self._sync_add_to_sls(app_id, title, packages)

    def _sync_add_to_sls(self, app_id, title, packages):
        try:
            sls_config_path = os.path.expanduser("~/.config/SLSsteam/config.yaml")
            if not os.path.exists(sls_config_path):
                print("SLSsteam config.yaml not found!")
                return

            with open(sls_config_path, "r") as f:
                lines = f.readlines()

            def insert_into_section(content_lines, section_header, new_item):
                try:
                    header_index = next(
                        i for i, line in enumerate(content_lines)
                        if line.strip() == section_header
                    )
                    for i in range(header_index + 1, len(content_lines)):
                        if content_lines[i].strip().startswith("-") and new_item.strip() in content_lines[i]:
                            return False
                        if content_lines[i].strip() and not content_lines[i].startswith(" "):
                            break
                    content_lines.insert(header_index + 1, f"  - {new_item}\n")
                    return True
                except StopIteration:
                    content_lines.append(f"\n{section_header}\n  - {new_item}\n")
                    return True

            needs_save = False
            item_entry = f"{app_id} # {title}"
            
            if self.settings_cache.get("add_to_additional_apps", True):
                if insert_into_section(lines, "AdditionalApps:", item_entry):
                    needs_save = True
                    print(f"Added {app_id} to AdditionalApps")
                else:
                    print(f"{app_id} already exists in AdditionalApps")
            else:
                print("Skipping adding to AdditionalApps (disabled in settings).")

            for pkg_id in packages:
                pkg_entry = f"{pkg_id} # {title}"
                if insert_into_section(lines, "AdditionalPackages:", pkg_entry):
                    needs_save = True
                    print(f"Added package {pkg_id} to AdditionalPackages")
                else:
                    print(f"Package {pkg_id} already exists in AdditionalPackages")

            if needs_save:
                with open(sls_config_path, "w") as f:
                    f.writelines(lines)
                print("Updated SLSsteam config.yaml successfully.")

        except Exception as e:
            print(f"Failed to update SLS config: {e}")

    def install_app(self, target):
        self.append_log(f"Handling --install {target}")
        thread = threading.Thread(target=self._install_thread, args=(target,))
        thread.start()

    def _install_thread(self, target):
        # if target is digits, it's an appid
        if target.isdigit():
            app_id = target
            title = "Unknown (Direct Install)"
        else:
            # search for target
            self.append_log(f"Searching for {target} to install...")
            encoded_query = urllib.parse.quote(target)
            url = f"https://store.steampowered.com/api/storesearch/?term={encoded_query}&l=english&cc=US"
            try:
                req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
                with urllib.request.urlopen(req, timeout=15) as response:
                    data = json.loads(response.read())
                items = data.get("items", [])
                if not items:
                    self.append_log(f"Could not find any game matching '{target}'.")
                    return
                app_id = str(items[0]["id"])
                title = items[0]["name"]
                self.append_log(f"Found match: {title} ({app_id})")
            except Exception as e:
                self.append_log(f"Search error: {e}")
                return

        # fetch details
        self.is_fetching_details = True
        self.current_app_id = str(app_id)
        self.current_game_name = title
        
        packages = []
        try:
            url = f"https://store.steampowered.com/api/appdetails?appids={app_id}"
            req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
            with urllib.request.urlopen(req, timeout=15) as response:
                data = json.loads(response.read())
            
            if data and str(app_id) in data and data[str(app_id)].get("success"):
                app_data = data[str(app_id)]["data"]
                packages = app_data.get("packages", [])
                
                if title == "Unknown (Direct Install)":
                    title = app_data.get("name", title)
                    self.current_game_name = title
                    self.append_log(f"Resolved name: {title}")
        except Exception as e:
            self.append_log(f"Failed to fetch app details: {e}")

        self._current_packages = packages
        self.is_fetching_details = False
        
        # directly add to SLS
        self._add_to_sls_thread(app_id, title, packages)

    def _add_to_sls_thread(self, app_id, title, packages):
        try:
            sls_config_path = os.path.expanduser("~/.config/SLSsteam/config.yaml")
            if not os.path.exists(sls_config_path):
                self.append_log("SLSsteam config.yaml not found!")
                self.add_to_steam_enabled = True
                return

            with open(sls_config_path, "r") as f:
                lines = f.readlines()

            def insert_into_section(content_lines, section_header, new_item):
                try:
                    header_index = next(
                        i for i, line in enumerate(content_lines)
                        if line.strip() == section_header
                    )
                    for i in range(header_index + 1, len(content_lines)):
                        if content_lines[i].strip().startswith("-") and new_item.strip() in content_lines[i]:
                            return False
                        if content_lines[i].strip() and not content_lines[i].startswith(" "):
                            break
                    content_lines.insert(header_index + 1, f"  - {new_item}\n")
                    return True
                except StopIteration:
                    content_lines.append(f"\n{section_header}\n  - {new_item}\n")
                    return True

            needs_save = False
            item_entry = f"{app_id} # {title}"
            
            if self.settings_cache.get("add_to_additional_apps", True):
                if insert_into_section(lines, "AdditionalApps:", item_entry):
                    needs_save = True
                    self.append_log(f"Added {app_id} to AdditionalApps")
                else:
                    self.append_log(f"{app_id} already exists in AdditionalApps")
            else:
                self.append_log("Skipping adding to AdditionalApps (disabled in settings).")

            for pkg_id in packages:
                pkg_entry = f"{pkg_id} # {title}"
                if insert_into_section(lines, "AdditionalPackages:", pkg_entry):
                    needs_save = True
                    self.append_log(f"Added package {pkg_id} to AdditionalPackages")
                else:
                    self.append_log(f"Package {pkg_id} already exists in AdditionalPackages")

            if needs_save:
                with open(sls_config_path, "w") as f:
                    f.writelines(lines)
                self.append_log("Updated SLSsteam config.yaml successfully.")

        except Exception as e:
            self.append_log(f"Failed to update SLS config: {e}")
        finally:
            self.add_to_steam_enabled = True

    def on_add_to_cart_clicked(self):
        if self.current_app_id == "-" or self.current_game_name == "-":
            return
        
        for item in self.cart:
            if item["app_id"] == self.current_app_id:
                self.append_log(f"{self.current_game_name} is already in cart")
                return

        self.cart.append({
            "app_id": self.current_app_id,
            "title": self.current_game_name,
            "packages": self._current_packages
        })
        self.append_log(f"Added {self.current_game_name} to cart")
        self.cart_count = len(self.cart)

    def clear_cart(self):
        self.cart.clear()
        self.cart_count = 0
        self.append_log("Cart cleared.")

    def remove_from_cart(self, app_id):
        original_length = len(self.cart)
        self.cart = [item for item in self.cart if str(item["app_id"]) != str(app_id)]
        if len(self.cart) < original_length:
            self.cart_count = len(self.cart)
            self.append_log(f"Removed item {app_id} from cart.")

    def download_cart(self):
        if not self.cart:
            return
            
        thread = threading.Thread(target=self._download_cart_thread)
        thread.start()

    def _download_cart_thread(self):
        try:
            sls_config_path = os.path.expanduser("~/.config/SLSsteam/config.yaml")
            if not os.path.exists(sls_config_path):
                self.append_log("SLSsteam config.yaml not found!")
                return

            with open(sls_config_path, "r") as f:
                lines = f.readlines()

            def insert_into_section(content_lines, section_header, new_item):
                try:
                    header_index = next(
                        i for i, line in enumerate(content_lines)
                        if line.strip() == section_header
                    )
                    for i in range(header_index + 1, len(content_lines)):
                        if content_lines[i].strip().startswith("-") and new_item.strip() in content_lines[i]:
                            return False
                        if content_lines[i].strip() and not content_lines[i].startswith(" "):
                            break
                    content_lines.insert(header_index + 1, f"  - {new_item}\n")
                    return True
                except StopIteration:
                    content_lines.append(f"\n{section_header}\n  - {new_item}\n")
                    return True

            needs_save = False
            for item in self.cart:
                item_entry = f"{item['app_id']} # {item['title']}"
                if self.settings_cache.get("add_to_additional_apps", True):
                    if insert_into_section(lines, "AdditionalApps:", item_entry):
                        needs_save = True
                        self.append_log(f"Added {item['app_id']} to AdditionalApps")
                    else:
                        self.append_log(f"{item['app_id']} already exists in AdditionalApps")
                else:
                    self.append_log(f"Skipping {item['app_id']} for AdditionalApps (disabled).")

                for pkg_id in item.get('packages', []):
                    pkg_entry = f"{pkg_id} # {item['title']}"
                    if insert_into_section(lines, "AdditionalPackages:", pkg_entry):
                        needs_save = True
                        self.append_log(f"Added package {pkg_id} to AdditionalPackages")
                    else:
                        self.append_log(f"Package {pkg_id} already exists in AdditionalPackages")

            if needs_save:
                with open(sls_config_path, "w") as f:
                    f.writelines(lines)
                self.append_log("Updated SLSsteam config.yaml successfully.")

            self.cart.clear()
            self.cart_count = 0

        except Exception as e:
            self.append_log(f"Failed to process cart: {e}")
