// System Loader - Centralized loading and health check system for LibrePortal
class SystemLoader {
  constructor() {
    this.systems = new Map();
    this.checks = new Map();
    this.components = new Map();
    this.progress = 0;
    this.totalChecks = 0;
    this.completedChecks = 0;
    this.errors = [];
    this.isFirstTime = false;
    this.callbacks = {
      onProgress: [],
      onSystemCheck: [],
      onComplete: [],
      onError: []
    };
    
    this.initializeSystems();
    this.initializeHealthChecks();
    this.initializeComponentRegistry();
  }

  // Initialize component registry
  initializeComponentRegistry() {
    
    // Config Manager - Essential for config pages
    this.components.set('config-manager', {
      system: 'managers',
      initializer: () => {
        if (typeof ConfigManager !== 'undefined') {
          window.configManager = new ConfigManager();
          return window.configManager;
        }
        return null;
      },
      global: 'configManager',
      dependencies: ['data'],
      scripts: [
        '/core/config/js/options.js',
        '/core/config/js/field-factory.js',
        '/components/admin/config/js/config-validator.js',
        '/components/admin/config/js/toggle-manager.js',
        '/components/admin/config/js/config-core.js',
        '/components/admin/config/js/domain-manager.js',
        '/components/admin/config/js/ip-whitelist-manager.js',
        '/components/admin/config/js/config-renderer.js',
        '/components/admin/config/js/config-sidebar.js',
        '/components/admin/config/js/config-form.js',
        '/components/admin/config/js/config-utils.js',
        '/components/admin/config/js/config-manager.js'
      ]
    });
    
    // Mobile Menu
    this.components.set('mobile-menu', {
      system: 'components',
      initializer: () => {
        if (typeof setupMobileMenu === 'function') {
          setupMobileMenu();
          return true;
        }
        console.warn('⚠️ setupMobileMenu not available');
        return null;
      },
      global: null,
      dependencies: [],
      scripts: [
        '/core/topbar/js/topbar.js',
        '/core/update-notifier/js/update-notifier.js',
        '/core/network-notifier/js/network-notifier.js',
        '/core/topbar/js/mobile-menu.js'
      ]
    });
    
    // Confirmation Dialog
    this.components.set('confirmation-dialog', {
      system: 'components',
      initializer: () => {
        if (typeof initConfirmationDialog === 'function') {
          initConfirmationDialog();
          return true;
        }
        console.warn('⚠️ initConfirmationDialog not available');
        return null;
      },
      global: null,
      dependencies: [],
      script: '/core/overlays/js/confirmation-dialog.js'
    });

    // Notifications
    this.components.set('notifications', {
      system: 'components',
      initializer: () => {
        if (typeof NotificationSystem !== 'undefined') {
          window.notificationSystem = new NotificationSystem();
          return window.notificationSystem;
        }
        console.warn('⚠️ NotificationSystem not available');
        return null;
      },
      global: 'notificationSystem',
      dependencies: [],
      script: '/core/notifications/js/notifications.js'
    });
    
    // Dashboard
    this.components.set('dashboard', {
      system: 'core',
      initializer: () => {
        // Initialize data loading system
        if (typeof initializeData === 'function') {
          initializeData();
        }

        // Initialize dashboard-specific functions
        if (typeof loadSystemInfo === 'function') {
          loadSystemInfo();
        }

        if (typeof setupEventListeners === 'function') {
          setupEventListeners();
        }

        return true;
      },
      global: null,
      dependencies: []
      // data-loader.js is now loaded in core HTML
    });
    
    // Task System - Load all task-related scripts together
    this.components.set('task-system', {
      system: 'task',
      initializer: () => {
        
        // Open the SSE feed before anything else so we don't miss the upserts
        // that fire as the page boots.
        if (window.taskEventBus && typeof window.taskEventBus.start === 'function') {
          window.taskEventBus.start();
        }

        // Create TasksManager instance
        if (typeof TasksManager !== 'undefined') {
          window.tasksManager = new TasksManager();
          return window.tasksManager;
        }
        
        console.warn('⚠️ TasksManager not available');
        return null;
      },
      global: 'tasksManager',
      dependencies: [],
      scripts: [
        '/core/tasks/js/task-event-bus.js',
        '/core/tasks/js/task-commands.js',
        '/core/tasks/js/task-actions.js',
        '/core/tasks/js/task-router.js',
        '/core/tasks/js/task-manager.js',
        '/core/tasks/js/task-parameter-preserve.js',
        '/components/tasks/js/tasks-manager.js',          // base: class + constructor + init + bus wiring
        // prototype-augment clusters (load after base; ordered via async=false):
        '/components/tasks/js/tasks-format.js',
        '/components/tasks/js/tasks-list-render.js',
        '/components/tasks/js/tasks-data-load.js',
        '/components/tasks/js/tasks-log-stream.js',
        '/components/tasks/js/tasks-row-expand.js',
        '/components/tasks/js/tasks-actions.js',
        '/components/tasks/js/tasks-modals.js',
        '/components/tasks/js/tasks-log-modal.js'
      ]
    });
    
    // Apps Manager - Essential for app management
    this.components.set('apps-manager', {
      system: 'managers',
      initializer: () => {
        
        if (typeof AppsManager !== 'undefined') {
          try {
            window.appsManager = new AppsManager();
            return window.appsManager;
          } catch (error) {
            console.error('❌ Failed to create AppsManager instance:', error);
            return null;
          }
        } else {
          console.error('❌ AppsManager class not available after script loading');
          return null;
        }
      },
      global: 'appsManager',
      dependencies: ['data'],
      scripts: [
        '/components/apps/port-manager/js/port-manager.js',
        '/core/tasks/js/task-manager.js',  // Add TaskManager for backup functionality
        '/core/backup-card/js/backup-app-card.js',
        '/components/updater/js/updater-page.js',  // headless reuse: per-app Updates tab + fleet Overview
        '/components/apps/services/js/services-manager.js',
        '/components/apps/tools/js/tools-manager.js',
        '/components/apps/routing/js/routing-manager.js',
        '/components/apps/core/js/apps-manager.js',          // base: class + constructor + orchestration + ServiceButtons + bootstrap (+ install-dispatch, kept inline)
        // prototype-augment clusters (load after base; ordered via async=false):
        '/components/apps/core/js/apps-grid.js',
        '/components/apps/core/js/config-form.js',
        '/components/apps/core/js/port-manager-integration.js',
        '/components/apps/core/js/gluetun-vpn.js',
        '/components/apps/core/js/config-dirty-guard.js',
        '/components/apps/core/js/install-console.js',
        '/components/apps/core/js/service-buttons-sidebar.js',
        '/components/apps/core/js/instance-manager.js'  // multi-instance "New instance" modal (window.instanceManager)
      ]
    });
    
    // App Tabbed Manager - Essential for app detail pages
    this.components.set('app-tabbed-manager', {
      system: 'managers',
      initializer: () => {
        
        if (typeof AppTabbedManager !== 'undefined') {
          window.appTabbedManager = new AppTabbedManager();
          return window.appTabbedManager;
        }
        console.warn('⚠️ AppTabbedManager not available');
        return null;
      },
      global: 'appTabbedManager',
      dependencies: [],
      script: '/components/apps/core/js/app-tabbed-manager.js'
    });
    
  }

