import json
import yaml
import os
import logging
from datetime import datetime, timedelta
from pathlib import Path
from typing import Dict

logger = logging.getLogger("lightrag")

def load_config():
    with open('config.yaml', 'r', encoding='utf-8') as f:
        return yaml.safe_load(f)

class ProjectStateManager:
    """Управление состоянием синхронизации и расписанием перестройки проектов"""
    
    def __init__(self):
        self.sync_state_file = "data/sync_state.json"
        self.config = load_config()
        
        # Интервалы из конфига
        self.periodic_interval_hours = self.config.get('sync', {}).get('periodic_interval_hours')
        self.rebuild_check_interval_hours = self.config.get('sync', {}).get('rebuild_check_interval_hours', 1.0)
        self.full_rebuild_interval_days = self.config.get('sync', {}).get('full_rebuild_interval_days', 30)
        
        logger.info(f"📋 Инициализация StateManager: синхронизация каждые {self.periodic_interval_hours}ч, "
                   f"проверка перестройки каждые {self.rebuild_check_interval_hours}ч, "
                   f"интервал перестройки {self.full_rebuild_interval_days} дней")
    
    def get_last_sync_time(self) -> datetime:
        """Получает ГЛОБАЛЬНОЕ время последней синхронизации (для запроса списка проектов)"""
        state = self._load_sync_state()
        
        last_sync_str = state.get("last_sync")
        if last_sync_str:
            try:
                return datetime.fromisoformat(last_sync_str.replace('Z', '+00:00'))
            except Exception as e:
                logger.warning(f"Ошибка парсинга времени последней синхронизации: {e}")
        
        # По умолчанию берем сутки назад
        return datetime.utcnow() - timedelta(hours=24)
    
    def save_last_sync_time(self, timestamp: datetime):
        """Сохраняет ГЛОБАЛЬНОЕ время последней синхронизации"""
        state = self._load_sync_state()
        
        state["last_sync"] = timestamp.isoformat() + "Z"
        state["last_sync_human"] = timestamp.strftime("%Y-%m-%d %H:%M:%S UTC")
        
        self._save_sync_state(state)
        logger.info(f"📅 Сохранено ГЛОБАЛЬНОЕ время последней синхронизации: {state['last_sync_human']}")
    
    # ========== НОВЫЕ МЕТОДЫ ДЛЯ PER-PROJECT СИНХРОНИЗАЦИИ ==========
    
    def get_project_sync_time(self, project_id: str) -> datetime:
        """
        Получает время последней синхронизации КОНКРЕТНОГО проекта
        
        Args:
            project_id: ID проекта
            
        Returns:
            datetime: время последней синхронизации этого проекта
        """
        state = self._load_sync_state()
        
        project_syncs = state.get("project_syncs", {})
        
        if project_id in project_syncs:
            last_sync_str = project_syncs[project_id].get("last_sync")
            if last_sync_str:
                try:
                    sync_time = datetime.fromisoformat(last_sync_str.replace('Z', '+00:00'))
                    logger.debug(f"📅 Проект {project_id}: последняя синхронизация {sync_time}")
                    return sync_time
                except Exception as e:
                    logger.warning(f"Ошибка парсинга времени синхронизации проекта {project_id}: {e}")
        
        # Если проект новый или время не сохранено - используем глобальное
        global_time = self.get_last_sync_time()
        logger.info(f"🆕 Проект {project_id}: используем глобальное время синхронизации {global_time}")
        return global_time
    
    def save_project_sync_time(self, project_id: str, timestamp: datetime):
        """
        Сохраняет время последней синхронизации для конкретного проекта
        
        Args:
            project_id: ID проекта
            timestamp: время синхронизации
        """
        state = self._load_sync_state()
        
        if "project_syncs" not in state:
            state["project_syncs"] = {}
        
        state["project_syncs"][project_id] = {
            "last_sync": timestamp.isoformat() + "Z",
            "last_sync_human": timestamp.strftime("%Y-%m-%d %H:%M:%S UTC")
        }
        
        self._save_sync_state(state)
        logger.info(f"📅 Обновлено время синхронизации проекта {project_id}: {state['project_syncs'][project_id]['last_sync_human']}")
    
    # ========== МЕТОДЫ ДЛЯ РАСПИСАНИЯ ПЕРЕСТРОЙКИ ==========
    
    def ensure_project_in_rebuild_schedule(self, project_id: str) -> bool:
        """
        Добавляет проект в расписание перестройки, если его там нет
        
        Returns:
            bool: True если проект был добавлен, False если уже существовал
        """
        state = self._load_sync_state()
        
        # Инициализируем секцию rebuild_schedule если её нет
        if "rebuild_schedule" not in state:
            state["rebuild_schedule"] = {}
        
        # Если проекта нет в расписании - добавляем
        if project_id not in state["rebuild_schedule"]:
            current_time = datetime.utcnow()
            state["rebuild_schedule"][project_id] = {
                "last_full_rebuild": current_time.isoformat() + "Z"
            }
            
            self._save_sync_state(state)
            logger.info(f"🆕 Добавлен новый проект {project_id} в расписание перестройки")
            
            return True  # Проект был добавлен
        
        return False  # Проект уже был в расписании
    
    def get_projects_needing_rebuild(self) -> list[str]:
        """
        Возвращает список проектов, которым нужна полная перестройка
        
        Returns:
            list[str]: список project_id, которым нужна перестройка
        """
        try:
            state = self._load_sync_state()
            rebuild_schedule = state.get("rebuild_schedule", {})
            
            if not rebuild_schedule:
                return []
            
            interval_seconds = self.full_rebuild_interval_days * 24 * 3600
            current_time = datetime.utcnow()
            projects_to_rebuild = []
            
            for project_id, rebuild_info in rebuild_schedule.items():
                try:
                    last_rebuild_str = rebuild_info.get("last_full_rebuild")
                    if not last_rebuild_str:
                        logger.info(f"⚠️ Проект {project_id}: нет информации о последней перестройке")
                        continue
                    
                    last_rebuild = datetime.fromisoformat(last_rebuild_str.replace('Z', '+00:00'))
                    time_diff = current_time - last_rebuild.replace(tzinfo=None)
                    seconds_since = time_diff.total_seconds()
                    
                    if seconds_since >= interval_seconds:
                        projects_to_rebuild.append(project_id)
                        logger.info(f"🔥 Проект {project_id} нуждается в перестройке (прошло {seconds_since:.1f}s >= {interval_seconds:.1f}s)")
                    else:
                        remaining_seconds = interval_seconds - seconds_since
                        logger.debug(f"⏰ Проект {project_id}: перестройка через {remaining_seconds:.1f}s")
                        
                except Exception as e:
                    logger.error(f"⚠️ Ошибка проверки проекта {project_id}: {e}")
            
            return projects_to_rebuild
            
        except Exception as e:
            logger.error(f"❌ Ошибка при проверке проектов для перестройки: {e}")
            return []
    
    def update_project_rebuild_time(self, project_id: str, rebuild_time: datetime):
        """Обновляет время последней полной перестройки для проекта"""
        state = self._load_sync_state()
        
        if "rebuild_schedule" not in state:
            state["rebuild_schedule"] = {}
        
        state["rebuild_schedule"][project_id] = {
            "last_full_rebuild": rebuild_time.isoformat() + "Z"
        }
        
        self._save_sync_state(state)
        logger.info(f"📅 Обновлено время полной перестройки для {project_id}: {rebuild_time}")
    
    def get_rebuild_status_info(self) -> Dict:
        """Возвращает подробную информацию о статусе перестройки для API"""
        try:
            state = self._load_sync_state()
            rebuild_schedule = state.get("rebuild_schedule", {})
            rebuild_info = {}
            
            if rebuild_schedule:
                interval_seconds = self.full_rebuild_interval_days * 24 * 3600
                current_time = datetime.utcnow()
                
                for project_id, info in rebuild_schedule.items():
                    try:
                        last_rebuild_str = info.get("last_full_rebuild")
                        if last_rebuild_str:
                            last_rebuild = datetime.fromisoformat(last_rebuild_str.replace('Z', '+00:00'))
                            time_diff = current_time - last_rebuild.replace(tzinfo=None)
                            seconds_since = time_diff.total_seconds()
                            
                            # Для отображения переводим обратно в дни (с дробной частью)
                            days_since_precise = seconds_since / (24 * 3600)
                            seconds_until_rebuild = max(0, interval_seconds - seconds_since)
                            days_until_rebuild_precise = seconds_until_rebuild / (24 * 3600)
                            
                            rebuild_info[project_id] = {
                                "last_full_rebuild": last_rebuild.strftime("%Y-%m-%d %H:%M:%S UTC"),
                                "days_since_rebuild": round(days_since_precise, 6),
                                "days_until_rebuild": round(days_until_rebuild_precise, 6),
                                "seconds_since_rebuild": int(seconds_since),
                                "seconds_until_rebuild": int(seconds_until_rebuild),
                                "rebuild_needed": seconds_since >= interval_seconds
                            }
                    except Exception as e:
                        logger.error(f"Ошибка обработки информации о перестройке {project_id}: {e}")
            
            return rebuild_info
            
        except Exception as e:
            logger.error(f"Ошибка получения статуса перестройки: {e}")
            return {}
    
    # ========== ВНУТРЕННИЕ МЕТОДЫ ==========
    
    def _load_sync_state(self) -> Dict:
        """Загружает полное состояние синхронизации"""
        try:
            if Path(self.sync_state_file).exists():
                with open(self.sync_state_file, 'r') as f:
                    return json.load(f)
        except Exception as e:
            logger.warning(f"Ошибка чтения состояния синхронизации: {e}")
        
        # Возвращаем пустое состояние по умолчанию
        return {
            "last_sync": None,
            "last_sync_human": "Никогда",
            "rebuild_schedule": {},
            "project_syncs": {}  # НОВОЕ поле
        }

    def _save_sync_state(self, state: Dict):
        """Сохраняет полное состояние синхронизации"""
        try:
            os.makedirs(os.path.dirname(self.sync_state_file), exist_ok=True)
            
            with open(self.sync_state_file, 'w') as f:
                json.dump(state, f, indent=2)
                
        except Exception as e:
            logger.error(f"Ошибка сохранения состояния: {e}")
