import os
import configparser
import shutil
from portprotonqt.logger import get_logger

logger = get_logger(__name__)

_portproton_location = None

# Пути к конфигурационным файлам
CONFIG_FILE = os.path.join(
    os.getenv("XDG_CONFIG_HOME", os.path.join(os.path.expanduser("~"), ".config")),
    "PortProtonQt.conf"
)

PORTPROTON_CONFIG_FILE = os.path.join(
    os.getenv("XDG_CONFIG_HOME", os.path.join(os.path.expanduser("~"), ".config")),
    "PortProton.conf"
)

# Пути к папкам с темами
xdg_data_home = os.getenv("XDG_DATA_HOME", os.path.join(os.path.expanduser("~"), ".local", "share"))
THEMES_DIRS = [
    os.path.join(xdg_data_home, "PortProtonQt", "themes"),
    os.path.join(os.path.dirname(os.path.abspath(__file__)), "themes")
]

def read_config():
    """
    Читает конфигурационный файл и возвращает словарь параметров.
    Пример строки в конфиге (без секций):
      detail_level = detailed
    """
    config_dict = {}
    if os.path.exists(CONFIG_FILE):
        with open(CONFIG_FILE, encoding="utf-8") as f:
            for line in f:
                line = line.strip()
                if not line or line.startswith("#"):
                    continue
                key, sep, value = line.partition("=")
                if sep:
                    config_dict[key.strip()] = value.strip()
    return config_dict

def read_theme_from_config():
    """
    Читает из конфигурационного файла тему из секции [Appearance].
    Если параметр не задан, возвращает "standart".
    """
    cp = configparser.ConfigParser()
    if os.path.exists(CONFIG_FILE):
        try:
            cp.read(CONFIG_FILE, encoding="utf-8")
        except (configparser.DuplicateSectionError, configparser.DuplicateOptionError) as e:
            logger.error("Ошибка в конфигурационном файле: %s", e)
            return "standart"
    return cp.get("Appearance", "theme", fallback="standart")

def save_theme_to_config(theme_name):
    """
    Сохраняет имя выбранной темы в секции [Appearance] конфигурационного файла.
    """
    cp = configparser.ConfigParser()
    if os.path.exists(CONFIG_FILE):
        try:
            cp.read(CONFIG_FILE, encoding="utf-8")
        except (configparser.DuplicateSectionError, configparser.DuplicateOptionError) as e:
            logger.error("Ошибка в конфигурационном файле: %s", e)
    if "Appearance" not in cp:
        cp["Appearance"] = {}
    cp["Appearance"]["theme"] = theme_name
    with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
        cp.write(configfile)

def read_time_config():
    """
    Читает настройки времени из секции [Time] конфигурационного файла.
    Если секция или параметр отсутствуют, сохраняет и возвращает "detailed" по умолчанию.
    """
    cp = configparser.ConfigParser()
    if os.path.exists(CONFIG_FILE):
        try:
            cp.read(CONFIG_FILE, encoding="utf-8")
        except (configparser.DuplicateSectionError, configparser.DuplicateOptionError) as e:
            logger.error("Ошибка в конфигурационном файле: %s", e)
            save_time_config("detailed")
            return "detailed"
        if not cp.has_section("Time") or not cp.has_option("Time", "detail_level"):
            save_time_config("detailed")
            return "detailed"
        return cp.get("Time", "detail_level", fallback="detailed").lower()
    return "detailed"

def save_time_config(detail_level):
    """
    Сохраняет настройку уровня детализации времени в секции [Time].
    """
    cp = configparser.ConfigParser()
    if os.path.exists(CONFIG_FILE):
        try:
            cp.read(CONFIG_FILE, encoding="utf-8")
        except (configparser.DuplicateSectionError, configparser.DuplicateOptionError) as e:
            logger.error("Ошибка в конфигурационном файле: %s", e)
    if "Time" not in cp:
        cp["Time"] = {}
    cp["Time"]["detail_level"] = detail_level
    with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
        cp.write(configfile)

def read_file_content(file_path):
    """
    Читает содержимое файла и возвращает его как строку.
    """
    with open(file_path, encoding="utf-8") as f:
        return f.read().strip()