  // Initialize all system definitions
  initializeSystems() {
    this.systems.set('core', {
      name: 'Core System',
      description: 'Essential system components',
      priority: 1,
      dependencies: [],
      checks: ['dom', 'spa', 'utils']
    });
    
    this.systems.set('data', {
      name: 'Data Functions',
      description: 'Data loading functions availability',
      priority: 2,
      dependencies: ['core'],
      checks: [] 
    });

    this.systems.set('components', {
      name: 'UI Components',
      description: 'User interface components',
      priority: 3,
      dependencies: ['core'],
      checks: ['topbar', 'confirmation-dialog', 'notifications', 'icon-preloading']
    });
    
    this.systems.set('task', {
      name: 'Task System',
      description: 'Task management and operations',
      priority: 4,
      dependencies: ['core'],
      checks: ['task-manager']
    });
    
    this.systems.set('managers', {
      name: 'System Managers',
      description: 'Application managers and services',
      priority: 5,
      dependencies: ['core', 'task'],
      checks: ['apps-manager', 'config-manager', 'app-tabbed-manager']
    });
    
    this.systems.set('backend', {
      name: 'Backend Services',
      description: 'External service connectivity',
      priority: 6,
      dependencies: ['core'],
      checks: ['server-connectivity', 'api-endpoints']
    });

    this.systems.set('config-validation', {
      name: 'Config Files',
      description: 'Configuration files validation',
      priority: 7,
      dependencies: ['core', 'task'],
      checks: ['config-files'],
      critical: true
    });
    
    this.systems.set('update-lock', {
      name: 'Update Lock Check',
      description: 'Check for update lock file to prevent concurrent updates',
      priority: 8,
      dependencies: ['core'],
      checks: ['update-lock'],
      critical: false,
      check: async () => this.checkUpdateLock()
    });
    
    this.systems.set('pause-lock', {
      name: 'Pause Lock Check',
      description: 'Check for pause lock file to prevent operations during pause',
      priority: 8.1,
      dependencies: ['core'],
      checks: ['pause-lock'],
      critical: false,
      check: async () => this.checkPauseLock()
    });
  }

