изучи 
import requests
import os
import json
import sqlite3
import tkinter as tk
from tkinter import messagebox, Toplevel, filedialog, font
from threading import Thread
from tkinter.scrolledtext import ScrolledText
from ttkbootstrap import Style
from ttkbootstrap.constants import *
from ttkbootstrap import ttk
from PIL import ImageTk, Image, ImageResampling

CONFIG_FILE = 'config.json'

# === Загрузка и сохранение конфигурации ===
def load_config():
    if not os.path.exists(CONFIG_FILE):
        default_config = {
            "mc_version": "",
            "mod_loader": "Forge",
            "default_keywords": [],
            "download_folder": "downloads",
            "user_agent": "ModPackBuilder/1.0 (+contact@yourdomain.com)",
        }
        with open(CONFIG_FILE, 'w', encoding='utf-8') as f:
            json.dump(default_config, f, indent=4, ensure_ascii=False)
    with open(CONFIG_FILE, 'r', encoding='utf-8') as f:
        return json.load(f)

def save_config(config):
    with open(CONFIG_FILE, 'w', encoding='utf-8') as f:
        json.dump(config, f, indent=4, ensure_ascii=False)

# === Modrinth API запросы и обработка ===
def search_projects_modrinth(description, project_type, mc_version=None, modloader=None, user_agent="ModPackBuilder"):
    url = 'https://api.modrinth.com/v2/search'
    headers = {'User-Agent': user_agent}
    facets = [
        [f"project_type:{project_type}"],
    ]
    if mc_version:
        facets.append([f"versions:{mc_version}"])
    if modloader and project_type == "mod":
        facets.append([f"categories:{modloader.lower()}"])
    params = {'query': description, 'facets': json.dumps(facets), 'limit': 100}
    response = requests.get(url, params=params, headers=headers)
    if response.status_code == 200:
        return response.json().get('hits', [])
    else:
        messagebox.showerror("Ошибка", f"Modrinth API Ошибка: {response.status_code}")
        return []

def get_latest_compatible_version_modrinth(project_id, mc_version=None, modloader=None, user_agent="ModPackBuilder"):
    url = f'https://api.modrinth.com/v2/project/{project_id}/version'
    headers = {'User-Agent': user_agent}
    response = requests.get(url, headers=headers)
    if response.status_code == 200:
        versions = response.json()
        if mc_version and modloader:
            compatible_versions = [v for v in versions if mc_version in v['game_versions'] and modloader.lower() in [loader.lower() for loader in v.get('loaders', [])]]
        elif mc_version:
            compatible_versions = [v for v in versions if mc_version in v['game_versions']]
        else:
            compatible_versions = versions

        if compatible_versions:
            for version in compatible_versions:
                if version['version_type'] == 'release':
                    return version
            return compatible_versions[0]
    return None

def get_mod_dependencies(version):
    dependencies = version.get('dependencies', [])
    required = []
    for dep in dependencies:
        if dep['dependency_type'] == 'required':
            required.append(dep['project_id'])
    return required

def get_mod_by_id(mod_id, user_agent="ModPackBuilder"):
    url = f'https://api.modrinth.com/v2/project/{mod_id}'
    headers = {'User-Agent': user_agent}
    response = requests.get(url, headers=headers)
    if response.status_code == 200:
        return response.json()
    return None

# === Spiget API для плагинов ===
def search_plugins_spiget(query, user_agent="ModPackBuilder"):
    url = f'https://api.spiget.org/v2/search/resources/{query}'
    headers = {'User-Agent': user_agent}
    params = {'size': 100}
    response = requests.get(url, params=params, headers=headers)
    if response.status_code == 200:
        return response.json()
    else:
        messagebox.showerror("Ошибка", f"Spiget API Ошибка: {response.status_code}")
        return []

def get_plugin_info_spiget(plugin_id, user_agent="ModPackBuilder"):
    url = f'https://api.spiget.org/v2/resources/{plugin_id}'
    headers = {'User-Agent': user_agent}
    response = requests.get(url, headers=headers)
    if response.status_code == 200:
        return response.json()
    return None

# === Функция загрузки файла ===
def download_file(url, dest_folder, filename, progress_bar=None, user_agent="ModPackBuilder"):
    local_filename = os.path.join(dest_folder, filename)
    headers = {'User-Agent': user_agent}
    with requests.get(url, stream=True, headers=headers) as r:
        r.raise_for_status()
        total_size = int(r.headers.get('content-length', 0))
        with open(local_filename, 'wb') as f:
            downloaded = 0
            for chunk in r.iter_content(chunk_size=8192):
                if chunk:
                    f.write(chunk)
                    downloaded += len(chunk)
                    if progress_bar and total_size > 0:
                        progress = (downloaded / total_size) * 100
                        progress_bar['value'] = progress
                        progress_bar.update()
    return local_filename