def get_portproton_location():
    """
    Возвращает путь к директории PortProton.
    Сначала проверяется кэшированный путь. Если он отсутствует, проверяется
    наличие пути в файле PORTPROTON_CONFIG_FILE. Если путь недоступен,
    используется директория по умолчанию.
    """
    global _portproton_location
    if _portproton_location is not None:
        return _portproton_location

    # Попытка чтения пути из конфигурационного файла
    if os.path.isfile(PORTPROTON_CONFIG_FILE):
        try:
            location = read_file_content(PORTPROTON_CONFIG_FILE).strip()
            if location and os.path.isdir(location):
                _portproton_location = location
                logger.info(f"Путь PortProton из конфигурации: {location}")
                return _portproton_location
            logger.warning(f"Недействительный путь в конфиге PortProton: {location}")
        except (OSError, PermissionError) as e:
            logger.error(f"Ошибка чтения файла конфигурации PortProton: {e}")

    default_dir = os.path.join(os.path.expanduser("~"), ".var", "app", "ru.linux_gaming.PortProton")
    if os.path.isdir(default_dir):
        _portproton_location = default_dir
        logger.info(f"Используется директория flatpak PortProton: {default_dir}")
        return _portproton_location

    logger.warning("Конфигурация и директория flatpak PortProton не найдены")
    return None

def parse_desktop_entry(file_path):
    """
    Читает и парсит .desktop файл с помощью configparser.
    Если секция [Desktop Entry] отсутствует, возвращается None.
    """
    cp = configparser.ConfigParser(interpolation=None)
    cp.read(file_path, encoding="utf-8")
    if "Desktop Entry" not in cp:
        return None
    return cp["Desktop Entry"]

def load_theme_metainfo(theme_name):
    """
    Загружает метаинформацию темы из файла metainfo.ini в корне папки темы.
    Ожидаемые поля: author, author_link, description, name.
    """
    meta = {}
    for themes_dir in THEMES_DIRS:
        theme_folder = os.path.join(themes_dir, theme_name)
        metainfo_file = os.path.join(theme_folder, "metainfo.ini")
        if os.path.exists(metainfo_file):
            cp = configparser.ConfigParser()
            cp.read(metainfo_file, encoding="utf-8")
            if "Metainfo" in cp:
                meta["author"] = cp.get("Metainfo", "author", fallback="Unknown")
                meta["author_link"] = cp.get("Metainfo", "author_link", fallback="")
                meta["description"] = cp.get("Metainfo", "description", fallback="")
                meta["name"] = cp.get("Metainfo", "name", fallback=theme_name)
            break
    return meta

def read_card_size():
    """
    Читает размер карточек (ширину) из секции [Cards],
    Если параметр не задан, возвращает 250.
    """
    cp = configparser.ConfigParser()
    if os.path.exists(CONFIG_FILE):
        try:
            cp.read(CONFIG_FILE, encoding="utf-8")
        except (configparser.DuplicateSectionError, configparser.DuplicateOptionError) as e:
            logger.error("Ошибка в конфигурационном файле: %s", e)
            save_card_size(250)
            return 250
        if not cp.has_section("Cards") or not cp.has_option("Cards", "card_width"):
            save_card_size(250)
            return 250
        return cp.getint("Cards", "card_width", fallback=250)
    return 250

def save_card_size(card_width):
    """
    Сохраняет размер карточек (ширину) в секцию [Cards].
    """
    cp = configparser.ConfigParser()
    if os.path.exists(CONFIG_FILE):
        try:
            cp.read(CONFIG_FILE, encoding="utf-8")
        except (configparser.DuplicateSectionError, configparser.DuplicateOptionError) as e:
            logger.error("Ошибка в конфигурационном файле: %s", e)
    if "Cards" not in cp:
        cp["Cards"] = {}
    cp["Cards"]["card_width"] = str(card_width)
    with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
        cp.write(configfile)

def read_sort_method():
    """
    Читает метод сортировки из секции [Games].
    Если параметр не задан, возвращает last_launch.
    """
    cp = configparser.ConfigParser()
    if os.path.exists(CONFIG_FILE):
        try:
            cp.read(CONFIG_FILE, encoding="utf-8")
        except (configparser.DuplicateSectionError, configparser.DuplicateOptionError) as e:
            logger.error("Ошибка в конфигурационном файле: %s", e)
            save_sort_method("last_launch")
            return "last_launch"
        if not cp.has_section("Games") or not cp.has_option("Games", "sort_method"):
            save_sort_method("last_launch")
            return "last_launch"
        return cp.get("Games", "sort_method", fallback="last_launch").lower()
    return "last_launch"