  // Initialize health check functions
  initializeHealthChecks() {
    // Core checks
    this.checks.set('dom', {
      name: 'DOM Ready',
      description: 'Document Object Model loaded',
      weight: 1,
      timeout: 5000,
      check: () => document.readyState === 'complete' || document.readyState === 'interactive'
    });

    this.checks.set('spa', {
      name: 'SPA Router',
      description: 'Single Page Application router',
      weight: 2,
      timeout: 5000,
      check: () => typeof LibrePortalSPAClean !== 'undefined'
    });

    this.checks.set('utils', {
      name: 'Utility Functions',
      description: 'Helper utilities and tools',
      weight: 1,
      timeout: 5000,
      check: async () => {
        // Wait a moment for scripts to load
        await new Promise(resolve => setTimeout(resolve, 500));
        
        // Check for essential utilities that should be loaded statically
        const hasSafeGetElement = typeof safeGetElement === 'function';
        const hasSafeQuerySelector = typeof safeQuerySelector === 'function';
        const hasGetAppIcon = typeof getAppIcon === 'function';
        
        // Check for utilities that will be loaded dynamically
        const hasDataLoader = typeof DataLoader !== 'undefined';
        const hasInitializeData = typeof initializeData === 'function';
        
            //key.includes('get') || 
            //key.includes('Data') ||
            //key.includes('Theme') ||
            //key.includes('initialize')
          //).slice(0, 10)
        //});
        
        // More flexible check - require at least 2 of the essential utilities
        // Data loader and theme toggle will be loaded dynamically, so don't require them here
        const essentialUtilitiesCount = [hasSafeGetElement, hasSafeQuerySelector, hasGetAppIcon].filter(Boolean).length;
        return essentialUtilitiesCount >= 2;
      }
    });

    // Data Loader health check
    this.checks.set('data-loader', {
      name: 'Data Loader',
      description: 'Data loading and management system',
      weight: 2,
      timeout: 5000,
      check: async () => {
        // Wait a moment for data-loader to load
        await new Promise(resolve => setTimeout(resolve, 1000));
        
        const hasDataLoader = typeof DataLoader !== 'undefined';
        const hasInitializeData = typeof initializeData === 'function';
        const hasLoadDashboardData = typeof loadDashboardData === 'function';
        const hasLoadAppsPageData = typeof loadAppsPageData === 'function';
        const hasLoadConfigDetailData = typeof loadConfigDetailData === 'function';
        const hasLoadMinimalData = typeof loadMinimalData === 'function';
        
        
        // Check if data loader functions are available
        return hasInitializeData && (hasLoadDashboardData || hasLoadAppsPageData || hasLoadConfigDetailData);
      }
    });

    // Note: Individual data checks (apps-data, categories-data, config-data) removed
    // They are now handled by the comprehensive config-files check above

    // Component checks - always pass since they're loaded dynamically
    this.checks.set('topbar', {
      name: 'Topbar Component',
      description: 'Navigation topbar',
      weight: 2,
      timeout: 1000, // Reduced timeout since we're not actually checking
      check: async () => {
        // Always pass - TopbarComponent will be loaded dynamically by mobile-menu component
        return true;
      }
    });


    this.checks.set('confirmation-dialog', {
      name: 'Confirmation Dialog',
      description: 'User confirmation dialog system',
      weight: 1,
      timeout: 1000,
      check: async () => {
        return true;
      }
    });

    this.checks.set('notifications', {
      name: 'Notification System',
      description: 'User notification system',
      weight: 1,
      timeout: 1000, // Reduced timeout since we're not actually checking
      check: async () => {
        // Always pass - NotificationSystem will be loaded dynamically by notifications component
        return true;
      }
    });

    this.checks.set('icon-preloading', {
      name: 'Icon Preloading',
      description: 'Preload app center icons for faster loading',
      weight: 2,
      timeout: 15000,
      check: async () => this.checkIconPreloading()
    });

    // Manager checks - always pass since they're loaded dynamically
    this.checks.set('apps-manager', {
      name: 'Apps Manager',
      description: 'Application management system',
      weight: 3,
      timeout: 1000, // Reduced timeout since we're not actually checking
      check: async () => {
        // Always pass - AppsManager will be loaded dynamically by apps-manager component
        return true;
      }
    });

    this.checks.set('task-manager', {
      name: 'Task Manager',
      description: 'Background task management',
      weight: 3,
      timeout: 1000, // Reduced timeout since we're not actually checking
      check: async () => {
        // Always pass - TasksManager will be loaded dynamically by task-manager component
        return true;
      }
    });

    this.checks.set('config-manager', {
      name: 'Configuration Manager',
      description: 'System configuration management',
      weight: 2,
      timeout: 1000, // Reduced timeout since we're not actually checking
      check: async () => {
        // Always pass - ConfigManager will be loaded dynamically by config-manager component
        return true;
      }
    });

    this.checks.set('app-tabbed-manager', {
      name: 'App Tabbed Manager',
      description: 'Application tabbed interface management',
      weight: 3,
      timeout: 1000, // Reduced timeout since we're not actually checking
      check: async () => {
        // Always pass - AppTabbedManager will be loaded dynamically by app-tabbed-manager component
        return true;
      }
    });

    // Backend checks
    this.checks.set('server-connectivity', {
      name: 'Server Connectivity',
      description: 'Basic server connectivity',
      weight: 2,
      timeout: 8000,
      check: async () => {
        try {
          const response = await fetch('/', { method: 'HEAD' });
          return response.ok;
        } catch {
          return false;
        }
      }
    });

    this.checks.set('api-endpoints', {
      name: 'API Endpoints',
      description: 'Backend API availability',
      weight: 3,
      timeout: 10000,
      check: async () => {
        const endpoints = [
          '/data/apps/generated/apps.json',
          '/data/apps/apps-categories.json',
          '/data/config/generated/configs.json'
        ];
        
        try {
          const results = await Promise.allSettled(
            endpoints.map(endpoint => fetch(endpoint, { method: 'HEAD' }))
          );
          
          return results.some(result => 
            result.status === 'fulfilled' && result.value.ok
          );
        } catch {
          return false;
        }
      }
    });

    // Update Lock Check
    this.checks.set('update-lock', {
      name: 'Update Lock',
      description: 'Check for update lock file to prevent concurrent updates',
      weight: 2,
      timeout: 10000,
      check: async () => this.checkUpdateLock()
    });

    // Pause Lock Check
    this.checks.set('pause-lock', {
      name: 'Pause Lock',
      description: 'Check for pause lock file to prevent operations during pause',
      weight: 2,
      timeout: 10000,
      check: async () => this.checkPauseLock()
    });

    // Config Files
    this.checks.set('config-files', {
      name: 'Config Files',
      description: 'Required configuration files availability',
      weight: 2,
      timeout: 15000, // Increased timeout for content validation
      check: async () => this.checkConfigFiles()
    });
  }

