#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import json
import logging
import requests
import threading
from packaging import version

class UpdateCheckError(Exception):
    """Исключение для ошибок проверки обновлений"""
    pass

class UpdateChecker:
    """Класс для проверки обновлений программы"""
    
    def __init__(self, current_version, repo_url):
        self.current_version = current_version
        self.repo_url = repo_url
        # Формируем базовый URL API
        self.api_url = repo_url.replace("gitea.filow.ru", "gitea.filow.ru/api/v1/repos/LowaSC/ComConfigCopy")
        self._update_available = False
        self._latest_version = None
        self._latest_release = None
        self._error = None
        self._changelog = None
    
    def get_changelog(self, callback=None):
        """
        Получение changelog из репозитория.
        :param callback: Функция обратного вызова, которая будет вызвана после получения changelog
        """
        def fetch():
            try:
                # Пытаемся получить CHANGELOG.md из репозитория
                response = requests.get(f"{self.api_url}/contents/CHANGELOG.md", timeout=10)
                response.raise_for_status()
                
                content = response.json()
                if "content" in content:
                    import base64
                    changelog_content = base64.b64decode(content["content"]).decode("utf-8")
                    self._changelog = changelog_content
                    self._error = None
                else:
                    raise UpdateCheckError("Не удалось получить содержимое CHANGELOG.md")
                    
            except requests.RequestException as e:
                error_msg = f"Ошибка получения changelog: {e}"
                logging.error(error_msg, exc_info=True)
                self._error = error_msg
                self._changelog = None
            except Exception as e:
                error_msg = f"Неизвестная ошибка при получении changelog: {e}"
                logging.error(error_msg, exc_info=True)
                self._error = error_msg
                self._changelog = None
            finally:
                if callback:
                    callback(self._changelog, self._error)
        
        # Запускаем получение в отдельном потоке
        threading.Thread(target=fetch, daemon=True).start()
    
    def check_updates(self, callback=None):
        """
        Проверка наличия обновлений.
        :param callback: Функция обратного вызова, которая будет вызвана после проверки
        """
        def check():
            try:
                response = requests.get(f"{self.api_url}/releases", timeout=10)
                response.raise_for_status()
                
                releases = response.json()
                if not releases:
                    raise UpdateCheckError("Не найдено релизов в репозитории")
                
                latest_release = releases[0]
                latest_version = latest_release.get("tag_name", "").lstrip("v")
                
                if not latest_version:
                    raise UpdateCheckError("Не удалось определить версию последнего релиза")
                
                try:
                    if version.parse(latest_version) > version.parse(self.current_version):
                        self._update_available = True
                        self._latest_version = latest_version
                        self._latest_release = latest_release
                        logging.info(f"Доступно обновление: {latest_version}")
                    else:
                        logging.info("Обновления не требуются")
                except version.InvalidVersion as e:
                    raise UpdateCheckError(f"Некорректный формат версии: {e}")
                    
                self._error = None
                    
            except requests.RequestException as e:
                error_msg = f"Ошибка сетевого подключения: {e}"
                logging.error(error_msg, exc_info=True)
                self._error = error_msg
            except UpdateCheckError as e:
                logging.error(str(e), exc_info=True)
                self._error = str(e)
            except Exception as e:
                error_msg = f"Неизвестная ошибка при проверке обновлений: {e}"
                logging.error(error_msg, exc_info=True)
                self._error = error_msg
            finally:
                if callback:
                    callback(self._update_available, self._error)
    
    @property
    def update_available(self):
        """Доступно ли обновление"""
        return self._update_available
    
    @property
    def latest_version(self):
        """Последняя доступная версия"""
        return self._latest_version
    
    @property
    def error(self):
        """Последняя ошибка при проверке обновлений"""
        return self._error
    
    @property
    def changelog(self):
        """Текущий changelog"""
        return self._changelog
    
    def get_release_notes(self):
        """Получение информации о последнем релизе"""
        if self._latest_release:
            return {
                "version": self._latest_version,
                "description": self._latest_release.get("body", ""),
                "download_url": self._latest_release.get("assets", [{}])[0].get("browser_download_url", "")
            }
        return None

    def get_releases(self, callback=None):
        """
        Получение списка релизов из репозитория.
        :param callback: Функция обратного вызова, которая будет вызвана после получения списка релизов
        """
        def fetch():
            try:
                response = requests.get(f"{self.api_url}/releases", timeout=10)
                response.raise_for_status()
                releases = response.json()
                
                if not releases:
                    raise UpdateCheckError("Не найдено релизов в репозитории")
                
                self._error = None
                if callback:
                    callback(releases, None)
                    
            except requests.RequestException as e:
                error_msg = f"Ошибка сетевого подключения: {e}"
                logging.error(error_msg, exc_info=True)
                self._error = error_msg
                if callback:
                    callback(None, error_msg)
            except Exception as e:
                error_msg = f"Ошибка при получении списка релизов: {e}"
                logging.error(error_msg, exc_info=True)
                self._error = error_msg
                if callback:
                    callback(None, error_msg)
        
        # Запускаем получение в отдельном потоке
        threading.Thread(target=fetch, daemon=True).start() 