def save_sort_method(sort_method):
    """
    Сохраняет метод сортировки в секцию [Games].
    """
    cp = configparser.ConfigParser()
    if os.path.exists(CONFIG_FILE):
        try:
            cp.read(CONFIG_FILE, encoding="utf-8")
        except (configparser.DuplicateSectionError, configparser.DuplicateOptionError) as e:
            logger.error("Ошибка в конфигурационном файле: %s", e)
    if "Games" not in cp:
        cp["Games"] = {}
    cp["Games"]["sort_method"] = sort_method
    with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
        cp.write(configfile)

def read_display_filter():
    """
    Читает параметр display_filter из секции [Games].
    Если параметр отсутствует, сохраняет и возвращает значение "all".
    """
    cp = configparser.ConfigParser()
    if os.path.exists(CONFIG_FILE):
        try:
            cp.read(CONFIG_FILE, encoding="utf-8")
        except Exception as e:
            logger.error("Ошибка чтения конфига: %s", e)
            save_display_filter("all")
            return "all"
        if not cp.has_section("Games") or not cp.has_option("Games", "display_filter"):
            save_display_filter("all")
            return "all"
        return cp.get("Games", "display_filter", fallback="all").lower()
    return "all"

def save_display_filter(filter_value):
    """
    Сохраняет параметр display_filter в секцию [Games] конфигурационного файла.
    """
    cp = configparser.ConfigParser()
    if os.path.exists(CONFIG_FILE):
        try:
            cp.read(CONFIG_FILE, encoding="utf-8")
        except Exception as e:
            logger.error("Ошибка чтения конфига: %s", e)
    if "Games" not in cp:
        cp["Games"] = {}
    cp["Games"]["display_filter"] = filter_value
    with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
        cp.write(configfile)

def read_favorites():
    """
    Читает список избранных игр из секции [Favorites] конфигурационного файла.
    Список хранится как строка, заключённая в кавычки, с именами, разделёнными запятыми.
    Если секция или параметр отсутствуют, возвращает пустой список.
    """
    cp = configparser.ConfigParser()
    if os.path.exists(CONFIG_FILE):
        try:
            cp.read(CONFIG_FILE, encoding="utf-8")
        except Exception as e:
            logger.error("Ошибка чтения конфига: %s", e)
            return []
        if cp.has_section("Favorites") and cp.has_option("Favorites", "games"):
            favs = cp.get("Favorites", "games", fallback="").strip()
            # Если строка начинается и заканчивается кавычками, удаляем их
            if favs.startswith('"') and favs.endswith('"'):
                favs = favs[1:-1]
            return [s.strip() for s in favs.split(",") if s.strip()]
    return []

def save_favorites(favorites):
    """
    Сохраняет список избранных игр в секцию [Favorites] конфигурационного файла.
    Список сохраняется как строка, заключённая в двойные кавычки, где имена игр разделены запятыми.
    """
    cp = configparser.ConfigParser()
    if os.path.exists(CONFIG_FILE):
        try:
            cp.read(CONFIG_FILE, encoding="utf-8")
        except Exception as e:
            logger.error("Ошибка чтения конфига: %s", e)
    if "Favorites" not in cp:
        cp["Favorites"] = {}
    fav_str = ", ".join(favorites)
    cp["Favorites"]["games"] = f'"{fav_str}"'
    with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
        cp.write(configfile)

def read_rumble_config():
    """
    Читает настройку виброотдачи геймпада из секции [Gamepad].
    Если параметр отсутствует, сохраняет и возвращает False по умолчанию.
    """
    cp = configparser.ConfigParser()
    if os.path.exists(CONFIG_FILE):
        try:
            cp.read(CONFIG_FILE, encoding="utf-8")
        except Exception as e:
            logger.error("Ошибка чтения конфигурационного файла: %s", e)
            save_rumble_config(False)
            return False
        if not cp.has_section("Gamepad") or not cp.has_option("Gamepad", "rumble_enabled"):
            save_rumble_config(False)
            return False
        return cp.getboolean("Gamepad", "rumble_enabled", fallback=False)
    return False