  // Icon Preloading Check
  async checkIconPreloading() {

    // Load data directly since window.apps isn't populated yet
    let appsData = [];
    let categoriesData = [];

    try {
      const [appsResponse, categoriesResponse] = await Promise.all([
        fetch('/data/apps/generated/apps.json'),
        fetch('/data/apps/apps-categories.json')
      ]);


      if (appsResponse.ok) {
        const appsText = await appsResponse.text();
        const appsParsed = JSON.parse(appsText);
        appsData = appsParsed.apps || [];
      } else {
        console.warn('⚠️ Apps response not ok:', appsResponse.status);
      }

      if (categoriesResponse.ok) {
        const categoriesText = await categoriesResponse.text();
        const categoriesParsed = JSON.parse(categoriesText);
        categoriesData = categoriesParsed.categories || [];
      } else {
        console.warn('⚠️ Categories response not ok:', categoriesResponse.status);
      }
    } catch (error) {
      console.warn('⚠️ Failed to load data for icon preloading:', error);
    }


    // Collect all icon URLs to preload
    const iconUrls = new Set();

    // Add app icons
    if (appsData && Array.isArray(appsData)) {
      appsData.forEach(app => {
        if (app.icon) {
          iconUrls.add(app.icon.startsWith('/') ? app.icon : '/' + app.icon);
        } else {
          const cleanAppName = app.command?.split(' ').pop() || app.name;
          iconUrls.add(`/core/icons/apps/${cleanAppName}.svg`);
        }
        iconUrls.add('/core/icons/apps/default.svg');
      });
    }

    // Add category icons
    if (categoriesData && Array.isArray(categoriesData)) {
      categoriesData.forEach(category => {
        if (category.icon) {
          iconUrls.add(category.icon.startsWith('/') ? category.icon : '/' + category.icon);
        }
      });
    }

    // Add 'all' and 'installed' category icons
    iconUrls.add('/core/icons/categories/all.svg');
    iconUrls.add('/core/icons/categories/installed.svg');


    // Preload all icons using Image objects
    const preloadPromises = Array.from(iconUrls).map(iconUrl => {
      return new Promise((resolve) => {
        const img = new Image();
        img.onload = () => resolve();
        img.onerror = () => resolve(); // Resolve even on error to not block
        img.src = iconUrl;
      });
    });

    await Promise.all(preloadPromises);

    // Pre-render app center in background
    if (window.appsManager && typeof window.appsManager.showAppsList === 'function') {
      window.appsManager.showAppsList('all');
      await new Promise(resolve => setTimeout(resolve, 300)); // Wait for rendering
    }

    return true;
  }

