// Fetch services.xml and render the service cards with logos.
(async function(){
  const container = document.getElementById('services-container');
  const searchInput = document.getElementById('search-input');
  const host = window.location.hostname;
  let allServices = []; // Store all service elements for filtering

  try{
    const res = await fetch('/services.xml', {cache: 'no-cache'});
    if(!res.ok){ throw new Error('Failed to load services.xml'); }
    const text = await res.text();
    const parser = new DOMParser();
    const doc = parser.parseFromString(text, 'application/xml');
    
    // Check for XML parsing errors
    const parseError = doc.querySelector('parsererror');
    if(parseError){
      throw new Error('XML parsing error: ' + parseError.textContent);
    }
    
    // Get Tailscale IP from root services element
    const servicesRoot = doc.getElementsByTagName('services')[0];
    const tailscaleIP = servicesRoot ? servicesRoot.getAttribute('tailscale-ip') : null;
    console.log('Tailscale IP:', tailscaleIP || 'not configured');
    
    // Check if we have groups or just services
    const groups = Array.from(doc.getElementsByTagName('group'));
    const hasGroups = groups.length > 0;
    
    console.log('Found', groups.length, 'groups');
    
    if(hasGroups){
      // Render grouped services
      groups.forEach(group => {
        const groupName = group.getAttribute('name') || 'Services';
        const services = Array.from(group.getElementsByTagName('service'));
        
        console.log('Group:', groupName, 'has', services.length, 'services');
        
        if(services.length === 0) return;
        
        // Create group section
        const groupSection = document.createElement('section');
        groupSection.className = 'service-group';
        
        const groupHeader = document.createElement('h2');
        groupHeader.className = 'group-header';
        groupHeader.textContent = groupName;
        groupSection.appendChild(groupHeader);
        
        const grid = document.createElement('div');
        grid.className = 'services-grid';
        
        services.forEach(s => {
          const card = createServiceCard(s, host, allServices, tailscaleIP);
          grid.appendChild(card);
        });
        
        groupSection.appendChild(grid);
        container.appendChild(groupSection);
      });
    } else {
      // Fallback: render ungrouped services
      const services = Array.from(doc.getElementsByTagName('service'));
      if(services.length === 0){ 
        container.innerHTML = '<p class="notes">No services found in services.xml</p>'; 
        return; 
      }
      
      const grid = document.createElement('div');
      grid.className = 'grid';
      grid.id = 'services-grid';
      
      services.forEach(s => {
        const card = createServiceCard(s, host, allServices, tailscaleIP);
        grid.appendChild(card);
      });
      
      container.appendChild(grid);
    }

    // Function to create a service card
    function createServiceCard(s, host, allServices, tailscaleIP) {
      const name = s.getAttribute('name') || s.getAttribute('id') || 'unknown';
    const serviceId = s.getAttribute('id') || name.toLowerCase().replace(/\s+/g, '-');
  const proto = s.getAttribute('proto') || 'http';
      const port = s.getAttribute('port') || '';
      const logo = s.getAttribute('logo') || '';
  const hostAttr = s.getAttribute('host'); // optional public hostname or full URL
  const localIpAttr = s.getAttribute('local-ip'); // optional local IP for proxied health-check
      const manualStatus = s.getAttribute('status'); // optional: 'online', 'offline', 'maintenance'
      const checkHealth = s.getAttribute('check-health') !== 'false'; // default true, set to false to disable

  // Build href: prefer explicit host attribute when present.
      let href = '';
      let healthCheckUrl = ''; // Separate URL for health checks
  const pageIsSecure = window.location.protocol === 'https:';
  const desiredProto = pageIsSecure ? 'https' : proto; // use https for health checks when page is secure to avoid mixed content
      
      if(hostAttr){
        // Service has a public hostname or URL
        // Parse hostAttr to extract hostname and optional port
        let parsedHost = hostAttr;
        let parsedPort = port;
        let parsedProto = proto;
        if(/^https?:\/\//i.test(hostAttr)){
          // remove protocol
          const u = new URL(hostAttr);
          parsedHost = u.hostname;
          parsedPort = u.port || parsedPort;
          parsedProto = u.protocol.replace(':','') || parsedProto;
          href = hostAttr;
        } else {
          const hasPortInHost = /:\d+$/.test(hostAttr);
          if(hasPortInHost){
            // host:port
            href = `${proto}://${hostAttr}`;
            parsedHost = hostAttr.split(':')[0];
            parsedPort = hostAttr.split(':')[1];
          } else {
            href = `https://${hostAttr}`;
            parsedHost = hostAttr;
          }
        }
        // Always proxy health checks via same-origin endpoint to avoid mixed-content
  healthCheckUrl = `/healthcheck?id=${encodeURIComponent(serviceId)}`;
      } else {
        // Local service - use Tailscale IP if configured, otherwise current hostname
  const targetHost = localIpAttr || tailscaleIP || host;
        let portPart = '';
        if(port && !((proto==='http'&&port==='80')||(proto==='https'&&port==='443'))){ portPart = ':'+port; }
  // Keep the link protocol as the defined proto (so clicking uses the intended protocol),
  // but use the server-side health proxy for health checks to avoid mixed content blocking.
  href = `${proto}://${targetHost}${portPart}`;
  // Use our same-origin proxy path which nginx will forward to the health-proxy service.
  const encodedHost = encodeURIComponent(targetHost);
        const hcPort = port || (desiredProto === 'https' ? '443' : '80');
        if(localIpAttr){
          console.log(`Service ${name}: using local-ip ${localIpAttr} for proxied health checks`);
        } else if(tailscaleIP){
          console.log(`Service ${name}: using tailscale-ip ${tailscaleIP} for proxied health checks`);
        }
  healthCheckUrl = `/healthcheck?id=${encodeURIComponent(serviceId)}`;
        // Warn when site is secure but service link is HTTP and target is a private IP
        if(pageIsSecure && proto === 'http' && targetHost === tailscaleIP){
          console.warn(`Service ${name} will use HTTP at ${href}, but the page is loaded over HTTPS — mixed-content checks will prevent programmatic health checks to the service. Consider enabling TLS or providing a public hostname.`);
        }
      }

      const a = document.createElement('a');
      a.className = 'service-card';
      a.href = href;
      a.target = '_blank';
      a.rel = 'noreferrer';
      a.dataset.serviceName = name.toLowerCase(); // For search filtering
      a.dataset.serviceId = serviceId; // For drag-drop and identification
      a.setAttribute('draggable', 'true'); // Enable drag-and-drop

      const img = document.createElement('img');
      img.className = 'logo';
      img.src = logo ? ('/logos/'+logo) : '/logos/default.svg';
      img.alt = name + ' logo';

      const span = document.createElement('div');
      span.className = 'label';
      span.textContent = `${name}`;

      a.appendChild(img);
      a.appendChild(span);

  // Add status indicator - will be updated by health check
      const statusDot = document.createElement('span');
      statusDot.className = 'status-dot status-checking';
      statusDot.title = 'Checking status...';
      let currentStatus = 'checking';
      
  // If maintenance mode is set manually, use that and skip health check
      if(manualStatus === 'maintenance'){
        statusDot.className = 'status-dot status-maintenance';
        statusDot.title = 'Status: maintenance';
        currentStatus = 'maintenance';
        a.appendChild(statusDot);
  } else if(checkHealth && healthCheckUrl){
        // Show checking indicator initially
        a.appendChild(statusDot);
        
        // Perform health check using healthCheckUrl (Tailscale IP for local services)
        if(healthCheckUrl !== href){
          console.log(`Service ${name}: using healthCheckUrl (${healthCheckUrl}) while link is ${href}`);
        }
        (async function performHealthCheck(){
          try {
            const controller = new AbortController();
            const timeoutId = setTimeout(() => controller.abort(), 5000); // 5 second timeout
            
            const response = await fetch(healthCheckUrl, {
              method: 'HEAD',
              mode: 'no-cors', // Allow cross-origin requests
              cache: 'no-cache',
              signal: controller.signal
            });
            
            clearTimeout(timeoutId);
            
            // In no-cors mode, opaque responses mean the server responded
            currentStatus = 'online';
            statusDot.className = 'status-dot status-online';
            statusDot.title = 'Status: online';
          } catch(err) {
            // Connection failed or timed out
            // If the page is not secure, try fallback to http if we used https for health check
            if(!pageIsSecure && healthCheckUrl.startsWith('https:')){
              try {
                const fallback = healthCheckUrl.replace(/^https:/i, 'http:');
                const controller2 = new AbortController();
                const timeoutId2 = setTimeout(() => controller2.abort(), 5000);
                await fetch(fallback, { method: 'HEAD', mode: 'no-cors', cache: 'no-cache', signal: controller2.signal });
                clearTimeout(timeoutId2);
                currentStatus = 'online';
                statusDot.className = 'status-dot status-online';
                statusDot.title = 'Status: online';
                return;
              } catch(fErr){
                // continue to mark offline
              }
            }
            currentStatus = 'offline';
            statusDot.className = 'status-dot status-offline';
            statusDot.title = 'Status: offline';
          }
        })();
      } else if(manualStatus){
        // Use manual status if health check is disabled
        statusDot.className = `status-dot status-${manualStatus}`;
        statusDot.title = `Status: ${manualStatus}`;
        currentStatus = manualStatus;
        a.appendChild(statusDot);
      }

      // Add info button if both hostname and port are available
      if((hostAttr || host) && port){
        const infoBtn = document.createElement('button');
        infoBtn.className = 'info-btn';
        infoBtn.title = 'Connection details';
        infoBtn.innerHTML = 'ⓘ';
        infoBtn.onclick = (e) => {
          e.preventDefault();
          e.stopPropagation();
          const displayHost = hostAttr || host;
          const details = `Service: ${name}\nHost: ${displayHost}\nPort: ${port}\nProtocol: ${proto}`;
          alert(details);
        };
        a.appendChild(infoBtn);
      }

      allServices.push(a);
      return a;
    }

    // Export allServices for use by search and keyboard navigation
    window.servicesData = { allServices, container };

  }catch(err){
    console.error(err);
    container.innerHTML = '<p class="notes">Error loading services.xml — see console for details.</p>';
  }
})();