def save_rumble_config(rumble_enabled):
    """
    Сохраняет настройку виброотдачи геймпада в секцию [Gamepad].
    """
    cp = configparser.ConfigParser()
    if os.path.exists(CONFIG_FILE):
        try:
            cp.read(CONFIG_FILE, encoding="utf-8")
        except (configparser.DuplicateSectionError, configparser.DuplicateOptionError) as e:
            logger.error("Ошибка чтения конфигурационного файла: %s", e)
    if "Gamepad" not in cp:
        cp["Gamepad"] = {}
    cp["Gamepad"]["rumble_enabled"] = str(rumble_enabled)
    with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
        cp.write(configfile)

def ensure_default_proxy_config():
    """
    Проверяет наличие секции [Proxy] в конфигурационном файле.
    Если секция отсутствует, создаёт её с пустыми значениями.
    """
    cp = configparser.ConfigParser()
    if os.path.exists(CONFIG_FILE):
        try:
            cp.read(CONFIG_FILE, encoding="utf-8")
        except Exception as e:
            logger.error("Ошибка чтения конфигурационного файла: %s", e)
            return
        if not cp.has_section("Proxy"):
            cp.add_section("Proxy")
            cp["Proxy"]["proxy_url"] = ""
            cp["Proxy"]["proxy_user"] = ""
            cp["Proxy"]["proxy_password"] = ""
            with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
                cp.write(configfile)

def read_proxy_config():
    """
    Читает настройки прокси из секции [Proxy] конфигурационного файла.
    Если параметр proxy_url не задан или пустой, возвращает пустой словарь.
    """
    ensure_default_proxy_config()
    cp = configparser.ConfigParser()
    try:
        cp.read(CONFIG_FILE, encoding="utf-8")
    except Exception as e:
        logger.error("Ошибка чтения конфигурационного файла: %s", e)
        return {}

    proxy_url = cp.get("Proxy", "proxy_url", fallback="").strip()
    if proxy_url:
        # Если указаны логин и пароль, добавляем их к URL
        proxy_user = cp.get("Proxy", "proxy_user", fallback="").strip()
        proxy_password = cp.get("Proxy", "proxy_password", fallback="").strip()
        if "://" in proxy_url and "@" not in proxy_url and proxy_user and proxy_password:
            protocol, rest = proxy_url.split("://", 1)
            proxy_url = f"{protocol}://{proxy_user}:{proxy_password}@{rest}"
        return {"http": proxy_url, "https": proxy_url}
    return {}

def save_proxy_config(proxy_url="", proxy_user="", proxy_password=""):
    """
    Сохраняет настройки proxy в секцию [Proxy] конфигурационного файла.
    Если секция отсутствует, создаёт её.
    """
    cp = configparser.ConfigParser()
    if os.path.exists(CONFIG_FILE):
        try:
            cp.read(CONFIG_FILE, encoding="utf-8")
        except (configparser.DuplicateSectionError, configparser.DuplicateOptionError) as e:
            logger.error("Ошибка чтения конфигурационного файла: %s", e)
    if "Proxy" not in cp:
        cp["Proxy"] = {}
    cp["Proxy"]["proxy_url"] = proxy_url
    cp["Proxy"]["proxy_user"] = proxy_user
    cp["Proxy"]["proxy_password"] = proxy_password
    with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
        cp.write(configfile)

def read_fullscreen_config():
    """
    Читает настройку полноэкранного режима приложения из секции [Display].
    Если параметр отсутствует, сохраняет и возвращает False по умолчанию.
    """
    cp = configparser.ConfigParser()
    if os.path.exists(CONFIG_FILE):
        try:
            cp.read(CONFIG_FILE, encoding="utf-8")
        except Exception as e:
            logger.error("Ошибка чтения конфигурационного файла: %s", e)
            save_fullscreen_config(False)
            return False
        if not cp.has_section("Display") or not cp.has_option("Display", "fullscreen"):
            save_fullscreen_config(False)
            return False
        return cp.getboolean("Display", "fullscreen", fallback=False)
    return False

def save_fullscreen_config(fullscreen):
    """
    Сохраняет настройку полноэкранного режима приложения в секцию [Display].
    """
    cp = configparser.ConfigParser()
    if os.path.exists(CONFIG_FILE):
        try:
            cp.read(CONFIG_FILE, encoding="utf-8")
        except (configparser.DuplicateSectionError, configparser.DuplicateOptionError) as e:
            logger.error("Ошибка чтения конфигурационного файла: %s", e)
    if "Display" not in cp:
        cp["Display"] = {}
    cp["Display"]["fullscreen"] = str(fullscreen)
    with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
        cp.write(configfile)