  // Add event callbacks
  on(event, callback) {
    if (this.callbacks[event]) {
      this.callbacks[event].push(callback);
    }
  }

  // Trigger event callbacks
  trigger(event, data) {
    if (this.callbacks[event]) {
      this.callbacks[event].forEach(callback => callback(data));
    }
  }

  // Calculate total checks weight
  calculateTotalWeight() {
    let total = 0;
    for (const [systemId, system] of this.systems) {
      for (const checkId of system.checks) {
        const check = this.checks.get(checkId);
        if (check) {
          total += check.weight;
        }
      }
    }
    return total;
  }

  // Initialize all components in dependency order
  async initializeComponents() {
    
    // Get systems in priority order
    const sortedSystems = Array.from(this.systems.entries())
      .sort(([,a], [,b]) => a.priority - b.priority);

    for (const [systemId, system] of sortedSystems) {
      
      // Check dependencies first
      const dependenciesMet = system.dependencies.every(dep => 
        this.systems.get(dep)?.initialized === true
      );

      if (!dependenciesMet) {
        continue;
      }

      // Find components for this system
      const systemComponents = Array.from(this.components.entries())
        .filter(([, component]) => component.system === systemId);


      // Initialize components for this system
      for (const [componentId, component] of systemComponents) {
        try {
          
          // Load component script(s) if specified
          if (component.script) {
            await this.loadScript(component.script);
          } else if (component.scripts) {
            await this.loadScripts(component.scripts);
          }
          
          // Check component dependencies
          const componentDepsMet = component.dependencies.every(dep => 
            this.systems.get(dep)?.initialized === true
          );

          if (!componentDepsMet) {
            continue;
          }

          // Initialize component
          const result = component.initializer();
          
          // Store result if available
          if (result && component.global) {
            window[component.global] = result;
          }

          
        } catch (error) {
          console.error(`❌ Failed to initialize ${componentId}:`, error);
          this.errors.push({
            system: system.name,
            component: componentId,
            error: error.message
          });
        }
      }

      // Mark system as initialized
      system.initialized = true;
    }
    
  }

  // Load a script dynamically
  async loadScript(src) {
    return new Promise((resolve, reject) => {
      // Check if script is already loaded
      if (document.querySelector(`script[src="${src}"]`)) {
        resolve();
        return;
      }

      const script = document.createElement('script');
      script.src = src;
      script.onload = resolve;
      script.onerror = reject;
      document.head.appendChild(script);
    });
  }

