"""
Servicio de Backup Básico
Versión simplificada para Fase 1 sin Everything API
"""

import os
import logging
import hashlib
from datetime import datetime
from pathlib import Path
from typing import List, Dict, Any


class BasicBackupService:
    """Servicio básico de backup sin Everything API"""

    def __init__(self, config):
        self.config = config
        self.logger = logging.getLogger(__name__)

    def check_system_requirements(self) -> bool:
        """Verificar requerimientos básicos del sistema"""
        try:
            # Verificar directorio de backup
            backup_dest = self.config.backup_destination
            if not os.path.exists(backup_dest):
                self.logger.error(f"Directorio de backup no existe: {backup_dest}")
                return False

            # Verificar directorios de observación
            obs_dirs = self.config.observation_directories
            for obs_dir in obs_dirs:
                if obs_dir.get("enabled", True):
                    path = obs_dir["path"]
                    if not os.path.exists(path):
                        self.logger.warning(
                            f"Directorio de observación no existe: {path}"
                        )

            self.logger.info("Requerimientos básicos del sistema verificados")
            return True

        except Exception as e:
            self.logger.error(f"Error verificando requerimientos: {e}")
            return False

    def discover_projects_basic(self) -> List[Dict[str, Any]]:
        """Descubrimiento básico de proyectos usando búsqueda de archivos"""
        projects = []

        try:
            obs_dirs = [
                obs_dir
                for obs_dir in self.config.observation_directories
                if obs_dir.get("enabled", True) and obs_dir.get("type") == "siemens_s7"
            ]

            for obs_dir in obs_dirs:
                self.logger.info(f"Buscando proyectos S7 en: {obs_dir['path']}")

                # Buscar archivos .s7p recursivamente
                base_path = Path(obs_dir["path"])
                if base_path.exists():
                    s7p_files = list(base_path.rglob("*.s7p"))

                    for s7p_file in s7p_files:
                        project_info = self._create_project_info(s7p_file, obs_dir)
                        projects.append(project_info)
                        self.logger.info(f"Proyecto encontrado: {project_info['name']}")

            self.logger.info(
                f"Descubrimiento completado. {len(projects)} proyectos encontrados"
            )
            return projects

        except Exception as e:
            self.logger.error(f"Error en descubrimiento de proyectos: {e}")
            return []

    def _create_project_info(
        self, s7p_file: Path, obs_dir: Dict[str, Any]
    ) -> Dict[str, Any]:
        """Crear información de proyecto desde archivo .s7p"""
        project_path = s7p_file.parent
        obs_path = Path(obs_dir["path"])

        # Calcular ruta relativa
        try:
            relative_path = project_path.relative_to(obs_path)
        except ValueError:
            relative_path = project_path.name

        # Generar ID único para el proyecto
        project_id = self._generate_project_id(str(project_path))

        return {
            "id": project_id,
            "name": project_path.name,
            "path": str(project_path),
            "s7p_file": str(s7p_file),
            "observation_directory": obs_dir["path"],
            "relative_path": str(relative_path),
            "backup_path": str(relative_path),
            "type": "siemens_s7",
            "auto_discovered": True,
            "discovery_method": "filesystem_search",
        }

    def _generate_project_id(self, path: str) -> str:
        """Generar ID único para un proyecto basado en su ruta"""
        # Usar hash de la ruta + timestamp para garantizar unicidad
        path_hash = hashlib.md5(path.encode()).hexdigest()[:8]
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        return f"project_{path_hash}_{timestamp}"

    def backup_project(self, project) -> Dict[str, Any]:
        """Ejecutar backup de un proyecto específico"""
        try:
            self.logger.info(f"Iniciando backup del proyecto: {project.name}")

            # Verificar que el directorio del proyecto existe
            if not os.path.exists(project.path):
                error_msg = f"Directorio del proyecto no existe: " f"{project.path}"
                self.logger.error(error_msg)
                return {"success": False, "error": error_msg}

            # Verificar que el archivo .s7p existe
            if hasattr(project, "s7p_file") and project.s7p_file:
                if not os.path.exists(project.s7p_file):
                    error_msg = f"Archivo .s7p no existe: {project.s7p_file}"
                    self.logger.error(error_msg)
                    return {"success": False, "error": error_msg}

            # Verificar espacio en disco
            backup_dest = self.config.backup_destination
            min_space_mb = self.config.global_settings.get("min_free_space_mb", 100)

            try:
                import shutil

                free_space_bytes = shutil.disk_usage(backup_dest).free
                free_space_mb = free_space_bytes / (1024 * 1024)

                if free_space_mb < min_space_mb:
                    error_msg = (
                        f"Espacio insuficiente en destino. "
                        f"Disponible: {free_space_mb:.1f}MB, "
                        f"Requerido: {min_space_mb}MB"
                    )
                    self.logger.error(error_msg)
                    return {"success": False, "error": error_msg}
            except Exception as e:
                self.logger.warning(f"No se pudo verificar espacio en disco: {e}")

            # Crear directorio de backup
            backup_path = self._create_backup_path(project)
            os.makedirs(backup_path, exist_ok=True)

            # Crear archivo ZIP
            timestamp = datetime.now().strftime("%H-%M-%S")
            backup_filename = f"{timestamp}_projects.zip"
            backup_filepath = os.path.join(backup_path, backup_filename)

            # Comprimir proyecto
            import zipfile

            with zipfile.ZipFile(backup_filepath, "w", zipfile.ZIP_DEFLATED) as zipf:
                self._add_directory_to_zip(zipf, project.path, project.backup_path)

            # Verificar que el archivo se creó correctamente
            if os.path.exists(backup_filepath):
                file_size = os.path.getsize(backup_filepath)
                file_size_mb = file_size / (1024 * 1024)

                self.logger.info(
                    f"Backup completado: {backup_filename} " f"({file_size_mb:.2f} MB)"
                )

                return {
                    "success": True,
                    "backup_file": backup_filepath,
                    "file_size_mb": file_size_mb,
                    "message": f"Backup creado exitosamente: {backup_filename}",
                }
            else:
                error_msg = "Error: el archivo de backup no se creó"
                self.logger.error(error_msg)
                return {"success": False, "error": error_msg}

        except Exception as e:
            error_msg = f"Error durante el backup: {str(e)}"
            self.logger.error(error_msg)
            return {"success": False, "error": error_msg}

    def _create_backup_path(self, project) -> str:
        """Crear la ruta de backup para un proyecto"""
        backup_base = Path(self.config.backup_destination)

        # Usar backup_path del proyecto si está disponible
        if hasattr(project, "backup_path") and project.backup_path:
            project_backup_path = project.backup_path
        else:
            # Fallback al nombre del proyecto
            project_backup_path = project.name

        # Crear estructura: backup_destination/project_path/YYYY-MM-DD/
        date_folder = datetime.now().strftime("%Y-%m-%d")
        full_backup_path = backup_base / project_backup_path / date_folder

        return str(full_backup_path)

    def _add_directory_to_zip(self, zipf, source_dir, archive_name):
        """Agregar directorio completo al archivo ZIP"""
        source_path = Path(source_dir)

        for file_path in source_path.rglob("*"):
            if file_path.is_file():
                # Calcular ruta relativa para el archivo en el ZIP
                relative_path = file_path.relative_to(source_path.parent)
                zipf.write(file_path, relative_path)
