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

"""
Модуль для взаимодействия с API Synology NAS
"""

import requests
from requests.adapters import HTTPAdapter
import json
import logging
import time
import urllib3
from urllib3.util import Retry
from typing import Dict, Any, Optional, List
import socket
import struct
from time import sleep

from src.config.config import (
    SYNOLOGY_HOST, 
    SYNOLOGY_PORT,
    SYNOLOGY_USERNAME,
    SYNOLOGY_PASSWORD,
    SYNOLOGY_SECURE,
    SYNOLOGY_TIMEOUT,
    SYNOLOGY_MAC,
    WOL_PORT,
    SYNOLOGY_API_VERSION,
    SYNOLOGY_POWER_API,
    SYNOLOGY_INFO_API
)
from src.api.api_discovery import discover_available_apis, find_compatible_api

# Отключение предупреждений о небезопасных SSL-соединениях
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

logger = logging.getLogger(__name__)

class SynologyAPI:
    """Класс для взаимодействия с API Synology NAS"""
    
    def __init__(self):
        """Инициализация класса SynologyAPI"""
        logger.info("Creating API with auto-retry and connection pool")
        logger.debug(f"Connection details: Host={SYNOLOGY_HOST}, Port={SYNOLOGY_PORT}, Secure={SYNOLOGY_SECURE}")
        
        self.protocol = "https" if SYNOLOGY_SECURE else "http"
        self.base_url = f"{self.protocol}://{SYNOLOGY_HOST}:{SYNOLOGY_PORT}/webapi"
        self.sid = None
        self.session = requests.Session()
        
        # Настройка SSL
        if self.protocol == "https":
            logger.debug("SSL enabled, disabling certificate verification for internal network")
            self.session.verify = False  # Отключаем проверку SSL для внутренней сети
        
        # Добавляем пользовательские заголовки для улучшения совместимости с API
        custom_headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
            'Accept': 'application/json, text/javascript, */*; q=0.01',
            'Accept-Language': 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7',
            'X-Requested-With': 'XMLHttpRequest',
            'Connection': 'keep-alive',
            'Referer': f'{self.protocol}://{SYNOLOGY_HOST}:{SYNOLOGY_PORT}/'
        }
        self.session.headers.update(custom_headers)
        logger.debug("Added browser-like headers for API compatibility")
        
        # Добавляем повторные попытки для HTTP-запросов
        retry_strategy = Retry(
            total=5,  # Увеличиваем количество попыток
            status_forcelist=[429, 500, 502, 503, 504, 404],
            allowed_methods=["GET", "POST"],
            backoff_factor=1.5,  # Увеличиваем задержку между попытками
            respect_retry_after_header=True
        )
        adapter = HTTPAdapter(
            max_retries=retry_strategy, 
            pool_connections=3, 
            pool_maxsize=10
        )
        self.session.mount("http://", adapter)
        self.session.mount("https://", adapter)
        
        # Таймауты будут указаны в запросах
        self.default_timeout = (SYNOLOGY_TIMEOUT, SYNOLOGY_TIMEOUT*2)
        logger.debug(f"Setting default request timeout: {self.default_timeout}")
        
        # Кэш для хранения результатов запросов
        self._cache = {}
        self._cache_ttl = {}
        self._last_online_check = 0
        self._last_online_status = False
        self._online_check_interval = 30  # Интервал для кэширования проверок онлайн-статуса
        
        # Время последней успешной аутентификации и срок действия сессии
        self._last_auth_time = 0
        self._auth_expiry = 3600  # По умолчанию 1 час
        
        # Информация о доступных API
        self._available_apis = {}
        self._api_info_ttl = 0
        
        # Инициализируем API version resolver для автоматического определения совместимых API
        self.api_resolver = None  # Будет создан при необходимости
        
    def login(self) -> bool:
        """Авторизация в API Synology NAS"""
        # Сбрасываем SID для новой сессии
        self.sid = None
        
        logger.info("Attempting to authenticate with Synology NAS...")
        logger.debug(f"Base URL: {self.base_url}")
        
        # Проверяем доступность NAS перед запросом с помощью прямой TCP-проверки
        # Избегаем вызова is_online(), чтобы не создавать рекурсию
        online_status = self._check_tcp_connection()
        if not online_status:
            logger.error("Cannot login: Synology NAS is not reachable")
            return False
            
        # Пробуем различные версии API для аутентификации
        auth_versions_to_try = [6, 3, 2, 1]  # Пробуем от более новых к более старым версиям
        
        for auth_version in auth_versions_to_try:
            try:
                # Определяем путь к API аутентификации
                auth_path = "auth.cgi"  # Значение по умолчанию
                
                # Проверка информации API для определения доступных версий API
                api_info_url = f"{self.base_url}/entry.cgi"
                api_info_params = {
                    "api": "SYNO.API.Info",
                    "version": "1",
                    "method": "query",
                    "query": "SYNO.API.Auth"
                }
                
                logger.debug(f"Querying API info for auth version {auth_version}")
                try:
                    api_info_response = self.session.get(
                        api_info_url,
                        params=api_info_params,
                        timeout=self.default_timeout,
                        verify=False
                    )
                    
                    if api_info_response.status_code == 200:
                        api_info_data = api_info_response.json()
                        if api_info_data.get("success"):
                            auth_info = api_info_data.get("data", {}).get("SYNO.API.Auth", {})
                            max_version = auth_info.get("maxVersion", 6)
                            min_version = auth_info.get("minVersion", 1)
                            auth_path = auth_info.get("path", "auth.cgi")
                            logger.debug(f"Auth API versions: min={min_version}, max={max_version}, path={auth_path}")
                            
                            # Проверяем поддержку текущей версии
                            if auth_version < min_version or auth_version > max_version:
                                logger.warning(f"Auth API version {auth_version} not supported (min={min_version}, max={max_version}), trying next version")
                                continue
                        else:
                            logger.warning("Failed to query API info, using default auth path")
                    else:
                        logger.warning(f"API info request failed with status {api_info_response.status_code}, using default auth path")
                except Exception as e:
                    logger.warning(f"Error querying API info: {str(e)}, using default auth path")
                    
                # Основной запрос авторизации
                url = f"{self.base_url}/{auth_path}"
                params = {
                    "api": "SYNO.API.Auth",
                    "version": str(auth_version),
                    "method": "login",
                    "account": SYNOLOGY_USERNAME,
                    "passwd": SYNOLOGY_PASSWORD,
                    "session": "SynologyPowerControlBot",
                    "format": "cookie"
                }
                
                # Для версии 6+ используем немного другой формат
                if auth_version >= 6:
                    params["enable_syno_token"] = "yes"
                
                logger.debug(f"Sending auth request to {url} with API version {auth_version}")
                start_time = time.time()
                response = self.session.get(
                    url, 
                    params=params, 
                    timeout=self.default_timeout, 
                    verify=False
                )
                elapsed_time = time.time() - start_time
                logger.debug(f"Auth request completed in {elapsed_time:.2f}s with status code {response.status_code}")
                
                # Проверка статуса HTTP
                if response.status_code != 200:
                    logger.error(f"HTTP error: {response.status_code}")
                    logger.debug(f"Response content: {response.text[:200]}")
                    continue  # Пробуем следующую версию
                    
                try:
                    data = response.json()
                except json.JSONDecodeError:
                    logger.error("Failed to decode JSON response")
                    logger.debug(f"Response content: {response.text[:200]}")
                    continue  # Пробуем следующую версию
                
                if data.get("success"):
                    self.sid = data.get("data", {}).get("sid")
                    self._last_auth_time = time.time()
                    logger.info(f"Successfully logged in to Synology NAS using API version {auth_version}")
                    logger.debug(f"Session ID obtained: {self.sid[:5] if self.sid else 'None'}...")
                    
                    # Проверка валидности полученной сессии
                    if not self._validate_session():
                        logger.warning("Session validation failed, trying next auth version")
                        self.sid = None
                        continue
                        
                    return True
                else:
                    error_code = data.get("error", {}).get("code", -1)
                    logger.error(f"Failed to log in with version {auth_version}: Error code {error_code}")
                    
                    # Если ошибка связана с версией API, пробуем следующую версию
                    if error_code in [104, 105]:
                        logger.warning(f"Auth version {auth_version} not supported, trying next version")
                        continue
                    
                    # Дополнительная диагностика
                    if error_code == 400:
                        logger.error("Authentication error: Invalid credentials")
                    elif error_code == 401:
                        logger.error("Authentication error: Account disabled")
                    elif error_code == 402:
                        logger.error("Authentication error: Permission denied")
                    elif error_code == 403:
                        logger.error("Authentication error: 2-factor authentication required")
                    elif error_code == 404:
                        logger.error("Authentication error: Failed to authenticate with 2-factor authentication")
                    
                    # Если ошибка связана с неверными учетными данными, нет смысла пробовать другие версии API
                    if error_code in [400, 401, 402, 403, 404]:
                        return False
                    
            except requests.exceptions.Timeout:
                logger.error(f"Connection timeout during auth with version {auth_version}")
                continue  # Пробуем следующую версию
            except requests.exceptions.ConnectionError as e:
                logger.error(f"Connection error during auth with version {auth_version}: {str(e)}")
                continue  # Пробуем следующую версию
            except requests.RequestException as e:
                logger.error(f"Request error during auth with version {auth_version}: {str(e)}")
                continue  # Пробуем следующую версию
            except Exception as e:
                logger.error(f"Unexpected error during login with version {auth_version}: {str(e)}", exc_info=True)
                continue  # Пробуем следующую версию
                
        # Если все версии не сработали
        logger.error("Failed to authenticate with any API version")
        return False
        
    def _validate_session(self) -> bool:
        """Проверяет валидность сессии после авторизации"""
        if not self.sid:
            return False
            
        # Попробуем сделать простой запрос для проверки сессии
        test_apis = [
            {"api": "SYNO.Core.System", "method": "info", "version": 1},
            {"api": "SYNO.DSM.Info", "method": "getinfo", "version": 1}
        ]
        
        for test_api in test_apis:
            try:
                url = f"{self.base_url}/entry.cgi"
                params = {
                    "api": test_api["api"],
                    "version": str(test_api["version"]),
                    "method": test_api["method"],
                    "_sid": self.sid
                }
                
                response = self.session.get(url, params=params, timeout=self.default_timeout, verify=False)
                
                if response.status_code == 200:
                    data = response.json()
                    if data.get("success"):
                        logger.debug(f"Session validation successful using {test_api['api']}")
                        return True
                    else:
                        error_code = data.get("error", {}).get("code", -1)
                        if error_code != 119:  # Не сессия истекла
                            logger.debug(f"Session validation with {test_api['api']} returned error code {error_code}")
                            return True  # Считаем сессию валидной, если ошибка не связана с истечением сессии
            except Exception as e:
                logger.warning(f"Error during session validation with {test_api['api']}: {str(e)}")
                
        logger.warning("Session validation failed with all test APIs")
        return False
    
    def logout(self) -> bool:
        """Выход из API Synology NAS"""
        if not self.sid:
            return True
            
        try:
            url = f"{self.base_url}/auth.cgi"
            params = {
                "api": "SYNO.API.Auth",
                "version": "1",
                "method": "logout",
                "session": "SynologyPowerControlBot",
                "_sid": self.sid
            }
            
            response = self.session.get(url, params=params, timeout=SYNOLOGY_TIMEOUT, verify=False)
            data = response.json()
            
            if data.get("success"):
                self.sid = None
                logger.info("Successfully logged out from Synology NAS")
                return True
            else:
                error_code = data.get("error", {}).get("code", -1)
                logger.error(f"Failed to log out from Synology NAS: Error code {error_code}")
                return False
                
        except requests.RequestException as e:
            logger.error(f"Connection error: {str(e)}")
            return False
    
    def _make_api_request(self, api_name: str, method: str, version: int = 1, 
                         params: Optional[Dict[str, Any]] = None, retry_auth: bool = True, retry_count: int = 0) -> Optional[Dict[str, Any]]:
        """Обобщенный метод для выполнения API запросов с обработкой ошибок"""
        # Ограничение на количество повторных попыток
        if retry_count >= 3:
            logger.error(f"Too many retries for {api_name}.{method}, giving up")
            return None
            
        # Проверка наличия авторизации
        if not self.sid and not self.login():
            logger.error(f"Not authenticated for API request: {api_name}.{method}")
            return None
            
        # Проверка информации API для определения пути и поддерживаемой версии
        api_info_url = f"{self.base_url}/entry.cgi"
        api_info_params = {
            "api": "SYNO.API.Info",
            "version": "1",
            "method": "query",
            "query": api_name
        }
        
        api_path = "entry.cgi"
        try:
            logger.debug(f"Querying API info for {api_name}")
            api_info_response = self.session.get(
                api_info_url,
                params=api_info_params,
                timeout=self.default_timeout,
                verify=False
            )
            
            if api_info_response.status_code == 200:
                api_info_data = api_info_response.json()
                if api_info_data.get("success"):
                    api_info = api_info_data.get("data", {}).get(api_name, {})
                    if api_info:
                        max_version = api_info.get("maxVersion", version)
                        min_version = api_info.get("minVersion", version)
                        api_path = api_info.get("path", "entry.cgi")
                        
                        # Проверка, поддерживается ли запрошенная версия
                        if version < min_version:
                            logger.warning(f"API version {version} for {api_name} is below minimum {min_version}, using {min_version}")
                            version = min_version
                        elif version > max_version:
                            logger.warning(f"API version {version} for {api_name} exceeds maximum {max_version}, using {max_version}")
                            version = max_version
                            
                        logger.debug(f"Using API path: {api_path}, version: {version}")
                    else:
                        logger.warning(f"API {api_name} not found in API info, using defaults")
        except Exception as e:
            logger.warning(f"Error querying API info for {api_name}: {str(e)}, using defaults")
            
        # Подготовка базовых параметров запроса
        base_params = {
            "api": api_name,
            "version": str(version),
            "method": method,
            "_sid": self.sid  # Используем _sid вместо sid для лучшей совместимости
        }
        
        # Добавление дополнительных параметров, если они заданы
        if params:
            base_params.update(params)
        
        url = f"{self.base_url}/{api_path}"
        logger.debug(f"API request: {api_name}.{method} v{version} to {url}")
        logger.debug(f"Full request params: {base_params}")
        
        try:
            start_time = time.time()
            response = self.session.get(
                url, 
                params=base_params, 
                timeout=self.default_timeout, 
                verify=False
            )
            elapsed_time = time.time() - start_time
            logger.debug(f"API request completed in {elapsed_time:.2f}s with status {response.status_code}")
            
            # Проверка статуса HTTP
            if response.status_code != 200:
                logger.error(f"HTTP error: {response.status_code} for {api_name}.{method}")
                
                # Повторная попытка при ошибках соединения
                if response.status_code in [500, 502, 503, 504]:
                    logger.info(f"Server error, retrying request for {api_name}.{method}")
                    sleep(2)
                    return self._make_api_request(api_name, method, version, params, retry_auth, retry_count + 1)
                    
                return None
                
            try:
                data = response.json()
            except json.JSONDecodeError:
                logger.error(f"Failed to decode JSON response for {api_name}.{method}")
                logger.debug(f"Response content: {response.text[:200]}")
                
                # Повторная попытка при ошибках декодирования
                logger.info(f"JSON decode error, retrying request for {api_name}.{method}")
                sleep(2)
                return self._make_api_request(api_name, method, version, params, retry_auth, retry_count + 1)
                
            if data.get("success"):
                logger.info(f"API request successful for {api_name}.{method}")
                return data.get("data", {})
            else:
                error_code = data.get("error", {}).get("code", -1)
                error_desc = self._get_error_description(error_code)
                logger.error(f"API error for {api_name}.{method}: {error_code} - {error_desc}")
                
                # Ошибки доступа или прав часто встречаются, но они не критичные
                # Например, ошибка 102 означает, что нет прав, но NAS доступен
                if error_code in [102, 103, 104, 105]:
                    logger.warning(f"Permission-related error for {api_name}.{method}: {error_code}")
                    # Возвращаем пустой словарь вместо None,
                    # чтобы вызывающий код мог понять, что запрос выполнен
                    return {}
                
                # Если ошибка связана с авторизацией и нам разрешено повторить попытку
                if error_code in [106, 107, 119] and retry_auth:
                    logger.info(f"Session error (code {error_code}), creating fresh session...")
                    self.sid = None  # Сбрасываем SID
                    
                    # Для ошибки 119 (Session timeout) дадим системе немного времени
                    if error_code == 119:
                        logger.info("Session timeout detected, waiting before retry...")
                        sleep(3)
                        
                    if self.login():
                        logger.info("Re-authenticated with fresh session, retrying API request...")
                        # Рекурсивный вызов, но со счетчиком повторов
                        return self._make_api_request(api_name, method, version, params, False, retry_count + 1)
                
                # Для некоторых ошибок можно автоматически повторить запрос
                if error_code in [408, 429, 500, 502, 503, 504]:
                    logger.info(f"Temporary error {error_code}, retrying request for {api_name}.{method}")
                    sleep(2)
                    return self._make_api_request(api_name, method, version, params, retry_auth, retry_count + 1)
                    
                return None
                
        except requests.exceptions.Timeout:
            logger.error(f"Request timeout for {api_name}.{method}")
            
            # Повторная попытка при таймауте
            if retry_count < 2:
                logger.info(f"Timeout, retrying request for {api_name}.{method}")
                sleep(2)
                return self._make_api_request(api_name, method, version, params, retry_auth, retry_count + 1)
                
            return None
        except requests.exceptions.ConnectionError as e:
            logger.error(f"Connection error for {api_name}.{method}: {str(e)}")
            
            # Повторная попытка при ошибке соединения
            if retry_count < 2:
                logger.info(f"Connection error, retrying request for {api_name}.{method}")
                sleep(2)
                return self._make_api_request(api_name, method, version, params, retry_auth, retry_count + 1)
                
            return None
        except Exception as e:
            logger.error(f"Unexpected error during {api_name}.{method}: {str(e)}")
            return None
    
    def get_system_status(self) -> Dict[str, Any]:
        """Получение статуса системы"""
        # Проверяем доступность системы
        if not self.is_online():
            logger.info("Device is offline, skipping API request")
            return {"status": "offline"}
            
        # Проверяем, есть ли кэшированный результат
        cache_key = "system_status"
        current_time = time.time()
        if cache_key in self._cache and current_time - self._cache_ttl.get(cache_key, 0) < 60:
            logger.debug("Using cached system status")
            return self._cache[cache_key]
        
        # Используем рекомендованный API для получения информации о системе
        logger.info(f"Getting system info using {SYNOLOGY_INFO_API} v{SYNOLOGY_API_VERSION}")
        
        # Для SYNO.DSM.Info метод getinfo, для других обычно используется get или info
        if SYNOLOGY_INFO_API == "SYNO.DSM.Info":
            method = "getinfo"
        else:
            method = "get"
            
        result = self._make_api_request(SYNOLOGY_INFO_API, method, version=SYNOLOGY_API_VERSION)
        
        if result:
            logger.info(f"Successfully retrieved system info using {SYNOLOGY_INFO_API}")
            
            # Формируем расширенный ответ с дополнительной информацией
            system_info = {
                "status": "online",
                "hostname": result.get("hostname", "unknown"),
                "model": result.get("model", "unknown"),
                "version": result.get("version", "unknown"),
                "uptime": result.get("uptime", 0),
                "time": current_time,
                "is_online": True,
                "api_used": SYNOLOGY_INFO_API
            }
            
            # Сохраняем в кэше
            self._cache[cache_key] = system_info
            self._cache_ttl[cache_key] = current_time
            
            return system_info
                
        # Если основной API не сработал, пробуем резервные варианты
        logger.warning(f"Failed to retrieve system info with {SYNOLOGY_INFO_API}, trying fallback APIs")
        
        # Пробуем резервные API
        apis_to_try = [
            {"name": "SYNO.DSM.Info", "method": "getinfo", "version": 2},
            {"name": "SYNO.Core.System", "method": "info", "version": 1},
            {"name": "SYNO.Core.System.Status", "method": "get", "version": 1},
            {"name": "SYNO.Core.System.Info", "method": "get", "version": 1},
        ]
        
        for api in apis_to_try:
            if api["name"] == SYNOLOGY_INFO_API:
                continue  # Пропускаем уже проверенный API
                
            logger.info(f"Trying to get system info using {api['name']}.{api['method']} v{api['version']}")
            result = self._make_api_request(api["name"], api["method"], version=api["version"])
            
            if result:
                logger.info(f"Successfully retrieved system info using {api['name']}")
                
                # Формируем расширенный ответ с дополнительной информацией
                system_info = {
                    "status": "online",
                    "hostname": result.get("hostname", "unknown"),
                    "model": result.get("model", "unknown"),
                    "version": result.get("version", "unknown"),
                    "uptime": result.get("uptime", 0),
                    "time": current_time,
                    "is_online": True,
                    "api_used": api["name"]
                }
                
                # Сохраняем в кэше
                self._cache[cache_key] = system_info
                self._cache_ttl[cache_key] = current_time
                
                return system_info
        
        # Если все запросы не удались, но система онлайн, возвращаем базовую информацию
        logger.warning("Failed to retrieve system info with all API methods")
        return {
            "status": "error", 
            "error": "Failed to fetch system information",
            "is_online": True,
            "time": current_time
        }
    
    def shutdown_system(self) -> bool:
        """Выключение системы"""
        # Проверяем, включено ли устройство перед попыткой его выключить
        if not self.is_online(force_check=True):
            logger.info("Synology NAS is already offline, no need to shut down")
            return True
            
        logger.info("Attempting to shutdown Synology NAS...")
        
        # Попробуем сначала использовать предпочтительный API для управления питанием
        logger.info(f"Trying shutdown with {SYNOLOGY_POWER_API} v{SYNOLOGY_API_VERSION}")
        
        # Для SYNO.Core.Hardware.PowerRecovery используется метод setPowerOnState
        # Для других API обычно используется метод shutdown или reboot
        if SYNOLOGY_POWER_API == "SYNO.Core.Hardware.PowerRecovery":
            # Для этого API нужны специальные параметры
            params = {"state": "powerbtn"}  # powerbtn имитирует нажатие кнопки питания
            result = self._make_api_request(SYNOLOGY_POWER_API, "setPowerOnState", version=SYNOLOGY_API_VERSION, params=params)
        else:
            # Пробуем стандартный метод
            result = self._make_api_request(SYNOLOGY_POWER_API, "shutdown", version=SYNOLOGY_API_VERSION)
        
        if result is not None:
            logger.info(f"Successfully initiated system shutdown using {SYNOLOGY_POWER_API}")
            
            # Даем системе время начать процесс выключения
            logger.info("Waiting for shutdown to initialize...")
            sleep(5)
            
            # Проверяем статус
            if not self.is_online(force_check=True):
                logger.info("System is now offline. Shutdown confirmed successful.")
                return True
            else:
                logger.info("System still appears to be online, but shutdown may be in progress.")
                return True
        else:
            logger.warning(f"Failed to shutdown using {SYNOLOGY_POWER_API}, trying alternative methods")
            
            # Если не сработал основной метод, пробуем резервные варианты
            # Проверка всех доступных методов API для выключения
            apis_to_try = [
                {"name": "SYNO.Core.System", "method": "shutdown", "version": 3},
                {"name": "SYNO.Core.System.Power", "method": "shutdown", "version": 1},
                {"name": "SYNO.DSM.Power", "method": "shutdown", "version": 1},
                {"name": "SYNO.System.Power", "method": "shutdown", "version": 1},
                {"name": "SYNO.DSM.System", "method": "shutdown", "version": 1}
            ]
            
            # Проверяем доступные API
            try:
                api_info_url = f"{self.base_url}/entry.cgi"
                api_info_params = {
                    "api": "SYNO.API.Info",
                    "version": "1",
                    "method": "query",
                    "query": "SYNO.Core.System.Power,SYNO.DSM.Power,SYNO.Core.System,SYNO.System.Power,SYNO.DSM.System"
                }
                
                logger.debug("Checking available shutdown APIs")
                api_info_response = self.session.get(
                    api_info_url,
                    params=api_info_params,
                    timeout=self.default_timeout,
                    verify=False
                )
                
                if api_info_response.status_code == 200:
                    api_info_data = api_info_response.json()
                    if api_info_data.get("success"):
                        available_apis = api_info_data.get("data", {})
                        logger.debug(f"Available APIs: {list(available_apis.keys())}")
                        
                        # Фильтруем только доступные API
                        filtered_apis = []
                        for api in apis_to_try:
                            if api["name"] in available_apis:
                                api_info = available_apis[api["name"]]
                                # Проверка версии API
                                if api_info.get("minVersion", 1) <= api["version"] <= api_info.get("maxVersion", 1):
                                    filtered_apis.append(api)
                                    logger.debug(f"Adding {api['name']} to available shutdown APIs")
                                else:
                                    logger.debug(f"API {api['name']} version {api['version']} not supported. Supported: {api_info.get('minVersion')}-{api_info.get('maxVersion')}")
                        
                        if filtered_apis:
                            apis_to_try = filtered_apis
                        else:
                            logger.warning("No compatible APIs found, trying all methods as fallback")
                    else:
                        logger.warning("Failed to query API info, using default methods")
                else:
                    logger.warning(f"API info request failed with status {api_info_response.status_code}, using default methods")
            except Exception as e:
                logger.warning(f"Error querying API info: {str(e)}, using default methods")
            
            # Пробуем все доступные методы по порядку
            for api in apis_to_try:
                logger.info(f"Trying shutdown with {api['name']}.{api['method']} v{api['version']}")
                result = self._make_api_request(api["name"], api["method"], version=api["version"])
                
                if result is not None:
                    logger.info(f"Successfully initiated system shutdown using {api['name']}")
                    
                    # Даем системе время начать процесс выключения
                    logger.info("Waiting for shutdown to initialize...")
                    sleep(5)
                    
                    # Проверяем статус
                    if not self.is_online(force_check=True):
                        logger.info("System is now offline. Shutdown confirmed successful.")
                        return True
                    else:
                        logger.info("System still appears to be online, but shutdown may be in progress.")
                        return True
                else:
                    logger.warning(f"Failed to shutdown using {api['name']}.{api['method']} v{api['version']}")
            
            # Если ни один метод не сработал, но система стала недоступна
            if not self.is_online(force_check=True):
                logger.info("System appears to be shutting down despite API errors")
                return True
                
            logger.error("Failed to shutdown system after trying multiple APIs")
            return False
    
    def reboot_system(self) -> bool:
        """Перезагрузка системы"""
        # Проверяем, включена ли система
        if not self.is_online(force_check=True):
            logger.error("Cannot reboot: System is offline")
            return False
        
        logger.info("Attempting to reboot Synology NAS...")
        
        # Попробуем сначала использовать предпочтительный API для управления питанием
        logger.info(f"Trying reboot with {SYNOLOGY_POWER_API} v{SYNOLOGY_API_VERSION}")
        
        # Для SYNO.Core.Hardware.PowerRecovery используется метод setPowerOnState или powerButton
        # Для других API обычно используется метод restart или reboot
        if SYNOLOGY_POWER_API == "SYNO.Core.Hardware.PowerRecovery":
            # Для этого API нужны специальные параметры
            params = {"reboot": "true"}  # Передаем флаг для перезагрузки
            result = self._make_api_request(SYNOLOGY_POWER_API, "setPowerOnState", version=SYNOLOGY_API_VERSION, params=params)
        else:
            # Пробуем стандартный метод
            methods_to_try = ["restart", "reboot"]
            result = None
            for method in methods_to_try:
                result = self._make_api_request(SYNOLOGY_POWER_API, method, version=SYNOLOGY_API_VERSION)
                if result is not None:
                    logger.info(f"Successfully used method {method} for {SYNOLOGY_POWER_API}")
                    break
        
        if result is not None:
            logger.info(f"Successfully initiated system reboot using {SYNOLOGY_POWER_API}")
            
            # Даем системе время начать процесс перезагрузки
            logger.info("Waiting for reboot to initialize...")
            sleep(5)
            
            # Ждем, пока система станет недоступна (признак перезагрузки)
            reboot_started = False
            for i in range(12):  # Проверяем в течение 60 секунд (12 * 5сек)
                if not self.is_online(force_check=True):
                    logger.info(f"System went offline after {i*5} seconds, reboot in progress")
                    reboot_started = True
                    break
                logger.debug(f"System still online, waiting... ({i+1}/12)")
                sleep(5)
                
            if reboot_started:
                # Ждем, пока система снова станет доступна
                logger.info("Waiting for system to come back online...")
                return self.wait_for_boot(max_attempts=30, delay=10)
            else:
                logger.warning("System did not go offline after reboot command, but command was accepted")
                # Даже если система не ушла оффлайн, команда могла быть принята
                return True
        else:
            logger.warning(f"Failed to reboot using {SYNOLOGY_POWER_API}, trying alternative methods")
            
            # Если не сработал основной метод, пробуем резервные варианты
            # Проверка всех доступных методов API для перезагрузки
            apis_to_try = [
                {"name": "SYNO.Core.System.Power", "method": "restart", "version": 1},
                {"name": "SYNO.DSM.Power", "method": "reboot", "version": 1},
                {"name": "SYNO.Core.System", "method": "reboot", "version": 3},
                {"name": "SYNO.System.Power", "method": "reboot", "version": 1},
                {"name": "SYNO.DSM.System", "method": "reboot", "version": 1},
                {"name": "SYNO.Core.Hardware.NeedReboot", "method": "reboot", "version": 1}
            ]
            
            # Получаем список доступных API
            try:
                api_info_url = f"{self.base_url}/entry.cgi"
                api_info_params = {
                    "api": "SYNO.API.Info",
                    "version": "1",
                    "method": "query",
                    "query": "SYNO.Core.System.Power,SYNO.DSM.Power,SYNO.Core.System,SYNO.System.Power,SYNO.DSM.System,SYNO.Core.Hardware.NeedReboot"
                }
                
                logger.debug("Checking available reboot APIs")
                api_info_response = self.session.get(
                    api_info_url,
                    params=api_info_params,
                    timeout=self.default_timeout,
                    verify=False
                )
                
                if api_info_response.status_code == 200:
                    api_info_data = api_info_response.json()
                    if api_info_data.get("success"):
                        available_apis = api_info_data.get("data", {})
                        logger.debug(f"Available APIs: {list(available_apis.keys())}")
                        
                        # Фильтруем только доступные API
                        filtered_apis = []
                        for api in apis_to_try:
                            if api["name"] in available_apis:
                                api_info = available_apis[api["name"]]
                                # Проверка версии API
                                if api_info.get("minVersion", 1) <= api["version"] <= api_info.get("maxVersion", 1):
                                    filtered_apis.append(api)
                                    logger.debug(f"Adding {api['name']} to available reboot APIs")
                                else:
                                    logger.debug(f"API {api['name']} version {api['version']} not supported. Supported: {api_info.get('minVersion')}-{api_info.get('maxVersion')}")
                        
                        if filtered_apis:
                            apis_to_try = filtered_apis
                        else:
                            logger.warning("No compatible APIs found, trying all methods as fallback")
                    else:
                        logger.warning("Failed to query API info, using default methods")
                else:
                    logger.warning(f"API info request failed with status {api_info_response.status_code}, using default methods")
            except Exception as e:
                logger.warning(f"Error querying API info: {str(e)}, using default methods")
            
            # Пробуем все доступные методы по порядку
            for api in apis_to_try:
                logger.info(f"Trying reboot with {api['name']}.{api['method']} v{api['version']}")
                result = self._make_api_request(api["name"], api["method"], version=api["version"])
                
                if result is not None:
                    logger.info(f"Successfully initiated system reboot using {api['name']}")
                    
                    # Даем системе время начать процесс перезагрузки
                    logger.info("Waiting for reboot to initialize...")
                    sleep(5)
                    
                    # Ждем, пока система станет недоступна (признак перезагрузки)
                    reboot_started = False
                    for i in range(12):  # Проверяем в течение 60 секунд (12 * 5сек)
                        if not self.is_online(force_check=True):
                            logger.info(f"System went offline after {i*5} seconds, reboot in progress")
                            reboot_started = True
                            break
                        logger.debug(f"System still online, waiting... ({i+1}/12)")
                        sleep(5)
                        
                    if reboot_started:
                        # Ждем, пока система снова станет доступна
                        logger.info("Waiting for system to come back online...")
                        return self.wait_for_boot(max_attempts=30, delay=10)
                    else:
                        logger.warning("System did not go offline after reboot command, but command was accepted")
                        # Даже если система не ушла оффлайн, команда могла быть принята
                        return True
                else:
                    logger.warning(f"Failed to reboot using {api['name']}.{api['method']} v{api['version']}")
            
            logger.error("Failed to reboot system after trying multiple APIs")
            return False
    
    def _get_error_description(self, error_code: int) -> str:
        """Получение описания ошибки по коду"""
        error_descriptions = {
            100: "Unknown error",
            101: "Invalid parameter",
            102: "API does not exist",
            103: "Method does not exist",
            104: "Version does not support",
            105: "Permission denied",
            106: "Session timeout",
            107: "Session interrupted by duplicate login",
            400: "Invalid credentials",
            401: "Account disabled",
            402: "Permission denied",
            403: "2FA required",
            404: "Failed to authenticate with 2FA"
        }
        return error_descriptions.get(error_code, "Unknown error code")
        
    def _check_tcp_connection(self) -> bool:
        """Проверка базового TCP-соединения с Synology NAS"""
        try:
            socket_obj = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            socket_obj.settimeout(SYNOLOGY_TIMEOUT)
            result = socket_obj.connect_ex((SYNOLOGY_HOST, SYNOLOGY_PORT))
            socket_obj.close()
            
            return result == 0
        except socket.error as e:
            logger.error(f"Socket error during connection check: {str(e)}")
            return False
        except Exception as e:
            logger.error(f"Unexpected error during connection check: {str(e)}")
            return False
            
    def is_online(self, force_check=False) -> bool:
        """Проверка онлайн-статуса Synology NAS"""
        # Используем кэшированное значение, если доступно и не устарело
        current_time = time.time()
        if not force_check and (current_time - self._last_online_check) < self._online_check_interval:
            logger.debug(f"Using cached online status: {self._last_online_status}")
            return self._last_online_status
            
        logger.info("Checking if NAS is online...")
        
        # Проверяем TCP-соединение
        online_status = self._check_tcp_connection()
        logger.info(f"Detected Synology NAS online status: {online_status}")
        
        # Если TCP-соединение успешно и у нас есть действующий SID,
        # попробуем более детальную проверку через API
        if online_status and self.sid:
            logger.info("Trying to fetch more detailed online status through API...")
            
            # Пробуем разные API для проверки онлайн-статуса
            api_checks = [
                {"api": "SYNO.DSM.Info", "version": "2", "method": "getinfo"},
                {"api": "SYNO.Core.System", "version": "1", "method": "info"},
                {"api": "SYNO.Core.System.Status", "version": "1", "method": "get"}
            ]
            
            api_success = False
            for api_check in api_checks:
                try:
                    url = f"{self.base_url}/entry.cgi"
                    params = {
                        "api": api_check["api"],
                        "version": api_check["version"],
                        "method": api_check["method"],
                        "sid": self.sid
                    }
                    
                    logger.debug(f"Trying online status check with {api_check['api']}")
                    response = self.session.get(
                        url, 
                        params=params, 
                        timeout=self.default_timeout, 
                        verify=False
                    )
                    
                    if response.status_code == 200:
                        data = response.json()
                        if data.get("success"):
                            logger.info(f"API request successful for {api_check['api']}")
                            logger.info("Synology NAS is online with API access")
                            api_success = True
                            break
                        else:
                            error_code = data.get("error", {}).get("code", -1)
                            logger.warning(f"API response indicates an error: {error_code}, but NAS is reachable")
                    else:
                        logger.warning(f"API returned status code {response.status_code}")
                except Exception as e:
                    logger.warning(f"API check failed for {api_check['api']}, but TCP connection succeeded: {str(e)}")
            
            if not api_success:
                logger.warning("All API checks failed, but TCP connection is successful")
        
        # Обновляем кэшированное значение
        self._last_online_check = current_time
        self._last_online_status = online_status
        
        return online_status
    
    def wake_on_lan(self) -> bool:
        """Отправка Wake-on-LAN пакета для включения Synology NAS"""
        if not SYNOLOGY_MAC:
            logger.error("MAC address not configured")
            return False
            
        try:
            # Преобразование MAC-адреса в байты
            mac_address = SYNOLOGY_MAC.replace(':', '').replace('-', '')
            if len(mac_address) != 12:
                logger.error(f"Invalid MAC address format: {SYNOLOGY_MAC}")
                return False
                
            try:
                mac_bytes = bytes.fromhex(mac_address)
            except ValueError as e:
                logger.error(f"Failed to parse MAC address: {str(e)}")
                logger.error(f"MAC address must contain only hex characters: {SYNOLOGY_MAC}")
                return False
            
            # Создание Magic Packet
            magic_packet = b'\xff' * 6 + mac_bytes * 16
            
            # Отправка пакета на конкретный адрес
            try:
                sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
                sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
                sock.sendto(magic_packet, (SYNOLOGY_HOST, WOL_PORT))
                sock.close()
                logger.info(f"Wake-on-LAN packet sent to {SYNOLOGY_MAC} at {SYNOLOGY_HOST}:{WOL_PORT}")
            except Exception as e:
                logger.error(f"Error sending directed WoL packet: {str(e)}")
                return False
                
            # Для надежности отправляем также широковещательный пакет
            try:
                sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
                sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
                
                # Используем стандартный широковещательный адрес
                broadcast_addr = "255.255.255.255"
                sock.sendto(magic_packet, (broadcast_addr, WOL_PORT))
                sock.close()
                logger.info(f"Wake-on-LAN broadcast packet sent to {broadcast_addr}:{WOL_PORT}")
            except Exception as e:
                logger.warning(f"Error sending broadcast WoL packet (non-critical): {str(e)}")
                # Не считаем ошибкой, т.к. основной пакет уже отправлен
                
            return True
            
        except Exception as e:
            logger.error(f"Unexpected error in wake_on_lan: {str(e)}")
            return False
            
    def wait_for_boot(self, max_attempts: int = 30, delay: int = 10) -> bool:
        """Ожидание загрузки Synology NAS"""
        logger.info(f"Waiting for Synology NAS to boot (timeout: {max_attempts * delay}s)...")
        
        for attempt in range(max_attempts):
            # Принудительно проверяем статус без использования кэша
            if self.is_online(force_check=True):
                logger.info(f"Synology NAS is online after {attempt + 1} attempts ({(attempt + 1) * delay}s)")
                
                # Проверяем, что не только сеть доступна, но и API загрузился
                api_ready = False
                logger.info("Waiting for API services to initialize...")
                
                for api_check in range(5):  # Даем еще до 50 секунд для загрузки API
                    if self.sid or self.login():
                        api_ready = True
                        logger.info(f"API services are ready after {api_check + 1} attempts")
                        break
                    logger.debug(f"API not ready yet, waiting... ({api_check + 1}/5)")
                    sleep(10)
                
                if not api_ready:
                    logger.warning("System is online but API services may not be fully initialized")
                    
                # Дадим дополнительное время для полной загрузки всех сервисов
                sleep(delay)
                return True
                
            sleep(delay)
            logger.info(f"Waiting for boot... Attempt {attempt + 1}/{max_attempts}")
            
        logger.error(f"Synology NAS didn't come online after {max_attempts * delay} seconds")
        return False
        
    def power_on(self) -> bool:
        """Включение Synology NAS"""
        # Принудительная проверка статуса
        if self.is_online(force_check=True):
            logger.info("Synology NAS is already online")
            return True
        
        logger.info("Powering on Synology NAS via Wake-on-LAN...")
        
        # Проверяем, настроен ли MAC-адрес
        if not SYNOLOGY_MAC:
            logger.error("Cannot power on: MAC address not configured in settings")
            return False
            
        # Пробуем отправить несколько WoL пакетов для надежности
        success = False
        for attempt in range(3):
            logger.debug(f"Sending WoL packet, attempt {attempt + 1}/3")
            if self.wake_on_lan():
                success = True
                break
            sleep(1)
            
        if not success:
            logger.error("Failed to send Wake-on-LAN packets")
            return False
        
        # Ожидание загрузки
        logger.info("WoL packets sent successfully, waiting for system to boot...")
        boot_result = self.wait_for_boot(max_attempts=30, delay=10)
        
        if boot_result:
            # Проверяем доступность API после загрузки
            system_status = self.get_system_status()
            if system_status.get("status") == "online":
                logger.info("System booted successfully with API access")
                return True
            else:
                logger.warning("System appears to be online but API may not be fully ready")
                return True
        else:
            logger.error("System did not come online after WoL")
            return False
        
    def power_off(self) -> bool:
        """Выключение Synology NAS"""
        if not self.is_online(force_check=True):
            logger.info("Synology NAS is already offline")
            return True
        
        logger.info("Powering off Synology NAS...")
        result = self.shutdown_system()
        
        if result:
            # Дополнительная проверка, что система действительно выключилась
            logger.info("Verifying system is offline...")
            for attempt in range(12):  # Проверяем в течение 2 минут (12 * 10 сек)
                if not self.is_online(force_check=True):
                    logger.info(f"System confirmed offline after {attempt * 10} seconds")
                    return True
                logger.debug(f"System still shutting down, checking again... ({attempt + 1}/12)")
                sleep(10)
                
            logger.warning("System still appears to be online after shutdown command")
            return False
        else:
            logger.error("Failed to initiate shutdown")
            return False
        
    # Заглушки для расширенных методов
    def get_shared_folders(self) -> List[Dict[str, Any]]:
        """Получение списка общих папок (заглушка)"""
        logger.warning("Function get_shared_folders() is not implemented yet")
        return []
        
    def get_system_load(self) -> Dict[str, Any]:
        """Получение информации о загрузке системы (заглушка)"""
        logger.warning("Function get_system_load() is not implemented yet")
        return {}
        
    def get_storage_status(self) -> Dict[str, Any]:
        """Получение подробной информации о хранилище (заглушка)"""
        logger.warning("Function get_storage_status() is not implemented yet")
        
        # Аутентифицируемся перед запросом данных
        if not self.sid and not self.login():
            logger.error("Failed to authenticate for storage status request")
            return {"error": "authentication_failed"}
            
        try:
            # Здесь будет реализация после добавления соответствующего API
            url = f"{self.base_url}/entry.cgi"
            params = {
                "api": "SYNO.Storage.CGI.Storage",
                "version": "1",
                "method": "load_info",
                "sid": self.sid
            }
            
            # В текущей версии просто возвращаем заглушку
            return {
                "volumes": [],
                "disks": [],
                "total_size": 0,
                "total_used": 0,
                "error": "not_implemented"
            }
        except Exception as e:
            logger.error(f"Error in get_storage_status: {str(e)}")
            return {"error": str(e)}
        
    def get_security_status(self) -> Dict[str, Any]:
        """Получение информации о состоянии безопасности (заглушка)"""
        logger.warning("Function get_security_status() is not implemented yet")
        
        # Аутентифицируемся перед запросом данных
        if not self.sid and not self.login():
            logger.error("Failed to authenticate for security status request")
            return {"success": False, "error": "authentication_failed"}
            
        try:
            # Здесь будет реализация после добавления соответствующего API
            url = f"{self.base_url}/entry.cgi"
            params = {
                "api": "SYNO.Core.SecurityScan.Status",
                "version": "1",
                "method": "get",
                "sid": self.sid
            }
            
            # В текущей версии просто возвращаем заглушку
            return {
                "success": False,
                "status": "not_implemented",
                "last_check": None,
                "is_secure": False,
                "error": "not_implemented"
            }
        except Exception as e:
            logger.error(f"Error in get_security_status: {str(e)}")
            return {"success": False, "error": str(e)}
