"""
AutoBackups - Aplicación Principal Flask
Sistema automatizado de backup para proyectos Simatic S7
"""

import sys
import os
import logging
from pathlib import Path
from datetime import datetime
from flask import Flask, render_template, request, jsonify, redirect, url_for
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger
import atexit

# Agregar el directorio src al path para imports
current_dir = Path(__file__).parent
src_dir = current_dir
sys.path.insert(0, str(src_dir))

# Imports de módulos propios
from models.config_model import Config
from models.project_model import ProjectManager
from utils.file_utils import DiskSpaceChecker
from utils.system_tray import SystemTrayManager
from services.basic_backup_service import BasicBackupService
from routes import register_api_routes, register_web_routes


# Crear instancia Flask
app = Flask(__name__, template_folder="../templates", static_folder="../static")

# Configuración para desarrollo - habilitar recarga de templates
app.config["TEMPLATES_AUTO_RELOAD"] = True


class AutoBackupsFlaskApp:
    """Aplicación principal de AutoBackups con Flask"""

    def __init__(self):
        self.config = None
        self.project_manager = None
        self.disk_checker = None
        self.backup_service = None
        self.scheduler = None
        self.logger = None
        self.system_tray = None

        # Inicializar aplicación
        self._setup_logging()
        self._load_configuration()
        self._initialize_services()
        self._setup_scheduler()
        self._register_routes()
        self._setup_system_tray()

    def _setup_logging(self):
        """Configurar sistema de logging"""
        try:
            # Crear directorio de logs si no existe
            logs_dir = Path(__file__).parent.parent / ".logs"
            logs_dir.mkdir(exist_ok=True)

            # Nombre del archivo de log con timestamp
            timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
            log_filename = logs_dir / f"autobackups_{timestamp}.log"

            # Configurar logging
            logging.basicConfig(
                level=logging.INFO,
                format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
                handlers=[
                    logging.FileHandler(log_filename, encoding="utf-8"),
                    logging.StreamHandler(sys.stdout),
                ],
            )

            self.logger = logging.getLogger(__name__)
            self.logger.info(f"AutoBackups Flask iniciado - Log: {log_filename}")

        except Exception as e:
            print(f"Error configurando logging: {e}")
            sys.exit(1)

    def _load_configuration(self):
        """Cargar configuración del sistema"""
        try:
            self.logger.info("Cargando configuración...")
            self.config = Config()
            self.logger.info("Configuración cargada exitosamente")

            # Mostrar información básica de configuración
            dirs_count = len(self.config.observation_directories)
            self.logger.info(f"Directorios de observación: {dirs_count}")
            self.logger.info(f"Destino: {self.config.backup_destination}")

        except Exception as e:
            self.logger.error(f"Error cargando configuración: {e}")
            sys.exit(1)

    def _initialize_services(self):
        """Inicializar servicios principales"""
        try:
            self.logger.info("Inicializando servicios...")

            # Project Manager
            self.project_manager = ProjectManager()
            self.logger.info("Project Manager inicializado")

            # Disk Space Checker
            self.disk_checker = DiskSpaceChecker()
            self.logger.info("Disk Space Checker inicializado")

            # Basic Backup Service
            self.backup_service = BasicBackupService(self.config)
            self.logger.info("Basic Backup Service inicializado")

            self.logger.info("Todos los servicios inicializados correctamente")

        except Exception as e:
            self.logger.error(f"Error inicializando servicios: {e}")
            sys.exit(1)

    def _setup_scheduler(self):
        """Configurar scheduler para tareas automáticas"""
        try:
            self.scheduler = BackgroundScheduler(timezone="America/Mexico_City")

            # Agregar job de escaneo cada hora
            self.scheduler.add_job(
                func=self.scheduled_project_scan,
                trigger=CronTrigger(minute=0),  # Cada hora en el minuto 0
                id="project_scan",
                name="Escaneo de proyectos automático",
                replace_existing=True,
            )

            # Iniciar scheduler
            self.scheduler.start()
            self.logger.info("Scheduler configurado e iniciado")

            # Asegurar que el scheduler se detenga al cerrar la aplicación
            atexit.register(lambda: self.scheduler.shutdown())

        except Exception as e:
            self.logger.error(f"Error configurando scheduler: {e}")

    def _register_routes(self):
        """Registrar rutas de Flask usando módulos separados"""
        register_web_routes(app, self)
        register_api_routes(app, self)
        self.logger.info("Rutas Flask registradas desde módulos")

    def _setup_system_tray(self):
        """Inicializa el icono de system tray"""
        try:
            host = self.config.web_interface.get("host", "127.0.0.1")
            port = self.config.web_interface.get("port", 5000)

            self.system_tray = SystemTrayManager(self, host, port)
            self.logger.info("System tray configurado correctamente")

        except Exception as e:
            self.logger.error(f"Error configurando system tray: {e}")
            self.system_tray = None

    def start_system_tray(self):
        """Inicia el icono de system tray"""
        if self.system_tray:
            success = self.system_tray.start_tray()
            if success:
                self.logger.info("System tray iniciado correctamente")
                return True
            else:
                self.logger.warning("No se pudo iniciar el system tray")
                return False
        return False

    def scheduled_project_scan(self):
        """Escaneo programado de proyectos"""
        try:
            self.logger.info("Iniciando escaneo programado de proyectos...")
            projects_found = self.discover_projects()
            self.logger.info(f"Escaneo completado: {projects_found} proyectos")
        except Exception as e:
            self.logger.error(f"Error en escaneo programado: {e}")

    def discover_projects(self) -> int:
        """Descubrir proyectos en directorios de observación"""
        try:
            self.logger.info("Iniciando descubrimiento de proyectos...")

            # Usar el servicio básico de backup
            if hasattr(self, "backup_service"):
                projects = self.backup_service.discover_projects_basic()
            else:
                projects = []

            # Obtener proyectos existentes para evitar duplicados
            existing_projects = self.project_manager.get_all_projects()
            existing_paths = {project.path for project in existing_projects}

            # Agregar solo proyectos nuevos al manager
            new_projects_count = 0
            for project_info in projects:
                project_path = project_info.get("path")
                if project_path not in existing_paths:
                    self.project_manager.add_or_update_project(project_info)
                    new_projects_count += 1
                    self.logger.debug(
                        f"Nuevo proyecto agregado: {project_info.get('name')}"
                    )
                else:
                    self.logger.debug(
                        f"Proyecto ya existe, omitido: {project_info.get('name')}"
                    )

            msg = f"Descubrimiento completado: {len(projects)} proyectos encontrados, {new_projects_count} nuevos agregados"
            self.logger.info(msg)

            return new_projects_count

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

    def check_system_requirements(self) -> bool:
        """Verificar requerimientos del sistema"""
        try:
            self.logger.info("Verificando requerimientos del sistema...")

            # Verificar espacio en disco
            backup_destination = self.config.backup_destination
            min_space_mb = self.config.get_min_free_space_mb()

            free_space_mb = self.disk_checker.get_free_space_mb(backup_destination)

            if free_space_mb < min_space_mb:
                self.logger.error(
                    f"Espacio insuficiente en destino de backup. "
                    f"Disponible: {free_space_mb:.1f}MB, "
                    f"Requerido: {min_space_mb}MB"
                )
                return False

            self.logger.info(f"Espacio en disco OK: {free_space_mb:.1f}MB disponibles")
            return True

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