  // Run all health checks
  async runHealthChecks() {
    this.totalChecks = this.calculateTotalWeight();
    this.completedChecks = 0;
    this.errors = [];
    
    const results = new Map();
    
    // Process systems in priority order
    const sortedSystems = Array.from(this.systems.entries())
      .sort(([,a], [,b]) => a.priority - b.priority);

    for (const [systemId, system] of sortedSystems) {
      // Check dependencies first
      const dependenciesMet = system.dependencies.every(dep => 
        results.get(dep)?.status === 'passed'
      );


      if (!dependenciesMet) {
        results.set(systemId, {
          status: 'skipped',
          reason: 'Dependencies not met',
          checks: []
        });
        continue;
      }

      // Run system checks
      const systemResults = [];
      
      // If system has no checks, it automatically passes
      if (system.checks.length === 0) {
        
        // Trigger status update for systems with no checks
        this.trigger('onSystemCheck', {
          systemId,
          systemName: system.name,
          checkId: 'auto-pass',
          checkName: 'No checks required',
          status: 'passed'
        });
      } else {
        // Run checks for systems that have them
        for (const checkId of system.checks) {
        const check = this.checks.get(checkId);
        if (!check) continue;

        this.trigger('onSystemCheck', {
          systemId,
          systemName: system.name,
          checkId,
          checkName: check.name,
          status: 'checking'
        });


        try {
          const result = await this.runSingleCheck(checkId, check);
          systemResults.push(result);
          
          if (result.status === 'failed') {
            
            this.errors.push({
              system: system.name,
              check: check.name,
              error: result.error
            });
            
            // If this is a critical system, stop all further processing
            if (system.critical) {
              console.error(`🚨 CRITICAL SYSTEM FAILURE: ${system.name} - stopping all further checks`);
              // Mark ALL remaining systems as skipped due to critical failure
              const currentIndex = sortedSystems.findIndex(([id]) => id === systemId);
              for (let i = currentIndex + 1; i < sortedSystems.length; i++) {
                const [remainingSystemId, remainingSystem] = sortedSystems[i];
                results.set(remainingSystemId, {
                  status: 'skipped',
                  reason: `Critical system ${system.name} failed`,
                  checks: []
                });
              }
              // Return immediately with critical failure
              const criticalResult = {
                results: Object.fromEntries(results),
                errors: this.errors,
                success: false,
                criticalFailure: true
              };
              this.trigger('onComplete', criticalResult);
              return criticalResult;
            }
          }
        } catch (error) {
          
          systemResults.push({
            id: checkId,
            name: check.name,
            status: 'failed',
            error: error.message
          });
          
          this.errors.push({
            system: system.name,
            check: check.name,
            error: error.message
          });
          
          // If this is a critical system, stop all further processing
          if (system.critical) {
            console.error(`🚨 CRITICAL SYSTEM FAILURE: ${system.name} - stopping all further checks`);
            // Mark ALL remaining systems as skipped due to critical failure
            const currentIndex = sortedSystems.findIndex(([id]) => id === systemId);
            for (let i = currentIndex + 1; i < sortedSystems.length; i++) {
              const [remainingSystemId, remainingSystem] = sortedSystems[i];
              results.set(remainingSystemId, {
                status: 'skipped',
                reason: `Critical system ${system.name} failed`,
                checks: []
              });
            }
            // Return immediately with critical failure
            const criticalResult = {
              results: Object.fromEntries(results),
              errors: this.errors,
              success: false,
              criticalFailure: true
            };
            this.trigger('onComplete', criticalResult);
            return criticalResult;
          }
        }
      }
      }

      const systemPassed = systemResults.every(r => r.status === 'passed');
      results.set(systemId, {
        status: systemPassed ? 'passed' : 'failed',
        checks: systemResults
      });
    }

    this.trigger('onComplete', {
      results: Object.fromEntries(results),
      errors: this.errors,
      success: this.errors.length === 0
    });

    return {
      results: Object.fromEntries(results),
      errors: this.errors,
      success: this.errors.length === 0
    };
  }

