/**
 * Context assembly - Dependency injection container
 * Assembles all context objects needed by routes
 */
const { createDockerContext } = require('./docker');
const { createCaddyContext } = require('./caddy');
const { createDnsContext } = require('./dns');
const { createSessionContext } = require('./session');
const NotificationManager = require('../managers/notification-manager');
const tailscaleManager = require('../managers/tailscale-manager');
const { TailscaleCoordClient } = require('../managers/tailscale-coord');
const fs = require('fs');

/**
 * Assemble the full application context
 * This replaces the old "god object" ctx with explicit construction
 */
function assembleContext({
  // Config
  siteConfig,
  buildDomain,
  buildServiceUrl,
  SERVICES_FILE,
  CONFIG_FILE,
  TOTP_CONFIG_FILE,
  TAILSCALE_CONFIG_FILE,
  NOTIFICATIONS_FILE,
  ERROR_LOG_FILE,
  DNS_CREDENTIALS_FILE,
  CADDYFILE_PATH,
  CADDY_ADMIN_URL,
  
  // State managers
  servicesStateManager,
  configStateManager,

  // DC-053 share store
  shareStore,
  
  // Managers
  credentialManager,
  authManager,
  licenseManager,
  healthChecker,
  updateManager,
  backupManager,
  resourceMonitor,
  auditLogger,
  portLockManager,
  selfUpdater,
  dockerMaintenance,
  logDigest,
  dockerSecurity,
  
  // Templates
  APP_TEMPLATES,
  TEMPLATE_CATEGORIES,
  DIFFICULTY_LEVELS,
  RECIPE_TEMPLATES,
  RECIPE_CATEGORIES,
  
  // Helpers
  asyncHandler,
  errorResponse,
  ok,
  fetchT,
  httpsAgent,
  log,
  logError,
  safeErrorMessage,
  getServiceById,
  readConfig,
  saveConfig,
  addServiceToConfig,
  validateURL,
  strictLimiter,
  totpConfig,
  saveTotpConfig,
  loadSiteConfig,
  loadNotificationConfig,
  resyncHealthChecker,
  
  // Middleware result
  middlewareResult,
  
  // App
  app,
}) {
  // Create domain-specific contexts
  const docker = createDockerContext(dockerSecurity);
  const caddy = createCaddyContext(CADDYFILE_PATH, CADDY_ADMIN_URL, fetchT, httpsAgent, log, siteConfig, buildDomain);
  const dns = createDnsContext(siteConfig, buildDomain, credentialManager, fetchT, httpsAgent, log, DNS_CREDENTIALS_FILE);
  const session = createSessionContext(middlewareResult);

  // Create notification manager
  const notification = new NotificationManager({
    NOTIFICATIONS_FILE,
    fetchT,
    docker,
    log,
    config: siteConfig
  });

  // --- Tailscale coordination API client --------------------------------------
  // Reads the API token from credentialManager on every call (not cached on
  // the client) so that PUT /api/v1/tailscale/settings takes effect
  // immediately without restarting the process. The metadata file
  // tailscale-config.json stores non-secret state (tailnet name, last
  // validation time, device count) so we don't have to hit the API just to
  // answer "is this configured?" in the UI.
  function loadTailscaleMetadata() {
    try {
      if (TAILSCALE_CONFIG_FILE && fs.existsSync(TAILSCALE_CONFIG_FILE)) {
        return JSON.parse(fs.readFileSync(TAILSCALE_CONFIG_FILE, 'utf8'));
      }
    } catch (_e) { /* corrupt file → treat as unconfigured */ }
    return { configured: false };
  }
  function saveTailscaleMetadata(meta) {
    if (!TAILSCALE_CONFIG_FILE) return;
    try {
      fs.writeFileSync(TAILSCALE_CONFIG_FILE, JSON.stringify(meta, null, 2), 'utf8');
    } catch (e) {
      log.error('tailscale-coord', e, null, { note: 'Failed to write tailscale-config.json' });
    }
  }
  async function getCoordClient() {
    const tok = await credentialManager.retrieve('tailscale.coord.apiToken');
    return new TailscaleCoordClient({ apiToken: tok || null });
  }

  // Assemble flat context (temporary - routes still expect this)
  // Note: tailscale interface detection lives in src/utilities/network-detector.js
  // (DC-031). The empty `tailscale` stub previously wired here was dead code
  // — verified zero readers via grep across src/.
  const ctx = {
    // Namespaced contexts
    docker,
    caddy,
    dns,
    session,
    notification,
    // Tailscale manager — wraps `tailscale status --json` with 5min cache.
    // Replaces the long-standing null stub at src/app.js:189. See
    // src/managers/tailscale-manager.js for full API surface.
    tailscale: {
      getStatus: tailscaleManager.getStatus,
      getLocalIP: tailscaleManager.getLocalIP,
      getSummary: tailscaleManager.getSummary,
      getDevices: tailscaleManager.getDevices,
      isTailscaleIP: tailscaleManager.isTailscaleIP,
      invalidateCache: tailscaleManager.invalidateCache,
      getAccessToken: tailscaleManager.getAccessToken,
      startSyncTimer: tailscaleManager.startSyncTimer,
      stopSyncTimer: tailscaleManager.stopSyncTimer,
      syncAPI: tailscaleManager.syncAPI,
    },

    // Tailscale coordination API client — talk to api.tailscale.com for
    // device management, pre-auth key creation, ACL reads/writes, and user
    // listing. Distinct from the local tailscaleManager above (which reads
    // the local tailscaled daemon). The API token is stored encrypted via
    // credentialManager and re-read on every call so settings changes take
    // effect without process restart.
    tailscaleCoord: {
      // Returns a fresh client each call — cheap (just a Map + token lookup),
      // and guarantees the latest token is used.
      getClient: getCoordClient,
      // Metadata helpers — read/write tailscale-config.json
      loadMetadata: loadTailscaleMetadata,
      saveMetadata: saveTailscaleMetadata,
      // Storage helpers — wraps credentialManager so route code doesn't
      // need to know the key naming convention.
      setApiToken: async (token) => {
        if (token) {
          await credentialManager.store('tailscale.coord.apiToken', token, {
            description: 'Tailscale coordination API token',
            source: 'settings-ui',
          });
        } else {
          await credentialManager.delete('tailscale.coord.apiToken');
        }
      },
      hasApiToken: async () => {
        const tok = await credentialManager.retrieve('tailscale.coord.apiToken');
        return !!tok;
      },
    },
    
    // App and config
    app,
    siteConfig,
    
    // State managers
    servicesStateManager,
    configStateManager,

    // DC-053 share store
    shareStore,
    
    // Managers
    credentialManager,
    authManager,
    licenseManager,
    healthChecker,
    updateManager,
    backupManager,
    resourceMonitor,
    auditLogger,
    portLockManager,
    selfUpdater,
    dockerMaintenance,
    logDigest,
    
    // Templates
    APP_TEMPLATES,
    TEMPLATE_CATEGORIES,
    DIFFICULTY_LEVELS,
    RECIPE_TEMPLATES,
    RECIPE_CATEGORIES,
    
    // Helpers
    asyncHandler,
    errorResponse,
    ok,
    fetchT,
    log,
    logError,
    safeErrorMessage,
    buildDomain,
    buildServiceUrl,
    getServiceById,
    readConfig,
    saveConfig,
    addServiceToConfig,
    validateURL,
    strictLimiter,
    
    // Config helpers
    totpConfig,
    saveTotpConfig,
    loadSiteConfig,
    loadNotificationConfig,
    resyncHealthChecker,
    
    // Middleware result (exposes renewCSRFToken etc.)
    middlewareResult,
    
    // File paths
    SERVICES_FILE,
    CONFIG_FILE,
    TOTP_CONFIG_FILE,
    TAILSCALE_CONFIG_FILE,
    NOTIFICATIONS_FILE,
    ERROR_LOG_FILE,
  };

  return ctx;
}

module.exports = { assembleContext };