# Instancia global de la aplicación
autobackups_app = None


def main():
    """Función principal"""
    global autobackups_app

    try:
        print("AutoBackups - Sistema de Backup Automatizado (Flask)")
        print("=" * 55)

        # Crear y configurar aplicación Flask
        autobackups_app = AutoBackupsFlaskApp()

        # Verificar requerimientos del sistema
        if not autobackups_app.check_system_requirements():
            print("Error en la verificación de requerimientos del sistema.")
            sys.exit(1)

        # Ejecutar descubrimiento inicial de proyectos
        projects_found = autobackups_app.discover_projects()
        print(f"Descubrimiento inicial: {projects_found} proyectos encontrados")

        # Configurar Flask
        host = autobackups_app.config.web_interface.get("host", "127.0.0.1")
        port = autobackups_app.config.web_interface.get("port", 5000)
        debug = autobackups_app.config.web_interface.get("debug", False)

        print(f"\nServidor web iniciando en http://{host}:{port}")

        # Iniciar system tray
        autobackups_app.start_system_tray()

        print("Presiona Ctrl+C para detener el servidor")
        print("Aplicación disponible en el system tray")

        # Iniciar servidor Flask
        app.run(host=host, port=port, debug=debug, use_reloader=False)

    except KeyboardInterrupt:
        print("\nAplicación interrumpida por el usuario")
        if autobackups_app:
            if autobackups_app.scheduler:
                autobackups_app.scheduler.shutdown()
            if autobackups_app.system_tray:
                autobackups_app.system_tray.stop_tray()
    except Exception as e:
        print(f"Error inesperado: {e}")
        if autobackups_app:
            if autobackups_app.scheduler:
                autobackups_app.scheduler.shutdown()
            if autobackups_app.system_tray:
                autobackups_app.system_tray.stop_tray()
        sys.exit(1)


if __name__ == "__main__":
    main()