def read_window_geometry() -> tuple[int, int]:
    """
    Читает ширину и высоту окна из секции [MainWindow] конфигурационного файла.
    Возвращает кортеж (width, height). Если данные отсутствуют, возвращает (0, 0).
    """
    cp = configparser.ConfigParser()
    if os.path.exists(CONFIG_FILE):
        try:
            cp.read(CONFIG_FILE, encoding="utf-8")
        except (configparser.DuplicateSectionError, configparser.DuplicateOptionError) as e:
            logger.error("Ошибка в конфигурационном файле: %s", e)
            return (0, 0)
        if cp.has_section("MainWindow"):
            width = cp.getint("MainWindow", "width", fallback=0)
            height = cp.getint("MainWindow", "height", fallback=0)
            return (width, height)
    return (0, 0)

def save_window_geometry(width: int, height: int):
    """
    Сохраняет ширину и высоту окна в секцию [MainWindow] конфигурационного файла.
    """
    cp = configparser.ConfigParser()
    if os.path.exists(CONFIG_FILE):
        try:
            cp.read(CONFIG_FILE, encoding="utf-8")
        except (configparser.DuplicateSectionError, configparser.DuplicateOptionError) as e:
            logger.error("Ошибка в конфигурационном файле: %s", e)
    if "MainWindow" not in cp:
        cp["MainWindow"] = {}
    cp["MainWindow"]["width"] = str(width)
    cp["MainWindow"]["height"] = str(height)
    with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
        cp.write(configfile)

def reset_config():
    """
    Сбрасывает конфигурационный файл, удаляя его.
    После этого все настройки будут возвращены к значениям по умолчанию при следующем чтении.
    """
    if os.path.exists(CONFIG_FILE):
        try:
            os.remove(CONFIG_FILE)
            logger.info("Конфигурационный файл %s удалён", CONFIG_FILE)
        except Exception as e:
            logger.error("Ошибка при удалении конфигурационного файла: %s", e)

def clear_cache():
    """
    Очищает кэш PortProtonQt, удаляя папку кэша.
    """
    xdg_cache_home = os.getenv("XDG_CACHE_HOME", os.path.join(os.path.expanduser("~"), ".cache"))
    cache_dir = os.path.join(xdg_cache_home, "PortProtonQt")
    if os.path.exists(cache_dir):
        try:
            shutil.rmtree(cache_dir)
            logger.info("Кэш PortProtonQt удалён: %s", cache_dir)
        except Exception as e:
            logger.error("Ошибка при удалении кэша: %s", e)

def read_auto_fullscreen_gamepad():
    """
    Читает настройку автоматического полноэкранного режима при подключении геймпада из секции [Display].
    Если параметр отсутствует, сохраняет и возвращает False по умолчанию.
    """
    cp = configparser.ConfigParser()
    if os.path.exists(CONFIG_FILE):
        try:
            cp.read(CONFIG_FILE, encoding="utf-8")
        except Exception as e:
            logger.error("Ошибка чтения конфигурационного файла: %s", e)
            save_auto_fullscreen_gamepad(False)
            return False
        if not cp.has_section("Display") or not cp.has_option("Display", "auto_fullscreen_gamepad"):
            save_auto_fullscreen_gamepad(False)
            return False
        return cp.getboolean("Display", "auto_fullscreen_gamepad", fallback=False)
    return False

def save_auto_fullscreen_gamepad(auto_fullscreen):
    """
    Сохраняет настройку автоматического полноэкранного режима при подключении геймпада в секцию [Display].
    """
    cp = configparser.ConfigParser()
    if os.path.exists(CONFIG_FILE):
        try:
            cp.read(CONFIG_FILE, encoding="utf-8")
        except (configparser.DuplicateSectionError, configparser.DuplicateOptionError) as e:
            logger.error("Ошибка чтения конфигурационного файла: %s", e)
    if "Display" not in cp:
        cp["Display"] = {}
    cp["Display"]["auto_fullscreen_gamepad"] = str(auto_fullscreen)
    with open(CONFIG_FILE, "w", encoding="utf-8") as configfile:
        cp.write(configfile)
