import { i18n } from './i18n'
import { sdk } from './sdk'
import { uiPort } from './utils'
import { configFile } from './file-models/config.json'

// ── System SMTP → config.json sync ───────────────────────────────────────
// The StartOS SDK exposes shared SMTP credentials via effects.getSystemSmtp.
// Passing a callback subscribes us — StartOS re-invokes the callback when
// the operator changes their System → SMTP settings. We mirror the values
// into our own config.json so the server (which polls the JSON via
// server/config.js) can pick them up without needing direct SDK access.
//
// `password` can be null in the StartOS payload — coerce to empty string
// so the Zod schema (z.string()) accepts it. The server treats "" the
// same as "auth disabled".
//
// Only meaningful in multi-tenant cloud mode (recap_mode === 'multi'),
// where the server sends magic-link sign-in emails. In single mode the
// fields exist in config.json but nothing reads them.
async function syncSystemSmtpToConfig(effects: any) {
  try {
    const smtp = await effects.getSystemSmtp({
      callback: () => {
        // Re-fire ourselves on change. Effects callbacks fire on every
        // mutation of the underlying value, so this stays in sync.
        syncSystemSmtpToConfig(effects).catch((err) => {
          console.warn('[smtp] sync callback failed:', err)
        })
      },
    })
    if (!smtp) {
      // No System SMTP configured — clear stale values so the server
      // doesn't try to send mail through a transport we no longer have
      // credentials for.
      await configFile.merge(effects, {
        smtp_host: '',
        smtp_port: 0,
        smtp_security: 'tls',
        smtp_username: '',
        smtp_password: '',
        smtp_from: '',
      })
      return
    }
    await configFile.merge(effects, {
      smtp_host: smtp.host || '',
      smtp_port: smtp.port || 0,
      smtp_security: smtp.security || 'tls',
      smtp_username: smtp.username || '',
      smtp_password: smtp.password || '',
      smtp_from: smtp.from || '',
    })
  } catch (err) {
    console.warn('[smtp] initial sync failed:', err)
  }
}

export const main = sdk.setupMain(async ({ effects }) => {
  console.info(i18n('Starting Recap...'))

  // Subscribe to System SMTP changes before the daemon starts so the
  // server boots with credentials already in config.json (no race where
  // a magic-link request arrives before the first sync).
  await syncSystemSmtpToConfig(effects)

  // Read current config to determine which mode to boot in. The
  // RECAP_MODE env var is passed to the container so the Node server
  // can branch on it without re-reading the config file at startup.
  const cfg = await configFile.read().once()
  const recapMode = cfg?.recap_mode === 'multi' ? 'multi' : 'single'

  return sdk.Daemons.of(effects).addDaemon('primary', {
    subcontainer: await sdk.SubContainer.of(
      effects,
      { imageId: 'main' },
      sdk.Mounts.of().mountVolume({
        volumeId: 'main',
        subpath: null,
        mountpoint: '/data',
        readonly: false,
      }),
      'recap-sub',
    ),
    exec: {
      command: [
        'dumb-init',
        '--',
        '/usr/local/bin/docker_entrypoint.sh',
      ],
      env: {
        RECAP_MODE: recapMode,
      },
    },
    ready: {
      display: i18n('Web Interface'),
      fn: () =>
        sdk.healthCheck.checkPortListening(effects, uiPort, {
          successMessage: i18n('Recap is ready'),
          errorMessage: i18n('Recap is not responding'),
        }),
    },
    requires: [],
  })
})