# === GUI ===
class ModPackBuilder:
    def __init__(self, root, config):
        self.root = root
        self.config = config
        self.root.title("ModPack Builder")
        self.root.geometry("1200x800")
        self.root.minsize(800, 600)

        # Применяем стиль ttkbootstrap
        self.style = Style(theme="darkly")  # Попробуйте разные темы: 'darkly', 'flatly', 'cyborg', 'superhero' и т.д.

        # Настройка пользовательских стилей
        self.style.configure('TFrame', background='#1e1e1e')
        self.style.configure('TButton', background='#4caf50', foreground='#ffffff')
        self.style.configure('TLabel', background='#1e1e1e', foreground='#ffffff')
        self.style.configure('Card.TFrame', background='#2b2b2b', relief='raised', borderwidth=1)
        self.style.configure('Hover.TFrame', background='#3a3a3a')

        # Установка шрифтов
        try:
            self.root.option_add("*Font", "Roboto 10")
            self.default_font = font.Font(family="Roboto", size=10)
        except:
            # Если шрифт Roboto не установлен, используйте системный
            self.default_font = font.nametofont("TkDefaultFont")
            self.root.option_add("*Font", self.default_font)

        # Подключение к базе данных
        self.db_connection = sqlite3.connect('user_data.db')
        self.create_tables()

        # Создаем основной PanedWindow для боковой панели и основного контента
        paned = ttk.PanedWindow(self.root, orient=tk.HORIZONTAL)
        paned.pack(fill='both', expand=True)

        # Боковая панель
        self.sidebar = ttk.Frame(paned, width=200, style='TFrame')
        paned.add(self.sidebar, weight=1)

        # Основной контент
        self.content_frame = ttk.Frame(paned, style='TFrame')
        paned.add(self.content_frame, weight=4)

        # Добавление кнопок в боковую панель
        self.add_sidebar_buttons()

        # Создание вкладок внутри основного контента
        self.tab_control = ttk.Notebook(self.content_frame)
        self.tab_control.pack(expand=1, fill="both")

        # Вкладки
        self.mods_tab = ttk.Frame(self.tab_control, style='TFrame')
        self.resourcepacks_tab = ttk.Frame(self.tab_control, style='TFrame')
        self.shaders_tab = ttk.Frame(self.tab_control, style='TFrame')
        self.plugins_tab = ttk.Frame(self.tab_control, style='TFrame')

        self.tab_control.add(self.mods_tab, text='Моды')
        self.tab_control.add(self.resourcepacks_tab, text='Ресурс-паки')
        self.tab_control.add(self.shaders_tab, text='Шейдеры')
        self.tab_control.add(self.plugins_tab, text='Плагины')

        # === Переменные ===
        self.mc_version_var = tk.StringVar(value=config["mc_version"])
        self.modloader_var = tk.StringVar(value=config.get("mod_loader", "Forge"))
        self.description_var = tk.StringVar(value=", ".join(config["default_keywords"]))
        self.build_type_var = tk.StringVar(value="client")

        # Добавляем переменные для категорий модов (добавьте необходимые категории)
        self.mod_categories = {
            "Utility": tk.BooleanVar(),
            "Technology": tk.BooleanVar(),
            "Adventure": tk.BooleanVar(),
            "Magic": tk.BooleanVar(),
            "Exploration": tk.BooleanVar(),
            # Добавьте другие категории по необходимости
        }

        # Добавляем переменные для исключаемых категорий
        self.exclude_categories = {
            "Читерные": tk.BooleanVar(),
            "Экспериментальные": tk.BooleanVar(),
            "Несовместимые": tk.BooleanVar(),
        }

        # Словари для хранения выбранных элементов
        self.selected_mods_info = {}
        self.selected_resourcepacks_info = {}
        self.selected_shaders_info = {}
        self.selected_plugins_info = {}

        # Создаем вкладки
        self.setup_mods_tab()
        self.setup_resourcepacks_tab()
        self.setup_shaders_tab()
        self.setup_plugins_tab()
        self.setup_build_settings()

        # Кнопка скачивания и рекомендации
        bottom_frame = ttk.Frame(self.content_frame, style='TFrame')
        bottom_frame.pack(pady=10)

        download_button = ttk.Button(bottom_frame, text="Скачать сборку", command=self.download_build, style='Success.TButton')
        download_button.pack(side='left', padx=10)

        recommendations_button = ttk.Button(bottom_frame, text="Рекомендуемые моды", command=self.show_recommendations, style='Info.TButton')
        recommendations_button.pack(side='left', padx=10)

        # При изменении размера окна обновляем размеры виджетов
        self.root.bind('<Configure>', self.on_resize)

        # Обработка закрытия окна
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)

    def create_tables(self):
        cursor = self.db_connection.cursor()
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS mod_ratings (
                mod_id TEXT PRIMARY KEY,
                rating INTEGER
            )
        ''')
        self.db_connection.commit()

    def add_sidebar_buttons(self):
        # Загрузка иконок для боковой панели
        icons = {
            "Моды": "icons/mod.png",
            "Ресурс-паки": "icons/resourcepack.png",
            "Шейдеры": "icons/shader.png",
            "Плагины": "icons/plugin.png",
        }

        for text, icon_path in icons.items():
            try:
                icon = ImageTk.PhotoImage(Image.open(icon_path).resize((24,24), Image.ANTIALIAS))
            except Exception as e:
                print(f"Не удалось загрузить иконку {icon_path}: {e}")
                icon = None  # Если иконка не найдена, кнопка будет без изображения
            button = ttk.Button(self.sidebar, text=text, image=icon, compound='left', style='TButton', command=lambda t=text: self.switch_tab(t))
            if icon:
                button.image = icon  # Сохраняем ссылку на изображение
            button.pack(pady=10, padx=10, fill='x')

    def switch_tab(self, tab_name):
        tab_mapping = {
            "Моды": self.mods_tab,
            "Ресурс-паки": self.resourcepacks_tab,
            "Шейдеры": self.shaders_tab,
            "Плагины": self.plugins_tab,
        }
        tab = tab_mapping.get(tab_name)
        if tab:
            self.tab_control.select(tab)

    def setup_mods_tab(self):
        # Верхняя часть вкладки для поиска и фильтров
        search_frame = ttk.Frame(self.mods_tab, style='TFrame')
        search_frame.pack(pady=10, padx=10, fill='x')

        ttk.Label(search_frame, text="Версия Minecraft:", font=('Roboto', 12, 'bold')).grid(row=0, column=0, sticky="w", padx=5, pady=5)
        ttk.Entry(search_frame, textvariable=self.mc_version_var, width=20).grid(row=0, column=1, sticky="ew", padx=5, pady=5)

        ttk.Label(search_frame, text="Mod Loader:", font=('Roboto', 12, 'bold')).grid(row=1, column=0, sticky="w", padx=5, pady=5)
        modloader_menu = ttk.OptionMenu(search_frame, self.modloader_var, self.modloader_var.get(), "Forge", "Fabric", "Quilt", "LiteLoader", "Cauldron")
        modloader_menu.grid(row=1, column=1, sticky="ew", padx=5, pady=5)

        # Настройка сетки для поисковой рамки
        search_frame.columnconfigure(1, weight=1)

        # Фрейм для категорий модов
        categories_frame = ttk.LabelFrame(self.mods_tab, text="Категории модов", style='TLabelFrame')
        categories_frame.pack(pady=10, padx=10, fill='x')

        # Добавление чекбоксов для категорий модов
        col = 0
        for category, var in self.mod_categories.items():
            chk = ttk.Checkbutton(categories_frame, text=category, variable=var, style="TCheckbutton")
            chk.grid(row=0, column=col, sticky="w", padx=5, pady=5)
            col += 1

        # Поле для дополнительных ключевых слов
        ttk.Label(categories_frame, text="Доп. ключевые слова:", font=('Roboto', 12, 'bold')).grid(row=1, column=0, sticky="w", padx=5, pady=5)
        self.additional_keywords_var = tk.StringVar()
        ttk.Entry(categories_frame, textvariable=self.additional_keywords_var).grid(row=1, column=1, sticky="ew", padx=5, pady=5)
        categories_frame.columnconfigure(1, weight=1)

        # Фрейм для исключаемых категорий
        exclude_frame = ttk.LabelFrame(self.mods_tab, text="Исключить категории модов", style='TLabelFrame')
        exclude_frame.pack(pady=10, padx=10, fill='x')

        col = 0
        for category, var in self.exclude_categories.items():
            chk = ttk.Checkbutton(exclude_frame, text=category, variable=var, style="TCheckbutton")
            chk.grid(row=0, column=col, sticky="w", padx=5, pady=5)
            col += 1

        # Кнопка поиска модов
        search_mods_button = ttk.Button(self.mods_tab, text="Поиск модов", command=self.search_mods, style='Primary.TButton')
        search_mods_button.pack(pady=10)

        # Фрейм для отображения карточек модов с прокруткой
        mods_cards_container = ttk.Frame(self.mods_tab, style='TFrame')
        mods_cards_container.pack(fill='both', expand=True, padx=10, pady=10)

        canvas = tk.Canvas(mods_cards_container, background='#1e1e1e')
        scrollbar = ttk.Scrollbar(mods_cards_container, orient="vertical", command=canvas.yview)
        self.mods_cards_frame = ttk.Frame(canvas, style='TFrame')

        self.mods_cards_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(
                scrollregion=canvas.bbox("all")
            )
        )

        canvas.create_window((0, 0), window=self.mods_cards_frame, anchor='nw')
        canvas.configure(yscrollcommand=scrollbar.set)

        canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")

        # Кнопки сохранения и загрузки конфигурации
        config_buttons_frame = ttk.Frame(self.mods_tab, style='TFrame')
        config_buttons_frame.pack(pady=10)

        ttk.Button(config_buttons_frame, text="Сохранить конфигурацию", command=self.save_user_config, style='Secondary.TButton').pack(side='left', padx=5)
        ttk.Button(config_buttons_frame, text="Загрузить конфигурацию", command=self.load_user_config, style='Secondary.TButton').pack(side='left', padx=5)

        # Кнопка для оценки модов
        ttk.Button(config_buttons_frame, text="Оценить выбранные моды", command=self.rate_selected_mods, style='Secondary.TButton').pack(side='left', padx=5)
        ttk.Button(config_buttons_frame, text="Проверить совместимость", command=self.check_compatibility, style='Secondary.TButton').pack(side='left', padx=5)

        # Сортировка
        sort_frame = ttk.Frame(self.mods_tab, style='TFrame')
        sort_frame.pack(pady=10, padx=10, fill='x')

        ttk.Label(sort_frame, text="Сортировать по:", font=('Roboto', 12, 'bold')).pack(side='left', padx=5)
        self.sort_by_var = tk.StringVar(value="Релевантности")
        sort_menu = ttk.OptionMenu(sort_frame, self.sort_by_var, self.sort_by_var.get(), "Релевантности", "Скачиваниям", "Подписчикам")
        sort_menu.pack(side='left', padx=5)

    def create_mod_card(self, parent, mod_info):
        card = ttk.Frame(parent, style='Card.TFrame')
        card.pack(pady=10, fill='x', padx=10)

        # Добавление изображения
        try:
            mod_image = ImageTk.PhotoImage(Image.open(mod_info['image_path']).resize((64,64), Image.ANTIALIAS))
        except Exception as e:
            print(f"Не удалось загрузить изображение {mod_info['image_path']}: {e}")
            # Если изображение не найдено, используем плейсхолдер
            mod_image = ImageTk.PhotoImage(Image.new('RGB', (64,64), color='#555555'))

        image_label = ttk.Label(card, image=mod_image, style='Card.TFrame')
        image_label.image = mod_image
        image_label.pack(side='left', padx=10, pady=10)

        # Информация о моде
        info_frame = ttk.Frame(card, style='Card.TFrame')
        info_frame.pack(side='left', fill='both', expand=True)

        title_label = ttk.Label(info_frame, text=mod_info['title'], font=('Roboto', 12, 'bold'), foreground='#ffffff', background='#2b2b2b')
        title_label.pack(anchor='w')

        desc_label = ttk.Label(info_frame, text=mod_info['description'], font=('Roboto', 10), foreground='#b3b3b3', background='#2b2b2b', wraplength=600)
        desc_label.pack(anchor='w')

        # Кнопки действий
        actions_frame = ttk.Frame(card, style='Card.TFrame')
        actions_frame.pack(side='right', padx=10, pady=10)

        try:
            like_icon = ImageTk.PhotoImage(Image.open('icons/like.png').resize((24,24), Image.ANTIALIAS))
            download_icon = ImageTk.PhotoImage(Image.open('icons/download.png').resize((24,24), Image.ANTIALIAS))
        except Exception as e:
            print(f"Не удалось загрузить иконки действий: {e}")
            like_icon = None
            download_icon = None

        like_button = ttk.Button(actions_frame, image=like_icon, style='TButton')
        if like_icon:
            like_button.image = like_icon
        like_button.pack(side='left', padx=5)

        download_button = ttk.Button(actions_frame, image=download_icon, style='TButton', command=lambda mod_id=mod_info['project_id']: self.download_single_mod(mod_id))
        if download_icon:
            download_button.image = download_icon
        download_button.pack(side='left', padx=5)

        # Добавление эффектов наведения
        card.bind("<Enter>", lambda e: card.configure(style='Hover.TFrame'))
        card.bind("<Leave>", lambda e: card.configure(style='Card.TFrame'))

    def download_single_mod(self, mod_id):
        if mod_id in self.selected_mods_info:
            mod_info = self.selected_mods_info[mod_id]
            version = get_latest_compatible_version_modrinth(mod_id, self.config["mc_version"], self.config["mod_loader"], self.config["user_agent"])
            if version:
                files = [file for file in version['files'] if file['primary']]
                if files:
                    file_info = files[0]
                    filename = file_info['filename']
                    url = file_info['url']
                    dest_folder = os.path.join(self.config["download_folder"], "mods")
                    if not os.path.exists(dest_folder):
                        os.makedirs(dest_folder)
                    progress_window = Toplevel(self.root)
                    progress_window.title(f"Скачивание {mod_info['title']}")

                    progress_bar = ttk.Progressbar(progress_window, orient="horizontal", length=300, mode="determinate")
                    progress_bar.pack(pady=20, padx=20)

                    def download():
                        try:
                            download_file(url, dest_folder, filename, progress_bar, self.config["user_agent"])
                            messagebox.showinfo("Успех", f"Мод '{mod_info['title']}' успешно скачан!")
                        except Exception as e:
                            messagebox.showerror("Ошибка", f"Не удалось скачать мод '{mod_info['title']}': {e}")
                        finally:
                            progress_window.destroy()

                    Thread(target=download).start()
                else:
                    messagebox.showinfo("Информация", f"Нет файлов для мода {mod_info['title']}.")
            else:
                messagebox.showerror("Ошибка", f"Не удалось найти совместимую версию для мода {mod_info['title']}.")

    def setup_resourcepacks_tab(self):
        # Верхняя часть вкладки для поиска ресурс-паков
        search_frame = ttk.Frame(self.resourcepacks_tab, style='TFrame')
        search_frame.pack(pady=10, padx=10, fill='x')

        ttk.Label(search_frame, text="Описание (ключевые слова):", font=('Roboto', 12, 'bold')).grid(row=0, column=0, sticky="w", padx=5, pady=5)
        ttk.Entry(search_frame, textvariable=self.resourcepack_description_var).grid(row=0, column=1, sticky="ew", padx=5, pady=5)

        # Кнопка поиска ресурс-паков
        search_resourcepacks_button = ttk.Button(search_frame, text="Поиск ресурс-паков", command=self.search_resourcepacks, style='Primary.TButton')
        search_resourcepacks_button.grid(row=1, column=0, columnspan=2, pady=10)

        # Рамка для карточек ресурс-паков с прокруткой
        resourcepacks_cards_container = ttk.Frame(self.resourcepacks_tab, style='TFrame')
        resourcepacks_cards_container.pack(fill='both', expand=True, padx=10, pady=10)

        canvas = tk.Canvas(resourcepacks_cards_container, background='#1e1e1e')
        scrollbar = ttk.Scrollbar(resourcepacks_cards_container, orient="vertical", command=canvas.yview)
        self.resourcepacks_cards_frame = ttk.Frame(canvas, style='TFrame')

        self.resourcepacks_cards_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(
                scrollregion=canvas.bbox("all")
            )
        )

        canvas.create_window((0, 0), window=self.resourcepacks_cards_frame, anchor='nw')
        canvas.configure(yscrollcommand=scrollbar.set)

        canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")

    def setup_shaders_tab(self):
        # Верхняя часть вкладки для поиска шейдеров
        search_frame = ttk.Frame(self.shaders_tab, style='TFrame')
        search_frame.pack(pady=10, padx=10, fill='x')

        ttk.Label(search_frame, text="Описание (ключевые слова):", font=('Roboto', 12, 'bold')).grid(row=0, column=0, sticky="w", padx=5, pady=5)
        ttk.Entry(search_frame, textvariable=self.shader_description_var).grid(row=0, column=1, sticky="ew", padx=5, pady=5)

        # Кнопка поиска шейдеров
        search_shaders_button = ttk.Button(search_frame, text="Поиск шейдеров", command=self.search_shaders, style='Primary.TButton')
        search_shaders_button.grid(row=1, column=0, columnspan=2, pady=10)

        # Рамка для карточек шейдеров с прокруткой
        shaders_cards_container = ttk.Frame(self.shaders_tab, style='TFrame')
        shaders_cards_container.pack(fill='both', expand=True, padx=10, pady=10)

        canvas = tk.Canvas(shaders_cards_container, background='#1e1e1e')
        scrollbar = ttk.Scrollbar(shaders_cards_container, orient="vertical", command=canvas.yview)
        self.shaders_cards_frame = ttk.Frame(canvas, style='TFrame')

        self.shaders_cards_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(
                scrollregion=canvas.bbox("all")
            )
        )

        canvas.create_window((0, 0), window=self.shaders_cards_frame, anchor='nw')
        canvas.configure(yscrollcommand=scrollbar.set)

        canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")

    def setup_plugins_tab(self):
        # Верхняя часть вкладки для поиска плагинов
        search_frame = ttk.Frame(self.plugins_tab, style='TFrame')
        search_frame.pack(pady=10, padx=10, fill='x')

        ttk.Label(search_frame, text="Поиск плагинов:", font=('Roboto', 12, 'bold')).grid(row=0, column=0, sticky="w", padx=5, pady=5)
        ttk.Entry(search_frame, textvariable=self.plugin_description_var).grid(row=0, column=1, sticky="ew", padx=5, pady=5)

        # Кнопка поиска плагинов
        search_plugins_button = ttk.Button(search_frame, text="Поиск плагинов", command=self.search_plugins, style='Primary.TButton')
        search_plugins_button.grid(row=1, column=0, columnspan=2, pady=10)

        # Рамка для карточек плагинов с прокруткой
        plugins_cards_container = ttk.Frame(self.plugins_tab, style='TFrame')
        plugins_cards_container.pack(fill='both', expand=True, padx=10, pady=10)

        canvas = tk.Canvas(plugins_cards_container, background='#1e1e1e')
        scrollbar = ttk.Scrollbar(plugins_cards_container, orient="vertical", command=canvas.yview)
        self.plugins_cards_frame = ttk.Frame(canvas, style='TFrame')

        self.plugins_cards_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(
                scrollregion=canvas.bbox("all")
            )
        )

        canvas.create_window((0, 0), window=self.plugins_cards_frame, anchor='nw')
        canvas.configure(yscrollcommand=scrollbar.set)

        canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")

    def setup_build_settings(self):
        settings_frame = ttk.LabelFrame(self.content_frame, text="Настройки сборки", style='TLabelFrame')
        settings_frame.pack(pady=10, padx=10, fill='x')

        ttk.Label(settings_frame, text="Тип сборки:", font=('Roboto', 12, 'bold')).grid(row=0, column=0, sticky="w", padx=5, pady=5)
        build_type_menu = ttk.OptionMenu(settings_frame, self.build_type_var, self.build_type_var.get(), "client", "server", "both")
        build_type_menu.grid(row=0, column=1, sticky="w", padx=5, pady=5)

    def on_resize(self, event):
        # Обновляем размеры виджетов при изменении размера окна
        self.content_frame.update_idletasks()

    def on_closing(self):
        # Закрываем соединение с базой данных
        self.db_connection.close()
        self.root.destroy()

    # === Функции для вкладки модов ===
    def search_mods(self):
        # Получаем выбранные категории
        selected_categories = [category for category, var in self.mod_categories.items() if var.get()]
        categories_query = " ".join(selected_categories)

        # Получаем дополнительные ключевые слова
        additional_keywords = self.additional_keywords_var.get()

        # Формируем общий запрос
        description = f"{categories_query} {additional_keywords}".strip()

        mc_version = self.mc_version_var.get()
        modloader = self.modloader_var.get()

        self.config["mc_version"] = mc_version
        self.config["mod_loader"] = modloader
        self.config["default_keywords"] = description.split(", ")
        save_config(self.config)

        # Очистка прошлых карточек
        for widget in self.mods_cards_frame.winfo_children():
            widget.destroy()

        self.mods = []

        mods = search_projects_modrinth(description, "mod", mc_version, modloader, self.config["user_agent"])

        # Получаем исключаемые категории
        excluded_categories = [category for category, var in self.exclude_categories.items() if var.get()]

        # Если выбраны категории для исключения, получаем их идентификаторы
        excluded_category_ids = []
        if excluded_categories:
            # Получаем список всех категорий с их идентификаторами
            all_categories = self.get_all_categories()
            for name in excluded_categories:
                cat_id = self.get_category_id_by_name(name, all_categories)
                if cat_id:
                    excluded_category_ids.append(cat_id)

        sort_by = self.sort_by_var.get()
        if sort_by == "Скачиваниям":
            mods.sort(key=lambda m: m.get('downloads', 0), reverse=True)
        elif sort_by == "Подписчикам":
            mods.sort(key=lambda m: m.get('follows', 0), reverse=True)
        # Если "Релевантности", оставляем порядок по умолчанию

        for mod in mods:
            # Проверяем, не входит ли мод в исключаемые категории
            if excluded_category_ids:
                if set(mod.get('categories', [])).intersection(excluded_category_ids):
                    continue  # Пропускаем мод
            self.mods.append({"source": "Modrinth", "data": mod})
            # Добавляем карточку для мода
            mod_info = {
                'title': mod['title'],
                'description': mod['description'][:200] + '...' if len(mod['description']) > 200 else mod['description'],
                'image_path': 'icons/mod_placeholder.png'  # Замените на реальный путь или используйте placeholder
            }
            self.selected_mods_info[mod['project_id']] = mod
            self.create_mod_card(self.mods_cards_frame, mod_info)

    def get_all_categories(self):
        url = 'https://api.modrinth.com/v2/tag/category'
        headers = {'User-Agent': self.config["user_agent"]}
        response = requests.get(url, headers=headers)
        if response.status_code == 200:
            return response.json()
        else:
            return []

    def get_category_id_by_name(self, name, categories):
        for category in categories:
            if category['name'].lower() == name.lower():
                return category['slug']
        return None

    def show_mod_details(self, event):
        selection = self.mods_list.curselection()
        if selection:
            index = selection[0]
            mod_entry = self.mods[index]
            mod = mod_entry['data']
            description = mod.get('description', 'Нет описания')
            downloads = mod.get('downloads', 0)
            followers = mod.get('follows', 0)
            # Очищаем и заполняем поле с деталями
            self.mod_details_text.delete('1.0', tk.END)
            self.mod_details_text.insert(tk.END, f"Название: {mod['title']}\n")
            self.mod_details_text.insert(tk.END, f"Скачивания: {downloads}\n")
            self.mod_details_text.insert(tk.END, f"Подписчики: {followers}\n")
            self.mod_details_text.insert(tk.END, f"\n{description}")

    def check_compatibility(self):
        # Получаем список выбранных модов из карточек
        if not self.selected_mods_info:
            messagebox.showwarning("Предупреждение", "Добавьте хотя бы один мод для проверки.")
            return

        mc_version = self.config["mc_version"]
        modloader = self.config["mod_loader"].lower()

        incompatible_mods = []
        mod_map = {}

        # Получение информации о выбранных модах и их версиях
        for mod_id, mod in self.selected_mods_info.items():
            mod_title = mod['title']
            version = get_latest_compatible_version_modrinth(mod_id, mc_version, modloader, self.config["user_agent"])
            if version:
                mod_map[mod_id] = {
                    'title': mod_title,
                    'version': version,
                    'dependencies': get_mod_dependencies(version),
                }
            else:
                incompatible_mods.append(mod_title)

        if incompatible_mods:
            messagebox.showerror("Несовместимые моды", f"Следующие моды не совместимы с версией {mc_version} и загрузчиком {modloader.capitalize()}:\n" + "\n".join(incompatible_mods))
            return

        # Проверка зависимостей и автоматическое добавление недостающих
        missing_dependencies = []
        processed_mods = set()
        mods_to_process = list(mod_map.keys())

        while mods_to_process:
            current_mods = mods_to_process
            mods_to_process = []
            for mod_id in current_mods:
                if mod_id in processed_mods:
                    continue
                mod_info = mod_map[mod_id]
                processed_mods.add(mod_id)
                for dep_id in mod_info['dependencies']:
                    if dep_id not in mod_map:
                        dep_project = get_mod_by_id(dep_id, self.config["user_agent"])
                        if dep_project:
                            dep_title = dep_project['title']
                            dep_version = get_latest_compatible_version_modrinth(dep_id, mc_version, modloader, self.config["user_agent"])
                            if dep_version:
                                # Добавляем зависимость в список модов
                                mod_map[dep_id] = {
                                    'title': dep_title,
                                    'version': dep_version,
                                    'dependencies': get_mod_dependencies(dep_version),
                                }
                                self.selected_mods_info[dep_id] = dep_project
                                # Добавляем карточку для зависимости
                                mod_info_dep = {
                                    'title': dep_title,
                                    'description': dep_project['description'][:200] + '...' if len(dep_project['description']) > 200 else dep_project['description'],
                                    'image_path': 'icons/mod_placeholder.png'  # Замените на реальный путь или используйте placeholder
                                }
                                self.create_mod_card(self.mods_cards_frame, mod_info_dep)
                                # Добавляем в список для дальнейшей обработки зависимостей этой зависимости
                                mods_to_process.append(dep_id)
                            else:
                                missing_dependencies.append(dep_title)
                        else:
                            missing_dependencies.append(dep_id)

        if missing_dependencies:
            messagebox.showwarning("Отсутствующие зависимости", f"Следующие зависимости отсутствуют или несовместимы:\n" + "\n".join(set(missing_dependencies)))
            return

        # Сохраняем информацию о выбранных модах и их зависимостях для дальнейшего использования при скачивании
        self.selected_mods_info = mod_map

        messagebox.showinfo("Совместимость", "Выбранные моды совместимы между собой и с текущей версией Minecraft. Все необходимые зависимости будут скачаны.")

    # Метод для оценки модов
    def rate_selected_mods(self):
        if not self.selected_mods_info:
            messagebox.showwarning("Предупреждение", "Выберите хотя бы один мод для оценки.")
            return

        for mod_id, mod in self.selected_mods_info.items():
            mod_title = mod['title']

            # Окно для ввода оценки
            rating_window = Toplevel(self.root)
            rating_window.title(f"Оценка мода {mod_title}")
            rating_window.geometry("300x150")

            ttk.Label(rating_window, text=f"Оцените мод '{mod_title}' (1-5):", font=('Roboto', 12, 'bold')).pack(pady=10)

            rating_var = tk.IntVar()
            ttk.Spinbox(rating_window, from_=1, to=5, textvariable=rating_var, width=5, font=('Roboto', 12)).pack(pady=5)

            ttk.Button(rating_window, text="Сохранить оценку", command=lambda mod_id=mod_id, var=rating_var, win=rating_window: self.save_mod_rating(mod_id, var.get(), win), style='Success.TButton').pack(pady=10)

    # Метод для сохранения оценки мода
    def save_mod_rating(self, mod_id, rating, window):
        if rating < 1 or rating > 5:
            messagebox.showwarning("Предупреждение", "Оценка должна быть от 1 до 5.")
            return

        # Сохраняем оценку в локальной базе данных
        self.save_rating_to_db(mod_id, rating)
        messagebox.showinfo("Спасибо!", "Ваша оценка сохранена.")
        window.destroy()

    def save_rating_to_db(self, mod_id, rating):
        cursor = self.db_connection.cursor()
        cursor.execute('''
            INSERT OR REPLACE INTO mod_ratings (mod_id, rating)
            VALUES (?, ?)
        ''', (mod_id, rating))
        self.db_connection.commit()

    # === Функции для вкладки ресурс-паков ===
    def search_resourcepacks(self):
        description = self.resourcepack_description_var.get()

        # Очистка прошлых карточек
        for widget in self.resourcepacks_cards_frame.winfo_children():
            widget.destroy()

        self.resourcepacks = []

        resourcepacks = search_projects_modrinth(description, "resourcepack", user_agent=self.config["user_agent"])
        for rp in resourcepacks:
            self.resourcepacks.append({"source": "Modrinth", "data": rp})
            # Добавляем карточку ресурс-пака
            rp_info = {
                'title': rp['title'],
                'description': rp['description'][:200] + '...' if len(rp['description']) > 200 else rp['description'],
                'image_path': 'icons/resourcepack_placeholder.png'  # Замените на реальный путь или используйте placeholder
            }
            self.selected_resourcepacks_info[rp['project_id']] = rp
            self.create_resourcepack_card(self.resourcepacks_cards_frame, rp_info)

    def create_resourcepack_card(self, parent, rp_info):
        card = ttk.Frame(parent, style='Card.TFrame')
        card.pack(pady=10, fill='x', padx=10)

        # Добавление изображения
        try:
            rp_image = ImageTk.PhotoImage(Image.open(rp_info['image_path']).resize((64,64), Image.ANTIALIAS))
        except Exception as e:
            print(f"Не удалось загрузить изображение {rp_info['image_path']}: {e}")
            # Если изображение не найдено, используем плейсхолдер
            rp_image = ImageTk.PhotoImage(Image.new('RGB', (64,64), color='#555555'))

        image_label = ttk.Label(card, image=rp_image, style='Card.TFrame')
        image_label.image = rp_image
        image_label.pack(side='left', padx=10, pady=10)

        # Информация о ресурс-паке
        info_frame = ttk.Frame(card, style='Card.TFrame')
        info_frame.pack(side='left', fill='both', expand=True)

        title_label = ttk.Label(info_frame, text=rp_info['title'], font=('Roboto', 12, 'bold'), foreground='#ffffff', background='#2b2b2b')
        title_label.pack(anchor='w')

        desc_label = ttk.Label(info_frame, text=rp_info['description'], font=('Roboto', 10), foreground='#b3b3b3', background='#2b2b2b', wraplength=600)
        desc_label.pack(anchor='w')

        # Кнопки действий
        actions_frame = ttk.Frame(card, style='Card.TFrame')
        actions_frame.pack(side='right', padx=10, pady=10)

        try:
            download_icon = ImageTk.PhotoImage(Image.open('icons/download.png').resize((24,24), Image.ANTIALIAS))
        except Exception as e:
            print(f"Не удалось загрузить иконку download.png: {e}")
            download_icon = None

        download_button = ttk.Button(actions_frame, image=download_icon, style='TButton', command=lambda rp_id=rp_info['title']: self.download_single_resourcepack(rp_id))
        if download_icon:
            download_button.image = download_icon
        download_button.pack(side='left', padx=5)

        # Добавление эффектов наведения
        card.bind("<Enter>", lambda e: card.configure(style='Hover.TFrame'))
        card.bind("<Leave>", lambda e: card.configure(style='Card.TFrame'))

    def download_single_resourcepack(self, rp_id):
        if rp_id in self.selected_resourcepacks_info:
            rp = self.selected_resourcepacks_info[rp_id]
            version = get_latest_compatible_version_modrinth(rp_id, self.config["mc_version"], user_agent=self.config["user_agent"])
            if version:
                files = version['files']
                if files:
                    file_info = files[0]
                    filename = file_info['filename']
                    url = file_info['url']
                    dest_folder = os.path.join(self.config["download_folder"], "resourcepacks")
                    if not os.path.exists(dest_folder):
                        os.makedirs(dest_folder)
                    progress_window = Toplevel(self.root)
                    progress_window.title(f"Скачивание {rp['title']}")

                    progress_bar = ttk.Progressbar(progress_window, orient="horizontal", length=300, mode="determinate")
                    progress_bar.pack(pady=20, padx=20)

                    def download():
                        try:
                            download_file(url, dest_folder, filename, progress_bar, self.config["user_agent"])
                            messagebox.showinfo("Успех", f"Ресурс-пак '{rp['title']}' успешно скачан!")
                        except Exception as e:
                            messagebox.showerror("Ошибка", f"Не удалось скачать ресурс-пак '{rp['title']}': {e}")
                        finally:
                            progress_window.destroy()

                    Thread(target=download).start()
                else:
                    messagebox.showinfo("Информация", f"Нет файлов для ресурс-пака {rp['title']}.")
            else:
                messagebox.showerror("Ошибка", f"Не удалось найти последнюю версию для ресурс-пака {rp['title']}.")

    # === Функции для вкладки шейдеров ===
    def search_shaders(self):
        description = self.shader_description_var.get()

        # Очистка прошлых карточек
        for widget in self.shaders_cards_frame.winfo_children():
            widget.destroy()

        self.shaders = []

        shaders = search_projects_modrinth(description, "shader", user_agent=self.config["user_agent"])
        for shader in shaders:
            self.shaders.append({"source": "Modrinth", "data": shader})
            # Добавляем карточку шейдера
            shader_info = {
                'title': shader['title'],
                'description': shader['description'][:200] + '...' if len(shader['description']) > 200 else shader['description'],
                'image_path': 'icons/shader_placeholder.png'  # Замените на реальный путь или используйте placeholder
            }
            self.selected_shaders_info[shader['project_id']] = shader
            self.create_shader_card(self.shaders_cards_frame, shader_info)

    def create_shader_card(self, parent, shader_info):
        card = ttk.Frame(parent, style='Card.TFrame')
        card.pack(pady=10, fill='x', padx=10)

        # Добавление изображения
        try:
            shader_image = ImageTk.PhotoImage(Image.open(shader_info['image_path']).resize((64,64), Image.ANTIALIAS))
        except Exception as e:
            print(f"Не удалось загрузить изображение {shader_info['image_path']}: {e}")
            # Если изображение не найдено, используем плейсхолдер
            shader_image = ImageTk.PhotoImage(Image.new('RGB', (64,64), color='#555555'))

        image_label = ttk.Label(card, image=shader_image, style='Card.TFrame')
        image_label.image = shader_image
        image_label.pack(side='left', padx=10, pady=10)

        # Информация о шейдере
        info_frame = ttk.Frame(card, style='Card.TFrame')
        info_frame.pack(side='left', fill='both', expand=True)

        title_label = ttk.Label(info_frame, text=shader_info['title'], font=('Roboto', 12, 'bold'), foreground='#ffffff', background='#2b2b2b')
        title_label.pack(anchor='w')

        desc_label = ttk.Label(info_frame, text=shader_info['description'], font=('Roboto', 10), foreground='#b3b3b3', background='#2b2b2b', wraplength=600)
        desc_label.pack(anchor='w')

        # Кнопки действий
        actions_frame = ttk.Frame(card, style='Card.TFrame')
        actions_frame.pack(side='right', padx=10, pady=10)

        try:
            download_icon = ImageTk.PhotoImage(Image.open('icons/download.png').resize((24,24), Image.ANTIALIAS))
        except Exception as e:
            print(f"Не удалось загрузить иконку download.png: {e}")
            download_icon = None

        download_button = ttk.Button(actions_frame, image=download_icon, style='TButton', command=lambda shader_id=shader_info['title']: self.download_single_shader(shader_id))
        if download_icon:
            download_button.image = download_icon
        download_button.pack(side='left', padx=5)

        # Добавление эффектов наведения
        card.bind("<Enter>", lambda e: card.configure(style='Hover.TFrame'))
        card.bind("<Leave>", lambda e: card.configure(style='Card.TFrame'))

    def download_single_shader(self, shader_id):
        if shader_id in self.selected_shaders_info:
            shader = self.selected_shaders_info[shader_id]
            version = get_latest_compatible_version_modrinth(shader_id, self.config["mc_version"], user_agent=self.config["user_agent"])
            if version:
                files = version['files']
                if files:
                    file_info = files[0]
                    filename = file_info['filename']
                    url = file_info['url']
                    dest_folder = os.path.join(self.config["download_folder"], "shaderpacks")
                    if not os.path.exists(dest_folder):
                        os.makedirs(dest_folder)
                    progress_window = Toplevel(self.root)
                    progress_window.title(f"Скачивание {shader['title']}")

                    progress_bar = ttk.Progressbar(progress_window, orient="horizontal", length=300, mode="determinate")
                    progress_bar.pack(pady=20, padx=20)

                    def download():
                        try:
                            download_file(url, dest_folder, filename, progress_bar, self.config["user_agent"])
                            messagebox.showinfo("Успех", f"Шейдер '{shader['title']}' успешно скачан!")
                        except Exception as e:
                            messagebox.showerror("Ошибка", f"Не удалось скачать шейдер '{shader['title']}': {e}")
                        finally:
                            progress_window.destroy()

                    Thread(target=download).start()
                else:
                    messagebox.showinfo("Информация", f"Нет файлов для шейдера {shader['title']}.")
            else:
                messagebox.showerror("Ошибка", f"Не удалось найти последнюю версию для шейдера {shader['title']}.")

    # === Функции для вкладки плагинов ===
    def search_plugins(self):
        query = self.plugin_description_var.get()

        # Очистка прошлых карточек
        for widget in self.plugins_cards_frame.winfo_children():
            widget.destroy()

        self.plugins = []

        plugins = search_plugins_spiget(query, self.config["user_agent"])
        for plugin in plugins:
            self.plugins.append(plugin)
            # Добавляем карточку плагина
            plugin_info = {
                'title': plugin['name'],
                'description': plugin.get('tag', 'Без описания')[:200] + '...' if len(plugin.get('tag', 'Без описания')) > 200 else plugin.get('tag', 'Без описания'),
                'image_path': 'icons/plugin_placeholder.png'  # Замените на реальный путь или используйте placeholder
            }
            self.selected_plugins_info[str(plugin['id'])] = plugin
            self.create_plugin_card(self.plugins_cards_frame, plugin_info)

    def create_plugin_card(self, parent, plugin_info):
        card = ttk.Frame(parent, style='Card.TFrame')
        card.pack(pady=10, fill='x', padx=10)

        # Добавление иконки плагина
        try:
            plugin_image = ImageTk.PhotoImage(Image.open(plugin_info['image_path']).resize((64,64), Image.ANTIALIAS))
        except Exception as e:
            print(f"Не удалось загрузить изображение {plugin_info['image_path']}: {e}")
            # Если изображение не найдено, используем плейсхолдер
            plugin_image = ImageTk.PhotoImage(Image.new('RGB', (64,64), color='#555555'))

        image_label = ttk.Label(card, image=plugin_image, style='Card.TFrame')
        image_label.image = plugin_image
        image_label.pack(side='left', padx=10, pady=10)

        # Информация о плагине
        info_frame = ttk.Frame(card, style='Card.TFrame')
        info_frame.pack(side='left', fill='both', expand=True)

        title_label = ttk.Label(info_frame, text=plugin_info['title'], font=('Roboto', 12, 'bold'), foreground='#ffffff', background='#2b2b2b')
        title_label.pack(anchor='w')

        desc_label = ttk.Label(info_frame, text=plugin_info['description'], font=('Roboto', 10), foreground='#b3b3b3', background='#2b2b2b', wraplength=600)
        desc_label.pack(anchor='w')

        # Кнопки действий
        actions_frame = ttk.Frame(card, style='Card.TFrame')
        actions_frame.pack(side='right', padx=10, pady=10)

        try:
            download_icon = ImageTk.PhotoImage(Image.open('icons/download.png').resize((24,24), Image.ANTIALIAS))
        except Exception as e:
            print(f"Не удалось загрузить иконку download.png: {e}")
            download_icon = None

        download_button = ttk.Button(actions_frame, image=download_icon, style='TButton', command=lambda plugin_id=plugin_info['title']: self.download_single_plugin(plugin_id))
        if download_icon:
            download_button.image = download_icon
        download_button.pack(side='left', padx=5)

        # Добавление эффектов наведения
        card.bind("<Enter>", lambda e: card.configure(style='Hover.TFrame'))
        card.bind("<Leave>", lambda e: card.configure(style='Card.TFrame'))

    def download_single_plugin(self, plugin_id):
        # Найти плагин по названию
        plugin = None
        for pid, p in self.selected_plugins_info.items():
            if p['name'] == plugin_id:
                plugin = p
                break

        if plugin:
            plugin_id_str = str(plugin['id'])
            url = f'https://api.spiget.org/v2/resources/{plugin_id_str}/download'
            filename = f"{plugin['name']}.jar"
            dest_folder = os.path.join(self.config["download_folder"], "plugins")
            if not os.path.exists(dest_folder):
                os.makedirs(dest_folder)
            progress_window = Toplevel(self.root)
            progress_window.title(f"Скачивание {plugin['name']}")

            progress_bar = ttk.Progressbar(progress_window, orient="horizontal", length=300, mode="determinate")
            progress_bar.pack(pady=20, padx=20)

            def download():
                try:
                    download_file(url, dest_folder, filename, progress_bar, self.config["user_agent"])
                    messagebox.showinfo("Успех", f"Плагин '{plugin['name']}' успешно скачан!")
                except Exception as e:
                    messagebox.showerror("Ошибка", f"Не удалось скачать плагин '{plugin['name']}': {e}")
                finally:
                    progress_window.destroy()

            Thread(target=download).start()
        else:
            messagebox.showerror("Ошибка", f"Плагин '{plugin_id}' не найден.")

    # === Функции для загрузки и отображения карточек плагинов ===
    def create_plugin_card(self, parent, plugin_info):
        card = ttk.Frame(parent, style='Card.TFrame')
        card.pack(pady=10, fill='x', padx=10)

        # Добавление изображения
        try:
            plugin_image = ImageTk.PhotoImage(Image.open(plugin_info['image_path']).resize((64,64), Image.ANTIALIAS))
        except Exception as e:
            print(f"Не удалось загрузить изображение {plugin_info['image_path']}: {e}")
            # Если изображение не найдено, используем плейсхолдер
            plugin_image = ImageTk.PhotoImage(Image.new('RGB', (64,64), color='#555555'))

        image_label = ttk.Label(card, image=plugin_image, style='Card.TFrame')
        image_label.image = plugin_image
        image_label.pack(side='left', padx=10, pady=10)

        # Информация о плагине
        info_frame = ttk.Frame(card, style='Card.TFrame')
        info_frame.pack(side='left', fill='both', expand=True)

        title_label = ttk.Label(info_frame, text=plugin_info['title'], font=('Roboto', 12, 'bold'), foreground='#ffffff', background='#2b2b2b')
        title_label.pack(anchor='w')

        desc_label = ttk.Label(info_frame, text=plugin_info['description'], font=('Roboto', 10), foreground='#b3b3b3', background='#2b2b2b', wraplength=600)
        desc_label.pack(anchor='w')

        # Кнопки действий
        actions_frame = ttk.Frame(card, style='Card.TFrame')
        actions_frame.pack(side='right', padx=10, pady=10)

        try:
            download_icon = ImageTk.PhotoImage(Image.open('icons/download.png').resize((24,24), Image.ANTIALIAS))
        except Exception as e:
            print(f"Не удалось загрузить иконку download.png: {e}")
            download_icon = None

        download_button = ttk.Button(actions_frame, image=download_icon, style='TButton', command=lambda plugin_id=plugin_info['title']: self.download_single_plugin(plugin_id))
        if download_icon:
            download_button.image = download_icon
        download_button.pack(side='left', padx=5)

        # Добавление эффектов наведения
        card.bind("<Enter>", lambda e: card.configure(style='Hover.TFrame'))
        card.bind("<Leave>", lambda e: card.configure(style='Card.TFrame'))

    # === Функции для вкладки модов ===
    def add_mod_to_modpack(self, mod_id):
        if mod_id in self.selected_mods_info:
            mod = self.selected_mods_info[mod_id]
            mod_title = mod['title']
            # Добавляем мод в дерево модпака
            if not hasattr(self, 'modpack_tree'):
                # Если дерево не создано, создайте его
                self.modpack_tree = ttk.Treeview(self.mods_tab)
                self.modpack_tree.pack()
            if not self.modpack_tree.exists(mod_id):
                self.modpack_tree.insert('', 'end', iid=mod_id, text=mod_title)
                messagebox.showinfo("Мод добавлен", f"Мод '{mod_title}' добавлен в модпак.")
            else:
                messagebox.showwarning("Внимание", f"Мод '{mod_title}' уже добавлен в модпак.")

    def download_build(self):
        build_type = self.build_type_var.get()

        if build_type in ["client", "both"]:
            self.download_client_build()

        if build_type in ["server", "both"]:
            self.download_server_build()

    def download_client_build(self):
        if not os.path.exists(self.config["download_folder"]):
            os.makedirs(self.config["download_folder"])

        self.progress_window = Toplevel(self.root)
        self.progress_window.title("Прогресс скачивания клиента")
        self.progress_window.geometry("400x100")

        progress_bar = ttk.Progressbar(self.progress_window, orient="horizontal", length=300, mode="determinate")
        progress_bar.pack(pady=20)

        def download():
            try:
                # Скачивание модов
                mod_items = list(self.selected_mods_info.items())
                total_mods = len(mod_items)
                for idx, (mod_id, mod_info) in enumerate(mod_items):
                    mod_title = mod_info['title']
                    version = get_latest_compatible_version_modrinth(mod_id, self.config["mc_version"], self.config["mod_loader"], self.config["user_agent"])
                    if version:
                        files = [file for file in version['files'] if file['primary']]
                        if files:
                            file_info = files[0]
                            filename = file_info['filename']
                            url = file_info['url']
                            dest_folder = os.path.join(self.config["download_folder"], "mods")
                            if not os.path.exists(dest_folder):
                                os.makedirs(dest_folder)
                            download_file(url, dest_folder, filename, progress_bar, self.config["user_agent"])
                        else:
                            messagebox.showinfo("Информация", f"Нет файлов для мода {mod_title}.")
                    else:
                        messagebox.showwarning("Предупреждение", f"Не удалось найти совместимую версию для мода {mod_title}.")

                    progress = ((idx + 1) / total_mods) * 100
                    progress_bar['value'] = progress
                    self.progress_window.update()

                # Скачивание ресурс-паков
                resourcepack_items = list(self.selected_resourcepacks_info.items())
                total_rps = len(resourcepack_items)
                for idx, (rp_id, rp) in enumerate(resourcepack_items):
                    version = get_latest_compatible_version_modrinth(rp_id, user_agent=self.config["user_agent"])
                    if version:
                        files = version['files']
                        if files:
                            file_info = files[0]
                            filename = file_info['filename']
                            url = file_info['url']
                            dest_folder = os.path.join(self.config["download_folder"], "resourcepacks")
                            if not os.path.exists(dest_folder):
                                os.makedirs(dest_folder)
                            download_file(url, dest_folder, filename, progress_bar, self.config["user_agent"])
                    progress = 100 * (idx + 1) / total_rps if total_rps else 100
                    progress_bar['value'] = progress
                    self.progress_window.update()

                # Скачивание шейдеров
                shader_items = list(self.selected_shaders_info.items())
                total_shaders = len(shader_items)
                for idx, (shader_id, shader) in enumerate(shader_items):
                    version = get_latest_compatible_version_modrinth(shader_id, user_agent=self.config["user_agent"])
                    if version:
                        files = version['files']
                        if files:
                            file_info = files[0]
                            filename = file_info['filename']
                            url = file_info['url']
                            dest_folder = os.path.join(self.config["download_folder"], "shaderpacks")
                            if not os.path.exists(dest_folder):
                                os.makedirs(dest_folder)
                            download_file(url, dest_folder, filename, progress_bar, self.config["user_agent"])
                    progress = 100 * (idx + 1) / total_shaders if total_shaders else 100
                    progress_bar['value'] = progress
                    self.progress_window.update()

                messagebox.showinfo("Готово", "Клиентская сборка успешно скачана!")
            except Exception as e:
                messagebox.showerror("Ошибка", f"Произошла ошибка при скачивании: {e}")
            finally:
                self.progress_window.destroy()

        Thread(target=download).start()

    def download_server_build(self):
        if not os.path.exists(self.config["download_folder"]):
            os.makedirs(self.config["download_folder"])

        self.progress_window = Toplevel(self.root)
        self.progress_window.title("Прогресс скачивания сервера")
        self.progress_window.geometry("400x100")

        progress_bar = ttk.Progressbar(self.progress_window, orient="horizontal", length=300, mode="determinate")
        progress_bar.pack(pady=20)

        def download():
            try:
                # Скачивание серверных файлов для Forge
                mc_version = self.config["mc_version"]
                modloader = self.config["mod_loader"]

                if modloader.lower() == "forge":
                    # Скачиваем Forge Installer
                    forge_version = self.get_forge_version(mc_version)
                    if forge_version:
                        url = f"https://maven.minecraftforge.net/net/minecraftforge/forge/{mc_version}-{forge_version}/forge-{mc_version}-{forge_version}-installer.jar"
                        filename = f"forge-{mc_version}-{forge_version}-installer.jar"
                        dest_folder = os.path.join(self.config["download_folder"], "server")
                        if not os.path.exists(dest_folder):
                            os.makedirs(dest_folder)
                        download_file(url, dest_folder, filename, progress_bar, self.config["user_agent"])

                        # Запускаем установщик сервера
                        installer_path = os.path.join(dest_folder, filename)
                        os.system(f'java -jar "{installer_path}" --installServer')

                        # Принимаем EULA
                        self.accept_eula(dest_folder)
                    else:
                        messagebox.showerror("Ошибка", "Не удалось найти версию Forge для данной версии Minecraft.")
                        return
                else:
                    messagebox.showwarning("Внимание", f"Автоматическая установка сервера для {modloader} не поддерживается.")
                    return

                # Скачивание модов
                mod_items = list(self.selected_mods_info.items())
                total_mods = len(mod_items)
                for idx, (mod_id, mod_info) in enumerate(mod_items):
                    mod_title = mod_info['title']
                    version = get_latest_compatible_version_modrinth(mod_id, self.config["mc_version"], self.config["mod_loader"], self.config["user_agent"])
                    if version:
                        files = [file for file in version['files'] if file['primary']]
                        if files:
                            file_info = files[0]
                            filename = file_info['filename']
                            url = file_info['url']
                            dest_folder = os.path.join(self.config["download_folder"], "server", "mods")
                            if not os.path.exists(dest_folder):
                                os.makedirs(dest_folder)
                            download_file(url, dest_folder, filename, progress_bar, self.config["user_agent"])
                        else:
                            messagebox.showinfo("Информация", f"Нет файлов для мода {mod_title}.")
                    else:
                        messagebox.showwarning("Предупреждение", f"Не удалось найти совместимую версию для мода {mod_title}.")

                    progress = (idx + 1) / total_mods * 100
                    progress_bar['value'] = progress
                    self.progress_window.update()

                # Скачивание плагинов
                plugin_items = list(self.selected_plugins_info.items())
                total_plugins = len(plugin_items)
                for idx, (plugin_id, plugin) in enumerate(plugin_items):
                    url = f'https://api.spiget.org/v2/resources/{plugin_id}/download'
                    filename = f"{plugin['name']}.jar"
                    dest_folder = os.path.join(self.config["download_folder"], "server", "plugins")
                    if not os.path.exists(dest_folder):
                        os.makedirs(dest_folder)
                    download_file(url, dest_folder, filename, progress_bar, self.config["user_agent"])

                    progress = 100 * (idx + 1) / total_plugins if total_plugins else 100
                    progress_bar['value'] = progress
                    self.progress_window.update()

                messagebox.showinfo("Готово", "Серверная сборка успешно скачана!")
            except Exception as e:
                messagebox.showerror("Ошибка", f"Произошла ошибка при скачивании сервера: {e}")
            finally:
                self.progress_window.destroy()

        Thread(target=download).start()

    def get_forge_version(self, mc_version):
        # Получение последней версии Forge для заданной версии Minecraft
        url = f"https://files.minecraftforge.net/maven/net/minecraftforge/forge/promotions_slim.json"
        response = requests.get(url)
        if response.status_code == 200:
            data = response.json()
            promotions = data.get('promos', {})
            key = f"{mc_version}-latest"
            forge_version = promotions.get(key)
            return forge_version
        return None

    def accept_eula(self, server_folder):
        eula_path = os.path.join(server_folder, 'eula.txt')
        with open(eula_path, 'w') as file:
            file.write('eula=true\n')

    # Метод для оценки модов
    def rate_selected_mods(self):
        if not self.selected_mods_info:
            messagebox.showwarning("Предупреждение", "Выберите хотя бы один мод для оценки.")
            return

        for mod_id, mod in self.selected_mods_info.items():
            mod_title = mod['title']

            # Окно для ввода оценки
            rating_window = Toplevel(self.root)
            rating_window.title(f"Оценка мода {mod_title}")
            rating_window.geometry("300x150")

            ttk.Label(rating_window, text=f"Оцените мод '{mod_title}' (1-5):", font=('Roboto', 12, 'bold')).pack(pady=10)

            rating_var = tk.IntVar()
            ttk.Spinbox(rating_window, from_=1, to=5, textvariable=rating_var, width=5, font=('Roboto', 12)).pack(pady=5)

            ttk.Button(rating_window, text="Сохранить оценку", command=lambda mod_id=mod_id, var=rating_var, win=rating_window: self.save_mod_rating(mod_id, var.get(), win), style='Success.TButton').pack(pady=10)

    # Функция скачивания одной карточки модпака (добавлена ранее)
    def download_single_mod(self, mod_id):
        if mod_id in self.selected_mods_info:
            mod_info = self.selected_mods_info[mod_id]
            mod_title = mod_info['title']
            version = get_latest_compatible_version_modrinth(mod_id, self.config["mc_version"], self.config["mod_loader"], self.config["user_agent"])
            if version:
                files = [file for file in version['files'] if file['primary']]
                if files:
                    file_info = files[0]
                    filename = file_info['filename']
                    url = file_info['url']
                    dest_folder = os.path.join(self.config["download_folder"], "mods")
                    if not os.path.exists(dest_folder):
                        os.makedirs(dest_folder)
                    progress_window = Toplevel(self.root)
                    progress_window.title(f"Скачивание {mod_info['title']}")

                    progress_bar = ttk.Progressbar(progress_window, orient="horizontal", length=300, mode="determinate")
                    progress_bar.pack(pady=20, padx=20)

                    def download():
                        try:
                            download_file(url, dest_folder, filename, progress_bar, self.config["user_agent"])
                            messagebox.showinfo("Успех", f"Мод '{mod_info['title']}' успешно скачан!")
                        except Exception as e:
                            messagebox.showerror("Ошибка", f"Не удалось скачать мод '{mod_info['title']}': {e}")
                        finally:
                            progress_window.destroy()

                    Thread(target=download).start()
                else:
                    messagebox.showinfo("Информация", f"Нет файлов для мода {mod_title}.")
            else:
                messagebox.showerror("Ошибка", f"Не удалось найти совместимую версию для мода {mod_title}.")

    # === Функции для загрузки и отображения карточек ресурс-паков ===
    def create_resourcepack_card(self, parent, rp_info):
        card = ttk.Frame(parent, style='Card.TFrame')
        card.pack(pady=10, fill='x', padx=10)

        # Добавление изображения
        try:
            rp_image = ImageTk.PhotoImage(Image.open(rp_info['image_path']).resize((64,64), Image.ANTIALIAS))
        except Exception as e:
            print(f"Не удалось загрузить изображение {rp_info['image_path']}: {e}")
            # Если изображение не найдено, используем плейсхолдер
            rp_image = ImageTk.PhotoImage(Image.new('RGB', (64,64), color='#555555'))

        image_label = ttk.Label(card, image=rp_image, style='Card.TFrame')
        image_label.image = rp_image
        image_label.pack(side='left', padx=10, pady=10)

        # Информация о ресурс-паке
        info_frame = ttk.Frame(card, style='Card.TFrame')
        info_frame.pack(side='left', fill='both', expand=True)

        title_label = ttk.Label(info_frame, text=rp_info['title'], font=('Roboto', 12, 'bold'), foreground='#ffffff', background='#2b2b2b')
        title_label.pack(anchor='w')

        desc_label = ttk.Label(info_frame, text=rp_info['description'], font=('Roboto', 10), foreground='#b3b3b3', background='#2b2b2b', wraplength=600)
        desc_label.pack(anchor='w')

        # Кнопки действий
        actions_frame = ttk.Frame(card, style='Card.TFrame')
        actions_frame.pack(side='right', padx=10, pady=10)

        try:
            download_icon = ImageTk.PhotoImage(Image.open('icons/download.png').resize((24,24), Image.ANTIALIAS))
        except Exception as e:
            print(f"Не удалось загрузить иконку download.png: {e}")
            download_icon = None

        download_button = ttk.Button(actions_frame, image=download_icon, style='TButton', command=lambda rp_id=rp_info['title']: self.download_single_resourcepack(rp_id))
        if download_icon:
            download_button.image = download_icon
        download_button.pack(side='left', padx=5)

        # Добавление эффектов наведения
        card.bind("<Enter>", lambda e: card.configure(style='Hover.TFrame'))
        card.bind("<Leave>", lambda e: card.configure(style='Card.TFrame'))

    # Метод для скачивания одного ресурс-пака (добавлено ранее)
    def download_single_resourcepack(self, rp_id):
        if rp_id in self.selected_resourcepacks_info:
            rp = self.selected_resourcepacks_info[rp_id]
            version = get_latest_compatible_version_modrinth(rp_id, user_agent=self.config["user_agent"])
            if version:
                files = version['files']
                if files:
                    file_info = files[0]
                    filename = file_info['filename']
                    url = file_info['url']
                    dest_folder = os.path.join(self.config["download_folder"], "resourcepacks")
                    if not os.path.exists(dest_folder):
                        os.makedirs(dest_folder)
                    progress_window = Toplevel(self.root)
                    progress_window.title(f"Скачивание {rp['title']}")

                    progress_bar = ttk.Progressbar(progress_window, orient="horizontal", length=300, mode="determinate")
                    progress_bar.pack(pady=20, padx=20)

                    def download():
                        try:
                            download_file(url, dest_folder, filename, progress_bar, self.config["user_agent"])
                            messagebox.showinfo("Успех", f"Ресурс-пак '{rp['title']}' успешно скачан!")
                        except Exception as e:
                            messagebox.showerror("Ошибка", f"Не удалось скачать ресурс-пак '{rp['title']}': {e}")
                        finally:
                            progress_window.destroy()

                    Thread(target=download).start()
                else:
                    messagebox.showinfo("Информация", f"Нет файлов для ресурс-пака {rp['title']}.")
            else:
                messagebox.showerror("Ошибка", f"Не удалось найти последнюю версию для ресурс-пака {rp['title']}.")

    def setup_build_settings(self):
        settings_frame = ttk.LabelFrame(self.content_frame, text="Настройки сборки", style='TLabelFrame')
        settings_frame.pack(pady=10, padx=10, fill='x')

        ttk.Label(settings_frame, text="Тип сборки:", font=('Roboto', 12, 'bold')).grid(row=0, column=0, sticky="w", padx=5, pady=5)
        build_type_menu = ttk.OptionMenu(settings_frame, self.build_type_var, self.build_type_var.get(), "client", "server", "both")
        build_type_menu.grid(row=0, column=1, sticky="w", padx=5, pady=5)

    def save_user_config(self):
        # Сохраняем все выбранные моды из карточек
        selected_mods = [mod_id for mod_id in self.selected_mods_info.keys()]
        user_config = {
            "selected_mods": selected_mods,
            "mod_categories": {k: v.get() for k, v in self.mod_categories.items()},
            "exclude_categories": {k: v.get() for k, v in self.exclude_categories.items()},
            "additional_keywords": self.additional_keywords_var.get(),
            "mc_version": self.mc_version_var.get(),
            "mod_loader": self.modloader_var.get(),
            "download_folder": self.config["download_folder"],
            "user_agent": self.config["user_agent"],
        }
        with open('user_config.json', 'w', encoding='utf-8') as f:
            json.dump(user_config, f, ensure_ascii=False, indent=4)
        messagebox.showinfo("Сохранение", "Конфигурация сохранена.")

    def load_user_config(self):
        if not os.path.exists('user_config.json'):
            messagebox.showwarning("Загрузка", "Конфигурация не найдена.")
            return
        with open('user_config.json', 'r', encoding='utf-8') as f:
            user_config = json.load(f)
        # Восстанавливаем версию Minecraft и модлоадер
        self.mc_version_var.set(user_config.get("mc_version", ""))
        self.modloader_var.set(user_config.get("mod_loader", "Forge"))
        # Восстанавливаем выбранные категории
        for k, v in user_config.get("mod_categories", {}).items():
            if k in self.mod_categories:
                self.mod_categories[k].set(v)
        for k, v in user_config.get("exclude_categories", {}).items():
            if k in self.exclude_categories:
                self.exclude_categories[k].set(v)
        # Восстанавливаем ключевые слова
        self.additional_keywords_var.set(user_config.get("additional_keywords", ""))
        # Обновляем список модов
        self.search_mods()
        # Восстанавливаем выбранные моды в дереве модпака (если используется)
        selected_mods = user_config.get("selected_mods", [])
        # Здесь можно добавить логику для выделения модов, если они уже отображены
        messagebox.showinfo("Загрузка", "Конфигурация загружена.")

    # === Функция скачивания сборки ===
    def download_build(self):
        build_type = self.build_type_var.get()

        if build_type in ["client", "both"]:
            self.download_client_build()

        if build_type in ["server", "both"]:
            self.download_server_build()

    def download_client_build(self):
        if not os.path.exists(self.config["download_folder"]):
            os.makedirs(self.config["download_folder"])

        self.progress_window = Toplevel(self.root)
        self.progress_window.title("Прогресс скачивания клиента")
        self.progress_window.geometry("400x100")

        progress_bar = ttk.Progressbar(self.progress_window, orient="horizontal", length=300, mode="determinate")
        progress_bar.pack(pady=20, padx=20)

        def download():
            try:
                # Скачивание модов
                mod_items = list(self.selected_mods_info.items())
                total_mods = len(mod_items)
                for idx, (mod_id, mod_info) in enumerate(mod_items):
                    mod_title = mod_info['title']
                    version = get_latest_compatible_version_modrinth(mod_id, self.config["mc_version"], self.config["mod_loader"], self.config["user_agent"])
                    if version:
                        files = [file for file in version['files'] if file['primary']]
                        if files:
                            file_info = files[0]
                            filename = file_info['filename']
                            url = file_info['url']
                            dest_folder = os.path.join(self.config["download_folder"], "mods")
                            if not os.path.exists(dest_folder):
                                os.makedirs(dest_folder)
                            download_file(url, dest_folder, filename, progress_bar, self.config["user_agent"])
                        else:
                            messagebox.showinfo("Информация", f"Нет файлов для мода {mod_title}.")
                    else:
                        messagebox.showwarning("Предупреждение", f"Не удалось найти совместимую версию для мода {mod_title}.")

                    progress = ((idx + 1) / total_mods) * 100
                    progress_bar['value'] = progress
                    self.progress_window.update()

                # Скачивание ресурс-паков
                resourcepack_items = list(self.selected_resourcepacks_info.items())
                total_rps = len(resourcepack_items)
                for idx, (rp_id, rp) in enumerate(resourcepack_items):
                    version = get_latest_compatible_version_modrinth(rp_id, user_agent=self.config["user_agent"])
                    if version:
                        files = version['files']
                        if files:
                            file_info = files[0]
                            filename = file_info['filename']
                            url = file_info['url']
                            dest_folder = os.path.join(self.config["download_folder"], "resourcepacks")
                            if not os.path.exists(dest_folder):
                                os.makedirs(dest_folder)
                            download_file(url, dest_folder, filename, progress_bar, self.config["user_agent"])
                    progress = 100 * (idx + 1) / total_rps if total_rps else 100
                    progress_bar['value'] = progress
                    self.progress_window.update()

                # Скачивание шейдеров
                shader_items = list(self.selected_shaders_info.items())
                total_shaders = len(shader_items)
                for idx, (shader_id, shader) in enumerate(shader_items):
                    version = get_latest_compatible_version_modrinth(shader_id, user_agent=self.config["user_agent"])
                    if version:
                        files = version['files']
                        if files:
                            file_info = files[0]
                            filename = file_info['filename']
                            url = file_info['url']
                            dest_folder = os.path.join(self.config["download_folder"], "shaderpacks")
                            if not os.path.exists(dest_folder):
                                os.makedirs(dest_folder)
                            download_file(url, dest_folder, filename, progress_bar, self.config["user_agent"])
                    progress = 100 * (idx + 1) / total_shaders if total_shaders else 100
                    progress_bar['value'] = progress
                    self.progress_window.update()

                messagebox.showinfo("Готово", "Клиентская сборка успешно скачана!")
            except Exception as e:
                messagebox.showerror("Ошибка", f"Произошла ошибка при скачивании: {e}")
            finally:
                self.progress_window.destroy()

        Thread(target=download).start()

    def download_server_build(self):
        if not os.path.exists(self.config["download_folder"]):
            os.makedirs(self.config["download_folder"])

        self.progress_window = Toplevel(self.root)
        self.progress_window.title("Прогресс скачивания сервера")
        self.progress_window.geometry("400x100")

        progress_bar = ttk.Progressbar(self.progress_window, orient="horizontal", length=300, mode="determinate")
        progress_bar.pack(pady=20, padx=20)

        def download():
            try:
                # Скачивание серверных файлов для Forge
                mc_version = self.config["mc_version"]
                modloader = self.config["mod_loader"]

                if modloader.lower() == "forge":
                    # Скачиваем Forge Installer
                    forge_version = self.get_forge_version(mc_version)
                    if forge_version:
                        url = f"https://maven.minecraftforge.net/net/minecraftforge/forge/{mc_version}-{forge_version}/forge-{mc_version}-{forge_version}-installer.jar"
                        filename = f"forge-{mc_version}-{forge_version}-installer.jar"
                        dest_folder = os.path.join(self.config["download_folder"], "server")
                        if not os.path.exists(dest_folder):
                            os.makedirs(dest_folder)
                        download_file(url, dest_folder, filename, progress_bar, self.config["user_agent"])

                        # Запускаем установщик сервера
                        installer_path = os.path.join(dest_folder, filename)
                        os.system(f'java -jar "{installer_path}" --installServer')

                        # Принимаем EULA
                        self.accept_eula(dest_folder)
                    else:
                        messagebox.showerror("Ошибка", "Не удалось найти версию Forge для данной версии Minecraft.")
                        return
                else:
                    messagebox.showwarning("Внимание", f"Автоматическая установка сервера для {modloader} не поддерживается.")
                    return

                # Скачивание модов
                mod_items = list(self.selected_mods_info.items())
                total_mods = len(mod_items)
                for idx, (mod_id, mod_info) in enumerate(mod_items):
                    mod_title = mod_info['title']
                    version = get_latest_compatible_version_modrinth(mod_id, self.config["mc_version"], self.config["mod_loader"], self.config["user_agent"])
                    if version:
                        files = [file for file in version['files'] if file['primary']]
                        if files:
                            file_info = files[0]
                            filename = file_info['filename']
                            url = file_info['url']
                            dest_folder = os.path.join(self.config["download_folder"], "server", "mods")
                            if not os.path.exists(dest_folder):
                                os.makedirs(dest_folder)
                            download_file(url, dest_folder, filename, progress_bar, self.config["user_agent"])
                        else:
                            messagebox.showinfo("Информация", f"Нет файлов для мода {mod_title}.")
                    else:
                        messagebox.showwarning("Предупреждение", f"Не удалось найти совместимую версию для мода {mod_title}.")

                    progress = ((idx + 1) / total_mods) * 100
                    progress_bar['value'] = progress
                    self.progress_window.update()

                # Скачивание плагинов
                plugin_items = list(self.selected_plugins_info.items())
                total_plugins = len(plugin_items)
                for idx, (plugin_id, plugin) in enumerate(plugin_items):
                    url = f'https://api.spiget.org/v2/resources/{plugin_id}/download'
                    filename = f"{plugin['name']}.jar"
                    dest_folder = os.path.join(self.config["download_folder"], "server", "plugins")
                    if not os.path.exists(dest_folder):
                        os.makedirs(dest_folder)
                    download_file(url, dest_folder, filename, progress_bar, self.config["user_agent"])

                    progress = 100 * (idx + 1) / total_plugins if total_plugins else 100
                    progress_bar['value'] = progress
                    self.progress_window.update()

                messagebox.showinfo("Готово", "Серверная сборка успешно скачана!")
            except Exception as e:
                messagebox.showerror("Ошибка", f"Произошла ошибка при скачивании сервера: {e}")
            finally:
                self.progress_window.destroy()

        Thread(target=download).start()

    def get_forge_version(self, mc_version):
        # Получение последней версии Forge для заданной версии Minecraft
        url = f"https://files.minecraftforge.net/maven/net/minecraftforge/forge/promotions_slim.json"
        response = requests.get(url)
        if response.status_code == 200:
            data = response.json()
            promotions = data.get('promos', {})
            key = f"{mc_version}-latest"
            forge_version = promotions.get(key)
            return forge_version
        return None

    def accept_eula(self, server_folder):
        eula_path = os.path.join(server_folder, 'eula.txt')
        with open(eula_path, 'w') as file:
            file.write('eula=true\n')

    # Метод для оценки модов (добавлено ранее)
    def rate_selected_mods(self):
        if not self.selected_mods_info:
            messagebox.showwarning("Предупреждение", "Выберите хотя бы один мод для оценки.")
            return

        for mod_id, mod in self.selected_mods_info.items():
            mod_title = mod['title']

            # Окно для ввода оценки
            rating_window = Toplevel(self.root)
            rating_window.title(f"Оценка мода {mod_title}")
            rating_window.geometry("300x150")

            ttk.Label(rating_window, text=f"Оцените мод '{mod_title}' (1-5):", font=('Roboto', 12, 'bold')).pack(pady=10)

            rating_var = tk.IntVar()
            ttk.Spinbox(rating_window, from_=1, to=5, textvariable=rating_var, width=5, font=('Roboto', 12)).pack(pady=5)

            ttk.Button(rating_window, text="Сохранить оценку", command=lambda mod_id=mod_id, var=rating_var, win=rating_window: self.save_mod_rating(mod_id, var.get(), win), style='Success.TButton').pack(pady=10)

    # === Функции для отображения рекомендаций ===
    def show_recommendations(self):
        trending_mods = self.get_trending_mods()
        recommendations_window = Toplevel(self.root)
        recommendations_window.title("Рекомендуемые моды")
        recommendations_window.geometry("600x400")

        # Рамка с прокруткой
        container = ttk.Frame(recommendations_window, style='TFrame')
        container.pack(fill='both', expand=True)

        canvas = tk.Canvas(container, background='#1e1e1e')
        scrollbar = ttk.Scrollbar(container, orient="vertical", command=canvas.yview)
        self.recommendations_frame = ttk.Frame(canvas, style='TFrame')

        self.recommendations_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(
                scrollregion=canvas.bbox("all")
            )
        )

        canvas.create_window((0, 0), window=self.recommendations_frame, anchor='nw')
        canvas.configure(yscrollcommand=scrollbar.set)

        canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")

        for mod in trending_mods:
            mod_info = {
                'title': mod['title'],
                'description': mod['description'][:200] + '...' if len(mod['description']) > 200 else mod['description'],
                'image_path': 'icons/mod_placeholder.png'  # Замените на реальный путь или используйте placeholder
            }
            self.create_recommendation_card(self.recommendations_frame, mod_info)

    def get_trending_mods(self):
        url = 'https://api.modrinth.com/v2/search'
        headers = {'User-Agent': self.config["user_agent"]}
        params = {
            'facets': json.dumps([[f"project_type:mod"]]),
            'sort': 'downloads',
            'limit': 10
        }
        response = requests.get(url, params=params, headers=headers)
        if response.status_code == 200:
            return response.json().get('hits', [])
        else:
            messagebox.showerror("Ошибка", f"Modrinth API Ошибка: {response.status_code}")
            return []

    def create_recommendation_card(self, parent, mod_info):
        card = ttk.Frame(parent, style='Card.TFrame')
        card.pack(pady=10, fill='x', padx=10)

        # Добавление изображения
        try:
            mod_image = ImageTk.PhotoImage(Image.open(mod_info['image_path']).resize((64,64), Image.ANTIALIAS))
        except Exception as e:
            print(f"Не удалось загрузить изображение {mod_info['image_path']}: {e}")
            # Если изображение не найдено, используем плейсхолдер
            mod_image = ImageTk.PhotoImage(Image.new('RGB', (64,64), color='#555555'))

        image_label = ttk.Label(card, image=mod_image, style='Card.TFrame')
        image_label.image = mod_image
        image_label.pack(side='left', padx=10, pady=10)

        # Информация о моде
        info_frame = ttk.Frame(card, style='Card.TFrame')
        info_frame.pack(side='left', fill='both', expand=True)

        title_label = ttk.Label(info_frame, text=mod_info['title'], font=('Roboto', 12, 'bold'), foreground='#ffffff', background='#2b2b2b')
        title_label.pack(anchor='w')

        desc_label = ttk.Label(info_frame, text=mod_info['description'], font=('Roboto', 10), foreground='#b3b3b3', background='#2b2b2b', wraplength=500)
        desc_label.pack(anchor='w')

        # Кнопки действий
        actions_frame = ttk.Frame(card, style='Card.TFrame')
        actions_frame.pack(side='right', padx=10, pady=10)

        try:
            download_icon = ImageTk.PhotoImage(Image.open('icons/download.png').resize((24,24), Image.ANTIALIAS))
        except Exception as e:
            print(f"Не удалось загрузить иконку download.png: {e}")
            download_icon = None

        download_button = ttk.Button(actions_frame, image=download_icon, style='TButton', command=lambda mod_id=mod_info['title']: self.download_single_mod(mod_id))
        if download_icon:
            download_button.image = download_icon
        download_button.pack(side='left', padx=5)

        # Добавление эффектов наведения
        card.bind("<Enter>", lambda e: card.configure(style='Hover.TFrame'))
        card.bind("<Leave>", lambda e: card.configure(style='Card.TFrame'))

# === Запуск приложения ===
if __name__ == '__main__':
    # Убедитесь, что шрифт Roboto доступен
    try:
        root_temp = tk.Tk()
        root_temp.destroy()
        font.nametofont("TkDefaultFont").configure(family="Roboto")
    except:
        print("Шрифт Roboto не найден. Используется системный шрифт.")

    config = load_config()
    root = tk.Tk()
    app = ModPackBuilder(root, config)
    root.mainloop()