  // Run a single health check
  async runSingleCheck(checkId, check) {
    const startTime = Date.now();
    
    try {
      
      const result = await Promise.race([
        Promise.resolve(check.check()),
        new Promise((_, reject) => 
          setTimeout(() => reject(new Error('Timeout')), check.timeout)
        )
      ]);

      const duration = Date.now() - startTime;
      const passed = Boolean(result);


      this.completedChecks += check.weight;
      this.progress = Math.min((this.completedChecks / this.totalChecks) * 100, 100);

      this.trigger('onProgress', {
        checkId,
        checkName: check.name,
        status: passed ? 'passed' : 'failed',
        progress: this.progress,
        duration
      });

      return {
        id: checkId,
        name: check.name,
        status: passed ? 'passed' : 'failed',
        duration,
        error: passed ? null : 'Check failed'
      };

    } catch (error) {
      const duration = Date.now() - startTime;
      console.error(`❌ Health check ${check.name} FAILED:`, error);
      
      this.completedChecks += check.weight;
      this.progress = Math.min((this.completedChecks / this.totalChecks) * 100, 100);

      this.trigger('onProgress', {
        checkId,
        checkName: check.name,
        status: 'failed',
        progress: this.progress,
        duration,
        error: error.message
      });

      return {
        id: checkId,
        name: check.name,
        status: 'failed',
        duration,
        error: error.message
      };
    }
  }

  // Check if this is first-time setup
  async checkFirstTimeSetup() {
    try {
      // Check for essential config files
      const essentialFiles = [
        '/data/apps/generated/apps.json',
        '/data/apps/apps-categories.json'
      ];

      for (const file of essentialFiles) {
        const response = await fetch(file, { method: 'HEAD' });
        if (!response.ok) {
          this.isFirstTime = true;
          return true;
        }
      }

      // Check localStorage for setup flag
      const setupComplete = localStorage.getItem('libreportal_setup_complete');
      if (!setupComplete) {
        this.isFirstTime = true;
        return true;
      }

      this.isFirstTime = false;
      return false;
    } catch {
      this.isFirstTime = true;
      return true;
    }
  }

  // Check required config files
  async checkConfigFiles() {
    
    // Critical files that MUST exist and not be empty
    const criticalFiles = [
      '/data/tasks/current.json',
      '/data/tasks/queue.json',
      '/data/system/system_info.json',
      '/data/system/memory_usage.json',
      '/data/system/disk_usage.json',
      '/data/system/system_info.json',
      '/data/apps/generated/apps.json',
      '/data/apps/apps-categories.json',
      '/data/apps/apps-field-mappings.json',
      '/data/apps/apps-config-categories.json',
      '/data/config/generated/configs.json'
    ];

    
    // Optional files (can be missing but should exist if possible)
    const optionalFiles = [
    ];
    
    const allFiles = [...criticalFiles, ...optionalFiles];
    const results = {
      available: [],
      missing: [],
      empty: [],
      total: allFiles.length,
      criticalMissing: [],
      criticalEmpty: []
    };

    for (const file of allFiles) {
      try {
        const response = await fetch(file, { method: 'HEAD' });
        
        if (response.ok) {
          // Get content length to check if file is empty
          const contentLength = response.headers.get('content-length');
          const isEmpty = contentLength === '0' || contentLength === null;
          
          
          // For critical files, also check actual content
          if (criticalFiles.includes(file) && !isEmpty) {
            try {
              const getResponse = await fetch(file);
              const content = await getResponse.text();
              
              // Check if content starts with '{' or '[' (basic JSON file check)
              const startsWithBrace = content.trim().startsWith('{');
              const startsWithBracket = content.trim().startsWith('[');
              const isValidJSONStart = startsWithBrace || startsWithBracket;
              
              if (!isValidJSONStart) {
                results.criticalEmpty.push(file);
                results.empty.push(file);
              }
              // Check if content is actual JSON data or fallback/error content
              else if (content.includes('404 Not Found') || content.includes('404') && content.includes('Not Found') ||
                  (content.includes('Error') && (content.includes('<!DOCTYPE') || content.includes('<html>') || content.includes('status'))) || 
                  content.includes('<!DOCTYPE') || content.includes('<html>')) {
                results.criticalEmpty.push(file);
                results.empty.push(file);
              } 
              // Validate JSON syntax
              else {
                try {
                  JSON.parse(content);
                  results.available.push(file);
                } catch (jsonError) {
                  results.criticalEmpty.push(file);
                  results.empty.push(file);
                }
              }
            } catch (contentError) {
              results.criticalEmpty.push(file);
              results.empty.push(file);
            }
          } else if (isEmpty) {
            results.empty.push(file);
            if (criticalFiles.includes(file)) {
              results.criticalEmpty.push(file);
            }
          } else {
            results.available.push(file);
          }
        } else {
          results.missing.push(file);
          if (criticalFiles.includes(file)) {
            results.criticalMissing.push(file);
          }
        }
      } catch (error) {
        results.missing.push(file);
        if (criticalFiles.includes(file)) {
          results.criticalMissing.push(file);
        }
      }
    }


    // Fail if ANY critical files are missing or empty
    if (results.criticalMissing.length > 0 || results.criticalEmpty.length > 0) {
      const errorMessages = [];
      if (results.criticalMissing.length > 0) {
        errorMessages.push(`Missing critical files: ${results.criticalMissing.join(', ')}`);
      }
      if (results.criticalEmpty.length > 0) {
        errorMessages.push(`Empty critical files: ${results.criticalEmpty.join(', ')}`);
      }
      const errorMessage = `Critical configuration files are missing or empty. Please run: libreportal webui generate all \n\nDetails: ${errorMessages.join('\n')}`;
      console.error('🚨 Config Files Check FAILED - throwing error:', errorMessage);
      throw new Error(errorMessage);
    }

    return results;
  }

  // Check for update lock file to prevent concurrent updates
  async checkUpdateLock() {
    
    try {
      const response = await fetch('/data/updater-lock', { method: 'HEAD' });
      const lockExists = response.ok;
      
      
      if (lockExists) {
        return {
          status: 'locked',
          message: 'Update in progress - please wait for current update to complete'
        };
      } else {
        return {
          status: 'unlocked', 
          message: 'No update in progress'
        };
      }
    } catch (error) {
      console.error('❌ Error checking update lock:', error);
      return {
        status: 'error',
        message: `Error checking update lock: ${error.message}`
      };
    }
  }

  // Check for pause lock file to prevent operations during pause
  async checkPauseLock() {
    
    try {
      const response = await fetch('/data/pause.lock', { method: 'HEAD' });
      const lockExists = response.ok;
      
      
      if (lockExists) {
        return {
          status: 'locked',
          message: 'System is paused - operations are temporarily disabled'
        };
      } else {
        return {
          status: 'unlocked',
          message: 'System is operational'
        };
      }
    } catch (error) {
      console.error('❌ Error checking pause lock:', error);
      return {
        status: 'error',
        message: `Error checking pause lock: ${error.message}`
      };
    }
  }

  // Get system summary
  getSystemSummary() {
    return {
      totalSystems: this.systems.size,
      totalChecks: this.checks.size,
      totalWeight: this.calculateTotalWeight(),
      systems: Array.from(this.systems.entries()).map(([id, system]) => ({
        id,
        name: system.name,
        description: system.description,
        priority: system.priority,
        dependencies: system.dependencies,
        checks: system.checks,
        initialized: system.initialized || false
      })),
      components: Array.from(this.components.entries()).map(([id, component]) => ({
        id,
        system: component.system,
        global: component.global,
        dependencies: component.dependencies,
        script: component.script || null
      }))
    };
  }

  // Load a script dynamically
  async loadScript(src) {
    return new Promise((resolve, reject) => {
      // Check if script is already loaded
      if (document.querySelector(`script[src="${src}"]`)) {
        resolve();
        return;
      }

      const script = document.createElement('script');
      script.src = src;
      // Dynamically-inserted scripts default to async=true and run in whatever
      // order they finish downloading. Force async=false so a component's
      // scripts[] execute in array/insertion order — required when a class is
      // split across files (a base file must run before files that augment its
      // prototype). Mirrors the ordered kernel ctx.loadScripts() path.
      script.async = false;
      script.onload = () => {
        resolve();
      };
      script.onerror = () => {
        console.error(`❌ Failed to load script: ${src}`);
        reject(new Error(`Failed to load script: ${src}`));
      };
      document.head.appendChild(script);
    });
  }

  // Load multiple scripts for a component
  async loadScripts(scripts) {
    if (!scripts || scripts.length === 0) return;
    
    await Promise.all(scripts.map(script => this.loadScript(script)));
  }
}

// Global instance
window.SystemLoader = SystemLoader;
