'use strict';

const { execFile: execFileCb, spawn: spawnCb } = require('child_process');
const fs = require('fs');
const net = require('net');
const path = require('path');
const { atomicWriteFileSync } = require('../atomic-write');
const {
  normalizeCloudflareAccessSettings,
} = require('./cloudflare-access');

const HOST_RE = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$/;
const UUID_RE = /\b[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\b/i;

function defaultExecFile(file, args, options = {}) {
  return new Promise((resolve, reject) => {
    execFileCb(file, args, options, (err, stdout, stderr) => {
      if (err) {
        err.stdout = stdout;
        err.stderr = stderr;
        reject(err);
        return;
      }
      resolve({ stdout, stderr });
    });
  });
}

function splitList(raw) {
  if (Array.isArray(raw)) return raw.map(String).map((s) => s.trim()).filter(Boolean);
  return String(raw || '').split(/[\s,]+/).map((s) => s.trim()).filter(Boolean);
}

function normalizeHostname(value) {
  const raw = String(value || '').trim();
  if (!raw) return '';
  let host = raw;
  try {
    const asUrl = /^https?:\/\//i.test(raw) ? new URL(raw) : new URL(`https://${raw}`);
    host = asUrl.hostname;
  } catch {
    host = raw.split('/')[0].split(':')[0];
  }
  host = host.toLowerCase().replace(/\.+$/, '');
  if (!HOST_RE.test(host)) return '';
  if (host === 'localhost' || host.endsWith('.localhost') || net.isIP(host)) return '';
  return host;
}

function normalizeEmail(value) {
  const email = String(value || '').trim().toLowerCase();
  if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email)) return '';
  return email;
}

function normalizeAccountId(value) {
  const id = String(value || '').trim();
  return /^[A-Za-z0-9_-]{4,64}$/.test(id) ? id : '';
}

function normalizeZoneId(value) {
  const id = String(value || '').trim();
  return /^[A-Za-z0-9_-]{4,64}$/.test(id) ? id : '';
}

function normalizeTunnelId(value) {
  const id = String(value || '').trim().toLowerCase();
  return UUID_RE.test(id) ? id.match(UUID_RE)[0].toLowerCase() : '';
}

function safeTunnelName(hostname) {
  const base = `ctm-${hostname.replace(/[^a-z0-9]+/g, '-')}`.replace(/-+/g, '-').replace(/^-|-$/g, '');
  return base.slice(0, 54) || 'ctm-phone';
}

function resolveCloudflaredTokenFile(rawTokenFile, defaultTokenFile, cfDir) {
  const fallback = defaultTokenFile ? path.resolve(defaultTokenFile) : '';
  const raw = String(rawTokenFile || '').trim();
  if (!raw) return fallback;
  const resolved = path.resolve(raw);
  const root = path.resolve(cfDir);
  return resolved.startsWith(`${root}${path.sep}`) ? resolved : fallback;
}

function shellQuote(value) {
  const s = String(value || '');
  if (/^[A-Za-z0-9_./:@%+=,-]+$/.test(s)) return s;
  return `'${s.replace(/'/g, `'\\''`)}'`;
}

function command(file, args) {
  const argv = [file, ...args];
  return { argv, display: argv.map(shellQuote).join(' ') };
}

function xmlEscape(value) {
  return String(value || '')
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&apos;');
}

function safeLabelPart(value) {
  return String(value || 'ctm-phone')
    .toLowerCase()
    .replace(/[^a-z0-9.-]+/g, '-')
    .replace(/-+/g, '-')
    .replace(/^-|-$/g, '')
    .slice(0, 80) || 'ctm-phone';
}

function managedStatePath(options = {}) {
  const configDir = path.resolve(options.configDir || path.join(process.env.HOME || process.cwd(), '.walle', 'data'));
  return path.join(configDir, 'cloudflared', 'managed-tunnel.json');
}

function loadManagedTunnelState(options = {}) {
  const fsImpl = options.fs || fs;
  try {
    const raw = fsImpl.readFileSync(managedStatePath(options), 'utf8');
    const parsed = JSON.parse(raw);
    return parsed && typeof parsed === 'object' ? parsed : null;
  } catch {
    return null;
  }
}

function writeManagedTunnelState(state, options = {}) {
  const fsImpl = options.fs || fs;
  const statePath = managedStatePath(options);
  fsImpl.mkdirSync(path.dirname(statePath), { recursive: true, mode: 0o700 });
  try { fsImpl.chmodSync(path.dirname(statePath), 0o700); } catch {}
  const body = JSON.stringify({ version: 1, ...state }, null, 2) + '\n';
  if (options.atomicWriteFileSync || fsImpl === fs) {
    (options.atomicWriteFileSync || atomicWriteFileSync)(statePath, body, { mode: 0o600 });
  } else {
    fsImpl.writeFileSync(statePath, body, { mode: 0o600 });
  }
  try { fsImpl.chmodSync(statePath, 0o600); } catch {}
}

function pidIsRunning(pid) {
  const n = Number(pid);
  if (!Number.isFinite(n) || n <= 0) return false;
  try {
    process.kill(n, 0);
    return true;
  } catch (err) {
    return err && err.code === 'EPERM';
  }
}

async function launchdLabelIsRunning(label, options = {}) {
  if (!label) return false;
  const platform = options.platform || process.platform;
  if (platform !== 'darwin') return false;
  const uid = typeof process.getuid === 'function' ? process.getuid() : null;
  if (uid == null) return false;
  const execFile = options.execFile || defaultExecFile;
  try {
    await execFile('launchctl', ['print', `gui/${uid}/${label}`], {
      encoding: 'utf8',
      timeout: options.statusTimeoutMs || 1500,
      maxBuffer: 512 * 1024,
    });
    return true;
  } catch {
    return false;
  }
}

async function detectManagedCloudflaredTunnel(options = {}) {
  const state = loadManagedTunnelState(options);
  if (!state) return { configured: false, running: false };
  const managed = {
    configured: true,
    running: false,
    mode: state.mode || '',
    label: state.label || '',
    pid: state.pid || null,
    hostname: state.hostname || '',
    origin: state.origin || '',
    mobile_url: state.mobile_url || '',
    tunnel_name: state.tunnel_name || '',
    tunnel_id: state.tunnel_id || '',
    remote_config: !!state.remote_config,
    token_file: state.token_file || '',
    config_path: state.config_path || '',
    plist_path: state.plist_path || '',
    log_path: state.log_path || '',
    error_log_path: state.error_log_path || '',
    run_command: state.run_command || '',
    started_at: state.started_at || '',
    state_path: managedStatePath(options),
  };
  if (managed.mode === 'process') managed.running = pidIsRunning(managed.pid);
  if (managed.mode === 'launchd') managed.running = await launchdLabelIsRunning(managed.label, options);
  return managed;
}

async function resolveCloudflaredBinary(options = {}) {
  if (options.cloudflaredPath) return options.cloudflaredPath;
  const execFile = options.execFile || defaultExecFile;
  try {
    const result = await execFile('which', ['cloudflared'], {
      encoding: 'utf8',
      timeout: options.timeoutMs || 2500,
      maxBuffer: 256 * 1024,
    });
    const resolved = String(result?.stdout || '').trim().split(/\r?\n/)[0];
    if (path.isAbsolute(resolved)) return resolved;
  } catch {}
  return 'cloudflared';
}

function cloudflaredLaunchdPlist({ label, binary, args, workingDir, env, logPath, errorLogPath }) {
  const programArgs = [binary, ...args]
    .map((arg) => `    <string>${xmlEscape(arg)}</string>`)
    .join('\n');
  const envLines = Object.entries(env || {})
    .filter(([, value]) => value != null && String(value) !== '')
    .map(([key, value]) => `    <key>${xmlEscape(key)}</key>\n    <string>${xmlEscape(value)}</string>`)
    .join('\n');
  return `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>${xmlEscape(label)}</string>
  <key>ProgramArguments</key>
  <array>
${programArgs}
  </array>
  <key>WorkingDirectory</key>
  <string>${xmlEscape(workingDir)}</string>
  <key>EnvironmentVariables</key>
  <dict>
${envLines}
  </dict>
  <key>RunAtLoad</key>
  <true/>
  <key>KeepAlive</key>
  <true/>
  <key>ThrottleInterval</key>
  <integer>5</integer>
  <key>StandardOutPath</key>
  <string>${xmlEscape(logPath)}</string>
  <key>StandardErrorPath</key>
  <string>${xmlEscape(errorLogPath)}</string>
</dict>
</plist>`;
}

function cloudflaredConfigContent(setup) {
  const credentialLine = setup.credentials_file ? `credentials-file: ${JSON.stringify(setup.credentials_file)}` : '';
  return [
    `tunnel: ${setup.tunnel_id || setup.tunnel_name}`,
    credentialLine,
    'ingress:',
    `  - hostname: ${setup.hostname}`,
    `    service: ${setup.local_service}`,
    '  - service: http_status:404',
    '',
  ].filter((line) => line !== '').join('\n');
}

function buildCloudflareFallbackSetup(input = {}, options = {}) {
  const hostname = normalizeHostname(input.hostname || input.host || input.cf_host || input.cloudflare_host);
  if (!hostname) {
    return { ok: false, error_code: 'cloudflare_hostname_invalid', error: 'Enter a valid public Cloudflare hostname.' };
  }
  const allowedEmail = normalizeEmail(
    input.allowed_email
    || input.allowedEmail
    || splitList(input.allowed_emails || input.allowedEmails || input.emails)[0]
    || '',
  );
  if (!allowedEmail) {
    return { ok: false, error_code: 'cloudflare_email_invalid', error: 'Enter the owner email allowed by Cloudflare Access.' };
  }
  const teamDomain = normalizeHostname(input.team_domain || input.teamDomain || '');
  const aud = String(input.aud || input.audience || '').replace(/[\r\n]/g, '').trim();
  const tunnelId = normalizeTunnelId(input.tunnel_id || input.tunnelId || '');
  const tunnelName = String(input.tunnel_name || input.tunnelName || safeTunnelName(hostname))
    .trim()
    .toLowerCase()
    .replace(/[^a-z0-9-]/g, '-')
    .replace(/-+/g, '-')
    .replace(/^-|-$/g, '')
    .slice(0, 54) || safeTunnelName(hostname);

  const configDir = path.resolve(options.configDir || path.join(process.env.HOME || process.cwd(), '.walle', 'data'));
  const homeDir = path.resolve(options.homeDir || process.env.HOME || process.cwd());
  const port = Number.isFinite(Number(options.port)) ? Number(options.port) : 3456;
  const origin = `https://${hostname}`;
  const localService = `http://127.0.0.1:${port}`;
  const cfDir = path.join(configDir, 'cloudflared');
  const configPath = path.join(cfDir, `${tunnelName}.yml`);
  const tunnelToken = String(input.tunnel_token || input.tunnelToken || '').trim();
  const remoteConfig = !!(input.remote_config || input.remoteConfig || tunnelToken || input.tunnel_token_file || input.tunnelTokenFile);
  const defaultTokenFile = remoteConfig && tunnelId ? path.join(cfDir, `${tunnelId}.token`) : '';
  const tokenFile = resolveCloudflaredTokenFile(input.tunnel_token_file || input.tunnelTokenFile, defaultTokenFile, cfDir);
  const credentialsFile = tunnelId ? path.join(homeDir, '.cloudflared', `${tunnelId}.json`) : '';
  const jwksUrl = teamDomain ? `https://${teamDomain}/cdn-cgi/access/certs` : '';

  const access = {
    enabled: !!(teamDomain && aud),
    configured: !!(teamDomain && aud),
    host: hostname,
    team_domain: teamDomain,
    aud,
    allowed_emails: [allowedEmail],
    jwks_url: jwksUrl,
  };
  const env = access.configured
    ? normalizeCloudflareAccessSettings({
      enabled: true,
      hosts: hostname,
      team_domain: teamDomain,
      aud,
      allowed_emails: allowedEmail,
      jwks_url: jwksUrl,
    }).env
    : {};
  if (access.configured) env.CTM_ALLOWED_ORIGINS = origin;

  const setup = {
    ok: true,
    hostname,
    origin,
    mobile_url: `${origin}/m/`,
    local_service: localService,
    tunnel_name: tunnelName,
    tunnel_id: tunnelId,
    remote_config: remoteConfig,
    token_file: tokenFile,
    credentials_file: credentialsFile,
    config_path: configPath,
    config_written: false,
    token_file_written: false,
    access,
    env,
    commands: {
      login: command('cloudflared', ['tunnel', 'login']),
      create_tunnel: command('cloudflared', ['tunnel', 'create', tunnelName]),
      route_dns: command('cloudflared', ['tunnel', 'route', 'dns', tunnelId || tunnelName, hostname]),
      run: remoteConfig && tokenFile
        ? command('cloudflared', ['tunnel', '--no-autoupdate', 'run', '--token-file', tokenFile])
        : command('cloudflared', ['tunnel', '--config', configPath, 'run', tunnelId || tunnelName]),
    },
  };
  Object.defineProperty(setup, 'tunnel_token', {
    value: tunnelToken,
    enumerable: false,
    configurable: true,
    writable: true,
  });
  setup.config_content = cloudflaredConfigContent(setup);
  return setup;
}

function cloudflaredLoginCertCandidates(homeDir, env = process.env) {
  const candidates = [];
  const add = (value) => {
    const raw = String(value || '').trim();
    if (!raw) return;
    const expanded = raw.replace(/^~(?=$|\/|\\)/, homeDir);
    const resolved = path.resolve(expanded);
    if (!candidates.includes(resolved)) candidates.push(resolved);
  };
  add(env.TUNNEL_ORIGIN_CERT);
  add(path.join(homeDir, '.cloudflared', 'cert.pem'));
  return candidates;
}

function detectLoginCertPath(paths, fsImpl) {
  for (const certPath of paths) {
    if (fsImpl.existsSync?.(certPath)) return certPath;
  }
  return '';
}

function parseCloudflaredLoginProcesses(output) {
  return String(output || '')
    .split(/\r?\n/)
    .map((line) => line.trim())
    .filter((line) => /\bcloudflared\b/.test(line) && /\btunnel\b/.test(line) && /\blogin\b/.test(line));
}

async function detectCloudflaredLoginProcess(options = {}) {
  const execFile = options.execFile || defaultExecFile;
  try {
    const result = await execFile('pgrep', ['-fl', 'cloudflared'], {
      encoding: 'utf8',
      timeout: options.processTimeoutMs || 1000,
      maxBuffer: 256 * 1024,
    });
    const matches = parseCloudflaredLoginProcesses(result?.stdout || '');
    return { running: matches.length > 0, count: matches.length };
  } catch {
    return { running: false, count: 0 };
  }
}

async function detectCloudflaredSetup(options = {}) {
  const execFile = options.execFile || defaultExecFile;
  const fsImpl = options.fs || fs;
  const homeDir = path.resolve(options.homeDir || process.env.HOME || process.cwd());
  const certCandidates = cloudflaredLoginCertCandidates(homeDir, options.env || process.env);
  const foundCertPath = detectLoginCertPath(certCandidates, fsImpl);
  const loginCertPath = foundCertPath || certCandidates[0] || path.join(homeDir, '.cloudflared', 'cert.pem');
  const managedTunnel = await detectManagedCloudflaredTunnel(options);
  const loginProcess = await detectCloudflaredLoginProcess(options);
  try {
    const result = await execFile('cloudflared', ['--version'], {
      encoding: 'utf8',
      timeout: options.timeoutMs || 2500,
      maxBuffer: 1024 * 1024,
    });
    return {
      installed: true,
      available: true,
      version: String(result?.stdout || '').trim(),
      login_cert_path: loginCertPath,
      login_cert_checked_paths: certCandidates,
      login_cert_exists: !!foundCertPath,
      login_process_running: loginProcess.running,
      login_process_count: loginProcess.count,
      login_command: command('cloudflared', ['tunnel', 'login']),
      managed_tunnel: managedTunnel,
    };
  } catch (err) {
    if (err?.code === 'ENOENT') {
      return {
        installed: false,
        available: false,
        error_code: 'cloudflared_cli_missing',
        error: 'cloudflared is not installed or not on PATH.',
        login_cert_path: loginCertPath,
        login_cert_checked_paths: certCandidates,
        login_cert_exists: false,
        login_process_running: loginProcess.running,
        login_process_count: loginProcess.count,
        login_command: command('cloudflared', ['tunnel', 'login']),
        managed_tunnel: managedTunnel,
      };
    }
    return {
      installed: true,
      available: false,
      error_code: 'cloudflared_version_failed',
      error: String(err?.stderr || err?.message || err || 'cloudflared failed').slice(0, 500),
      login_cert_path: loginCertPath,
      login_cert_checked_paths: certCandidates,
      login_cert_exists: !!foundCertPath,
      login_process_running: loginProcess.running,
      login_process_count: loginProcess.count,
      login_command: command('cloudflared', ['tunnel', 'login']),
      managed_tunnel: managedTunnel,
    };
  }
}

async function cfApiRequest(fetchImpl, url, token, options = {}) {
  const method = options.method || (Object.prototype.hasOwnProperty.call(options, 'body') ? 'POST' : 'GET');
  const headers = {
    Authorization: `Bearer ${token}`,
  };
  const request = { method, headers };
  if (Object.prototype.hasOwnProperty.call(options, 'body')) {
    headers['Content-Type'] = 'application/json';
    request.body = JSON.stringify(options.body);
  }
  const response = await fetchImpl(url, {
    ...request,
  });
  let payload = null;
  try { payload = await response.json(); } catch {}
  if (!response.ok || payload?.success === false) {
    const message = payload?.errors?.[0]?.message || `Cloudflare API returned ${response.status || 0}`;
    throw new Error(message);
  }
  return payload?.result || {};
}

async function cfApiJson(fetchImpl, url, token, body) {
  return cfApiRequest(fetchImpl, url, token, { method: 'POST', body });
}

function cloudflareZoneCandidates(hostname) {
  const parts = String(hostname || '').toLowerCase().split('.').filter(Boolean);
  const candidates = [];
  for (let i = 0; i <= Math.max(0, parts.length - 2); i += 1) {
    const zone = parts.slice(i).join('.');
    if (zone && !candidates.includes(zone)) candidates.push(zone);
  }
  return candidates;
}

function likelyCloudflareParentDomain(hostname) {
  const parts = String(hostname || '').toLowerCase().split('.').filter(Boolean);
  if (parts.length < 2) return '';
  return parts.slice(-2).join('.');
}

async function resolveCloudflareZone(input = {}, options = {}) {
  const fetchImpl = options.fetch || global.fetch;
  if (typeof fetchImpl !== 'function') {
    return { ok: false, error_code: 'cloudflare_fetch_unavailable', error: 'Fetch is not available.' };
  }
  const token = String(input.api_token || input.apiToken || input.cloudflare_api_token || '').trim();
  if (!token) return { ok: false, error_code: 'cloudflare_api_token_missing', error: 'Cloudflare API token is required.' };
  const accountId = normalizeAccountId(input.account_id || input.accountId || '');
  const hostname = normalizeHostname(input.hostname || input.host || '');
  if (!hostname) return { ok: false, error_code: 'cloudflare_hostname_invalid', error: 'Enter a valid public Cloudflare hostname.' };
  const zoneId = normalizeZoneId(input.zone_id || input.zoneId || '');
  if (zoneId) return { ok: true, id: zoneId, name: '', account_id: accountId, account_name: '' };

  try {
    for (const name of cloudflareZoneCandidates(hostname)) {
      const qs = new URLSearchParams({ name, per_page: '1' });
      if (accountId) qs.set('account.id', accountId);
      const zones = await cfApiRequest(fetchImpl, `https://api.cloudflare.com/client/v4/zones?${qs.toString()}`, token, { method: 'GET' });
      const zone = Array.isArray(zones) ? zones.find((z) => z && z.id) : null;
      if (zone) {
        const account = zone.account || {};
        return {
          ok: true,
          id: String(zone.id),
          name: String(zone.name || name),
          account_id: normalizeAccountId(account.id || zone.account_id || zone.accountId || accountId),
          account_name: String(account.name || zone.account_name || zone.accountName || ''),
          status: String(zone.status || ''),
          name_servers: Array.isArray(zone.name_servers) ? zone.name_servers.map(String).filter(Boolean) : [],
        };
      }
    }
    const parentDomain = likelyCloudflareParentDomain(hostname);
    const parentHint = parentDomain && parentDomain !== hostname
      ? ` Add the parent domain to Cloudflare first, for example ${parentDomain} for ${hostname}.`
      : ' Add this domain to Cloudflare first.';
    return {
      ok: false,
      error_code: 'cloudflare_zone_not_found',
      error: `Cloudflare could not find a DNS zone for ${hostname} in this account.${parentHint} Turn on automatic domain add to let CTM add the missing zone and show the registrar nameservers. Registrar nameserver changes still happen outside CTM. Use Tailscale or a hostname under a domain already listed in Cloudflare if you do not want to move the domain first.`,
    };
  } catch (err) {
    return {
      ok: false,
      error_code: 'cloudflare_zone_lookup_failed',
      error: String(err?.message || err || 'Cloudflare zone lookup failed').slice(0, 500),
    };
  }
}

async function resolveCloudflareAccountFromToken(input = {}, options = {}) {
  const fetchImpl = options.fetch || global.fetch;
  if (typeof fetchImpl !== 'function') {
    return { ok: false, error_code: 'cloudflare_fetch_unavailable', error: 'Fetch is not available.' };
  }
  const token = String(input.api_token || input.apiToken || input.cloudflare_api_token || '').trim();
  if (!token) return { ok: false, error_code: 'cloudflare_api_token_missing', error: 'Cloudflare API token is required.' };
  const explicitAccountId = normalizeAccountId(input.account_id || input.accountId || '');
  if (explicitAccountId) return { ok: true, account_id: explicitAccountId, account_name: '', source: 'input' };

  try {
    const accounts = await cfApiRequest(fetchImpl, 'https://api.cloudflare.com/client/v4/accounts?per_page=2', token, { method: 'GET' });
    const list = Array.isArray(accounts) ? accounts.filter((a) => a && normalizeAccountId(a.id)) : [];
    if (list.length === 1) {
      return {
        ok: true,
        account_id: normalizeAccountId(list[0].id),
        account_name: String(list[0].name || ''),
        source: 'accounts',
      };
    }
    if (list.length === 0) {
      return {
        ok: false,
        error_code: 'cloudflare_account_id_needed',
        error: 'CTM can add the missing Cloudflare zone, but this token cannot see a Cloudflare account. Open Advanced and enter the Account ID, or create the token with account scope All accounts.',
      };
    }
    return {
      ok: false,
      error_code: 'cloudflare_account_id_needed',
      error: 'CTM can add the missing Cloudflare zone, but this token can see multiple accounts. Open Advanced and enter the Account ID to choose where the domain should be added.',
    };
  } catch (err) {
    return {
      ok: false,
      error_code: 'cloudflare_account_lookup_failed',
      error: `CTM can add the missing Cloudflare zone, but it could not infer the Cloudflare account. Open Advanced and enter the Account ID manually. Cloudflare said: ${String(err?.message || err || 'account lookup failed').slice(0, 300)}`,
    };
  }
}

async function createCloudflareZone(input = {}, options = {}) {
  const fetchImpl = options.fetch || global.fetch;
  if (typeof fetchImpl !== 'function') {
    return { ok: false, error_code: 'cloudflare_fetch_unavailable', error: 'Fetch is not available.' };
  }
  const token = String(input.api_token || input.apiToken || input.cloudflare_api_token || '').trim();
  if (!token) return { ok: false, error_code: 'cloudflare_api_token_missing', error: 'Cloudflare API token is required.' };
  const hostname = normalizeHostname(input.hostname || input.host || '');
  const zoneName = normalizeHostname(input.zone_name || input.zoneName || likelyCloudflareParentDomain(hostname));
  if (!zoneName) return { ok: false, error_code: 'cloudflare_zone_name_invalid', error: 'CTM could not infer the parent domain to add to Cloudflare.' };
  const account = await resolveCloudflareAccountFromToken(input, options);
  if (!account.ok) return account;

  try {
    const zone = await cfApiRequest(fetchImpl, 'https://api.cloudflare.com/client/v4/zones', token, {
      method: 'POST',
      body: {
        name: zoneName,
        account: { id: account.account_id },
        type: 'full',
      },
    });
    return {
      ok: true,
      id: String(zone.id || ''),
      name: String(zone.name || zoneName),
      account_id: normalizeAccountId(zone.account?.id || account.account_id),
      account_name: String(zone.account?.name || account.account_name || ''),
      status: String(zone.status || ''),
      name_servers: Array.isArray(zone.name_servers) ? zone.name_servers.map(String).filter(Boolean) : [],
      original_name_servers: Array.isArray(zone.original_name_servers) ? zone.original_name_servers.map(String).filter(Boolean) : [],
      original_registrar: String(zone.original_registrar || ''),
    };
  } catch (err) {
    return {
      ok: false,
      error_code: 'cloudflare_zone_create_failed',
      error: `CTM could not add ${zoneName} to Cloudflare. Cloudflare said: ${String(err?.message || err || 'zone create failed').slice(0, 300)}`,
    };
  }
}

async function resolveCloudflareAccount(input = {}, options = {}) {
  const fetchImpl = options.fetch || global.fetch;
  if (typeof fetchImpl !== 'function') {
    return { ok: false, error_code: 'cloudflare_fetch_unavailable', error: 'Fetch is not available.' };
  }
  const token = String(input.api_token || input.apiToken || input.cloudflare_api_token || '').trim();
  if (!token) return { ok: false, error_code: 'cloudflare_api_token_missing', error: 'Cloudflare API token is required.' };
  const explicitAccountId = normalizeAccountId(input.account_id || input.accountId || '');
  if (explicitAccountId) return { ok: true, account_id: explicitAccountId, account_name: '', source: 'input' };

  const zone = await resolveCloudflareZone(input, options);
  if (zone.ok && zone.account_id) {
    return {
      ok: true,
      account_id: zone.account_id,
      account_name: zone.account_name || '',
      zone_id: zone.id,
      zone_name: zone.name,
      source: 'zone',
    };
  }
  if (!zone.ok) return zone;

  try {
    const accounts = await cfApiRequest(fetchImpl, 'https://api.cloudflare.com/client/v4/accounts?per_page=2', token, { method: 'GET' });
    const list = Array.isArray(accounts) ? accounts.filter((a) => a && normalizeAccountId(a.id)) : [];
    if (list.length === 1) {
      return {
        ok: true,
        account_id: normalizeAccountId(list[0].id),
        account_name: String(list[0].name || ''),
        zone_id: zone.id,
        zone_name: zone.name,
        source: 'accounts',
      };
    }
    return {
      ok: false,
      error_code: 'cloudflare_account_id_needed',
      error: 'CTM could not infer the Cloudflare account ID. Add Zone Read to the API token, or open Advanced and enter the Account ID manually.',
    };
  } catch (err) {
    return {
      ok: false,
      error_code: 'cloudflare_account_lookup_failed',
      error: `CTM could not infer the Cloudflare account ID. Add Zone Read to the API token, or open Advanced and enter it manually. Cloudflare said: ${String(err?.message || err || 'account lookup failed').slice(0, 300)}`,
    };
  }
}

async function resolveCloudflareOrganization(input = {}, options = {}) {
  const fetchImpl = options.fetch || global.fetch;
  if (typeof fetchImpl !== 'function') {
    return { ok: false, error_code: 'cloudflare_fetch_unavailable', error: 'Fetch is not available.' };
  }
  const explicitTeamDomain = normalizeHostname(input.team_domain || input.teamDomain || '');
  if (explicitTeamDomain) return { ok: true, team_domain: explicitTeamDomain, source: 'input' };
  const token = String(input.api_token || input.apiToken || input.cloudflare_api_token || '').trim();
  if (!token) return { ok: false, error_code: 'cloudflare_api_token_missing', error: 'Cloudflare API token is required.' };
  const accountId = normalizeAccountId(input.account_id || input.accountId || '');
  const zoneId = normalizeZoneId(input.zone_id || input.zoneId || '');
  const base = accountId
    ? `https://api.cloudflare.com/client/v4/accounts/${encodeURIComponent(accountId)}`
    : (zoneId ? `https://api.cloudflare.com/client/v4/zones/${encodeURIComponent(zoneId)}` : '');
  if (!base) {
    return {
      ok: false,
      error_code: 'cloudflare_org_lookup_missing_scope',
      error: 'CTM needs a Cloudflare account or zone before it can discover the Zero Trust team domain.',
    };
  }

  try {
    const org = await cfApiRequest(fetchImpl, `${base}/access/organizations`, token, { method: 'GET' });
    const teamDomain = normalizeHostname(org.auth_domain || org.authDomain || '');
    if (!teamDomain) {
      return {
        ok: false,
        error_code: 'cloudflare_team_domain_missing',
        error: 'Cloudflare did not return a Zero Trust team domain. If Zero Trust is already configured, open Advanced and enter the Team Domain manually.',
      };
    }
    return {
      ok: true,
      team_domain: teamDomain,
      organization_name: String(org.name || ''),
      source: accountId ? 'account_org' : 'zone_org',
    };
  } catch (err) {
    return {
      ok: false,
      error_code: 'cloudflare_team_domain_lookup_failed',
      error: `CTM could not discover the Cloudflare Zero Trust team domain. Add Access Organizations Read to the API token, or open Advanced and enter it manually. Cloudflare said: ${String(err?.message || err || 'organization lookup failed').slice(0, 300)}`,
    };
  }
}

async function resolveCloudflareSetupContext(input = {}, options = {}) {
  const account = await resolveCloudflareAccount(input, options);
  if (!account.ok) return account;
  const zoneId = normalizeZoneId(input.zone_id || input.zoneId || account.zone_id || '');
  const org = await resolveCloudflareOrganization({
    ...input,
    account_id: account.account_id,
    zone_id: zoneId,
  }, options);
  if (!org.ok) return org;
  return {
    ok: true,
    account_id: account.account_id,
    account_name: account.account_name || '',
    zone_id: zoneId,
    zone_name: account.zone_name || '',
    team_domain: org.team_domain,
    organization_name: org.organization_name || '',
    sources: {
      account: account.source || '',
      organization: org.source || '',
    },
  };
}

async function upsertCloudflareTunnelDns(input = {}, options = {}) {
  const fetchImpl = options.fetch || global.fetch;
  if (typeof fetchImpl !== 'function') {
    return { ok: false, error_code: 'cloudflare_fetch_unavailable', error: 'Fetch is not available.' };
  }
  const token = String(input.api_token || input.apiToken || input.cloudflare_api_token || '').trim();
  if (!token) return { ok: false, error_code: 'cloudflare_api_token_missing', error: 'Cloudflare API token is required.' };
  const hostname = normalizeHostname(input.hostname || input.host || '');
  if (!hostname) return { ok: false, error_code: 'cloudflare_hostname_invalid', error: 'Enter a valid public Cloudflare hostname.' };
  const tunnelId = normalizeTunnelId(input.tunnel_id || input.tunnelId || '');
  if (!tunnelId) return { ok: false, error_code: 'cloudflare_tunnel_id_missing', error: 'Cloudflare tunnel ID is required for DNS routing.' };

  const zone = await resolveCloudflareZone(input, options);
  if (!zone.ok) return zone;
  try {
    const base = `https://api.cloudflare.com/client/v4/zones/${encodeURIComponent(zone.id)}/dns_records`;
    const listQs = new URLSearchParams({ type: 'CNAME', name: hostname, per_page: '1' });
    const existing = await cfApiRequest(fetchImpl, `${base}?${listQs.toString()}`, token, { method: 'GET' });
    const body = {
      type: 'CNAME',
      name: hostname,
      content: `${tunnelId}.cfargotunnel.com`,
      proxied: true,
    };
    const first = Array.isArray(existing) ? existing.find((r) => r && r.id) : null;
    const record = first
      ? await cfApiRequest(fetchImpl, `${base}/${encodeURIComponent(first.id)}`, token, { method: 'PATCH', body })
      : await cfApiRequest(fetchImpl, base, token, { method: 'POST', body });
    return {
      ok: true,
      zone_id: zone.id,
      zone_name: zone.name,
      record_id: String(record.id || first?.id || ''),
      hostname,
      target: body.content,
    };
  } catch (err) {
    return {
      ok: false,
      error_code: 'cloudflare_dns_failed',
      error: String(err?.message || err || 'Cloudflare DNS routing failed').slice(0, 500),
    };
  }
}

async function provisionCloudflareAccess(input = {}, options = {}) {
  const fetchImpl = options.fetch || global.fetch;
  if (typeof fetchImpl !== 'function') {
    return { ok: false, error_code: 'cloudflare_fetch_unavailable', error: 'Fetch is not available.' };
  }
  const token = String(input.api_token || input.apiToken || input.cloudflare_api_token || '').trim();
  if (!token) return { ok: false, error_code: 'cloudflare_api_token_missing', error: 'Cloudflare API token is required.' };
  const account = await resolveCloudflareAccount(input, options);
  if (!account.ok) return account;
  const accountId = account.account_id;
  const hostname = normalizeHostname(input.hostname || input.host || '');
  if (!hostname) return { ok: false, error_code: 'cloudflare_hostname_invalid', error: 'Enter a valid public Cloudflare hostname.' };
  const allowedEmail = normalizeEmail(input.allowed_email || input.allowedEmail || splitList(input.allowed_emails || input.emails)[0] || '');
  if (!allowedEmail) return { ok: false, error_code: 'cloudflare_email_invalid', error: 'Enter the owner email allowed by Cloudflare Access.' };

  try {
    const base = `https://api.cloudflare.com/client/v4/accounts/${encodeURIComponent(accountId)}`;
    const app = await cfApiJson(fetchImpl, `${base}/access/apps`, token, {
      domain: hostname,
      type: 'self_hosted',
      name: String(input.app_name || input.appName || 'CTM Phone').slice(0, 80),
      app_launcher_visible: false,
      session_duration: '24h',
    });
    const appId = String(app.id || '').trim();
    const aud = String(app.aud || '').trim();
    if (!appId || !aud) throw new Error('Cloudflare Access application response did not include id and aud.');
    const policy = await cfApiJson(fetchImpl, `${base}/access/apps/${encodeURIComponent(appId)}/policies`, token, {
      name: 'CTM owner',
      decision: 'allow',
      include: [{ email: { email: allowedEmail } }],
      precedence: 1,
      session_duration: '24h',
    });
    return {
      ok: true,
      app_id: appId,
      policy_id: String(policy.id || '').trim(),
      aud,
      hostname,
      allowed_email: allowedEmail,
    };
  } catch (err) {
    return {
      ok: false,
      error_code: 'cloudflare_api_failed',
      error: String(err?.message || err || 'Cloudflare API provisioning failed').slice(0, 500),
    };
  }
}

function extractCloudflareTunnelToken(result) {
  if (typeof result === 'string') return result.trim();
  return String(result?.token || result?.tunnel_token || '').trim();
}

async function provisionCloudflareTunnel(input = {}, options = {}) {
  const fetchImpl = options.fetch || global.fetch;
  if (typeof fetchImpl !== 'function') {
    return { ok: false, error_code: 'cloudflare_fetch_unavailable', error: 'Fetch is not available.' };
  }
  const token = String(input.api_token || input.apiToken || input.cloudflare_api_token || '').trim();
  if (!token) return { ok: false, error_code: 'cloudflare_api_token_missing', error: 'Cloudflare API token is required.' };
  const account = await resolveCloudflareAccount(input, options);
  if (!account.ok) return account;
  const accountId = account.account_id;
  const hostname = normalizeHostname(input.hostname || input.host || '');
  if (!hostname) return { ok: false, error_code: 'cloudflare_hostname_invalid', error: 'Enter a valid public Cloudflare hostname.' };
  const tunnelName = String(input.tunnel_name || input.tunnelName || safeTunnelName(hostname))
    .trim()
    .toLowerCase()
    .replace(/[^a-z0-9-]/g, '-')
    .replace(/-+/g, '-')
    .replace(/^-|-$/g, '')
    .slice(0, 54) || safeTunnelName(hostname);
  const localService = String(input.local_service || input.localService || '').trim() || 'http://127.0.0.1:3456';
  let tunnelId = normalizeTunnelId(input.tunnel_id || input.tunnelId || '');
  let tunnelToken = String(input.tunnel_token || input.tunnelToken || '').trim();

  try {
    const base = `https://api.cloudflare.com/client/v4/accounts/${encodeURIComponent(accountId)}`;
    let created = null;
    if (!tunnelId) {
      created = await cfApiRequest(fetchImpl, `${base}/cfd_tunnel`, token, {
        method: 'POST',
        body: {
          name: tunnelName,
          config_src: 'cloudflare',
        },
      });
      tunnelId = normalizeTunnelId(created?.id || '');
      tunnelToken = extractCloudflareTunnelToken(created);
      if (!tunnelId) throw new Error('Cloudflare Tunnel response did not include a tunnel UUID.');
      if (!tunnelToken) throw new Error('Cloudflare Tunnel response did not include a tunnel token.');
    } else if (!tunnelToken) {
      const tokenResult = await cfApiRequest(fetchImpl, `${base}/cfd_tunnel/${encodeURIComponent(tunnelId)}/token`, token, { method: 'GET' });
      tunnelToken = extractCloudflareTunnelToken(tokenResult);
      if (!tunnelToken) throw new Error('Cloudflare Tunnel token endpoint did not return a tunnel token.');
    }

    const config = await cfApiRequest(fetchImpl, `${base}/cfd_tunnel/${encodeURIComponent(tunnelId)}/configurations`, token, {
      method: 'PUT',
      body: {
        config: {
          ingress: [
            { hostname, service: localService },
            { service: 'http_status:404' },
          ],
        },
      },
    });
    const dns = input.route_dns === false || input.routeDns === false
      ? null
      : await upsertCloudflareTunnelDns({ ...input, hostname, tunnel_id: tunnelId }, options);
    if (dns && !dns.ok) return dns;
    return {
      ok: true,
      tunnel_id: tunnelId,
      tunnel_name: tunnelName,
      tunnel_token: tunnelToken,
      account_tag: String(created?.account_tag || created?.accountTag || accountId),
      remote_config: true,
      config,
      dns_record: dns,
    };
  } catch (err) {
    return {
      ok: false,
      error_code: 'cloudflare_tunnel_api_failed',
      error: String(err?.message || err || 'Cloudflare Tunnel API provisioning failed').slice(0, 500),
    };
  }
}

function writeCloudflaredConfig(setup, options = {}) {
  const fsImpl = options.fs || fs;
  fsImpl.mkdirSync(path.dirname(setup.config_path), { recursive: true, mode: 0o700 });
  try { fsImpl.chmodSync(path.dirname(setup.config_path), 0o700); } catch {}
  if (options.atomicWriteFileSync || fsImpl === fs) {
    (options.atomicWriteFileSync || atomicWriteFileSync)(setup.config_path, setup.config_content, { mode: 0o600 });
  } else {
    fsImpl.writeFileSync(setup.config_path, setup.config_content, { mode: 0o600 });
  }
  try { fsImpl.chmodSync(setup.config_path, 0o600); } catch {}
}

function writeCloudflaredTokenFile(setup, options = {}) {
  const token = String(setup?.tunnel_token || '').trim();
  const tokenFile = String(setup?.token_file || '').trim();
  if (!token || !tokenFile) return false;
  const fsImpl = options.fs || fs;
  fsImpl.mkdirSync(path.dirname(tokenFile), { recursive: true, mode: 0o700 });
  try { fsImpl.chmodSync(path.dirname(tokenFile), 0o700); } catch {}
  if (options.atomicWriteFileSync || fsImpl === fs) {
    (options.atomicWriteFileSync || atomicWriteFileSync)(tokenFile, `${token}\n`, { mode: 0o600 });
  } else {
    fsImpl.writeFileSync(tokenFile, `${token}\n`, { mode: 0o600 });
  }
  try { fsImpl.chmodSync(tokenFile, 0o600); } catch {}
  setup.token_file_written = true;
  return true;
}

function parseTunnelId(stdout, stderr) {
  const match = String(`${stdout || ''}\n${stderr || ''}`).match(UUID_RE);
  return match ? match[0].toLowerCase() : '';
}

async function startCloudflaredTunnel(setup, options = {}) {
  const fsImpl = options.fs || fs;
  const configDir = path.resolve(options.configDir || path.join(process.env.HOME || process.cwd(), '.walle', 'data'));
  const homeDir = path.resolve(options.homeDir || process.env.HOME || process.cwd());
  const logDir = path.join(configDir, 'logs');
  writeCloudflaredTokenFile(setup, options);
  const runArgs = setup.commands.run.argv.slice(1);
  const runCommand = setup.commands.run.display;
  fsImpl.mkdirSync(logDir, { recursive: true, mode: 0o700 });
  try { fsImpl.chmodSync(logDir, 0o700); } catch {}

  const logPath = path.join(logDir, `${setup.tunnel_name}.cloudflared.log`);
  const errorLogPath = path.join(logDir, `${setup.tunnel_name}.cloudflared.err`);
  const platform = options.platform || process.platform;
  const startedAt = new Date().toISOString();

  if (platform === 'darwin' && options.preferLaunchd !== false) {
    const execFile = options.execFile || defaultExecFile;
    const binary = await resolveCloudflaredBinary(options);
    const label = `com.walle.ctm-cloudflared.${safeLabelPart(setup.tunnel_name || setup.hostname)}`;
    const plistDir = path.join(homeDir, 'Library', 'LaunchAgents');
    const plistPath = path.join(plistDir, `${label}.plist`);
    fsImpl.mkdirSync(plistDir, { recursive: true });
    const envPath = [
      path.dirname(binary),
      '/opt/homebrew/bin',
      '/usr/local/bin',
      '/usr/bin',
      '/bin',
    ].filter(Boolean).join(':');
    const plist = cloudflaredLaunchdPlist({
      label,
      binary,
      args: runArgs,
      workingDir: configDir,
      env: {
        PATH: envPath,
        HOME: homeDir,
      },
      logPath,
      errorLogPath,
    });
    if (options.atomicWriteFileSync || fsImpl === fs) {
      (options.atomicWriteFileSync || atomicWriteFileSync)(plistPath, plist, { mode: 0o644 });
    } else {
      fsImpl.writeFileSync(plistPath, plist, { mode: 0o644 });
    }
    try { fsImpl.chmodSync(plistPath, 0o644); } catch {}
    try {
      await execFile('launchctl', ['unload', plistPath], {
        encoding: 'utf8',
        timeout: options.timeoutMs || 10000,
        maxBuffer: 512 * 1024,
      });
    } catch {}
    await execFile('launchctl', ['load', plistPath], {
      encoding: 'utf8',
      timeout: options.timeoutMs || 10000,
      maxBuffer: 512 * 1024,
    });

    const state = {
      mode: 'launchd',
      label,
      plist_path: plistPath,
      hostname: setup.hostname,
      origin: setup.origin,
      mobile_url: setup.mobile_url,
      tunnel_name: setup.tunnel_name,
      tunnel_id: setup.tunnel_id,
      remote_config: !!setup.remote_config,
      token_file: setup.token_file || '',
      config_path: setup.config_path,
      log_path: logPath,
      error_log_path: errorLogPath,
      run_command: runCommand,
      started_at: startedAt,
    };
    writeManagedTunnelState(state, options);
    return { configured: true, running: true, started: true, ...state, state_path: managedStatePath(options) };
  }

  const spawnProcess = options.spawn || ((file, args, spawnOptions) => {
    const child = spawnCb(file, args, spawnOptions);
    child.unref();
    return child;
  });
  const outFd = fsImpl.openSync(logPath, 'a');
  const errFd = fsImpl.openSync(errorLogPath, 'a');
  const child = spawnProcess('cloudflared', runArgs, {
    cwd: configDir,
    detached: true,
    env: { ...process.env, HOME: homeDir },
    stdio: ['ignore', outFd, errFd],
  });
  const state = {
    mode: 'process',
    pid: child && child.pid ? child.pid : null,
    hostname: setup.hostname,
    origin: setup.origin,
    mobile_url: setup.mobile_url,
    tunnel_name: setup.tunnel_name,
    tunnel_id: setup.tunnel_id,
    remote_config: !!setup.remote_config,
    token_file: setup.token_file || '',
    config_path: setup.config_path,
    log_path: logPath,
    error_log_path: errorLogPath,
    run_command: runCommand,
    started_at: startedAt,
  };
  writeManagedTunnelState(state, options);
  return { configured: true, running: !!state.pid, started: true, ...state, state_path: managedStatePath(options) };
}

async function applyCloudflareFallbackSetup(input = {}, options = {}) {
  const requestedHostname = normalizeHostname(input.hostname || input.host || input.cf_host || input.cloudflare_host);
  const previousState = loadManagedTunnelState(options);
  if (requestedHostname && previousState?.hostname === requestedHostname && previousState.tunnel_id && !input.tunnel_id && !input.tunnelId) {
    input = { ...input, tunnel_id: previousState.tunnel_id };
  }
  if (requestedHostname && previousState?.hostname === requestedHostname && previousState.token_file && !input.tunnel_token_file && !input.tunnelTokenFile) {
    input = { ...input, tunnel_token_file: previousState.token_file, remote_config: previousState.remote_config };
  }

  let cloudflareContext = null;
  const apiToken = String(input.api_token || input.apiToken || input.cloudflare_api_token || '').trim();
  const shouldCreateMissingZone = !!(
    input.auto_create_zone
    || input.autoCreateZone
    || input.create_missing_zone
    || input.createMissingZone
  );
  const needsCloudflareContext = !!(apiToken && (
    !normalizeAccountId(input.account_id || input.accountId || '')
    || !normalizeHostname(input.team_domain || input.teamDomain || '')
    || (shouldCreateMissingZone && !normalizeZoneId(input.zone_id || input.zoneId || ''))
  ));
  if (needsCloudflareContext) {
    cloudflareContext = await resolveCloudflareSetupContext(input, options);
    if (!cloudflareContext.ok && shouldCreateMissingZone && cloudflareContext.error_code === 'cloudflare_zone_not_found') {
      const createdZone = await createCloudflareZone(input, options);
      if (!createdZone.ok) return createdZone;
      const retryInput = {
        ...input,
        account_id: input.account_id || input.accountId || createdZone.account_id,
        zone_id: input.zone_id || input.zoneId || createdZone.id,
      };
      cloudflareContext = await resolveCloudflareSetupContext(retryInput, options);
      if (cloudflareContext.ok) {
        cloudflareContext = {
          ...cloudflareContext,
          zone_id: cloudflareContext.zone_id || createdZone.id,
          zone_name: cloudflareContext.zone_name || createdZone.name,
          zone_status: cloudflareContext.zone_status || createdZone.status,
          zone_name_servers: cloudflareContext.zone_name_servers || createdZone.name_servers,
          created_zone: createdZone,
        };
      }
    }
    if (!cloudflareContext.ok) return cloudflareContext;
    input = {
      ...input,
      account_id: input.account_id || input.accountId || cloudflareContext.account_id,
      zone_id: input.zone_id || input.zoneId || cloudflareContext.zone_id,
      team_domain: input.team_domain || input.teamDomain || cloudflareContext.team_domain,
    };
  }

  let provisioned = null;
  if (input.provision_access || input.provisionAccess) {
    provisioned = await provisionCloudflareAccess(input, options);
    if (!provisioned.ok) return provisioned;
    input = { ...input, aud: provisioned.aud };
  }

  let setup = buildCloudflareFallbackSetup(input, options);
  if (!setup.ok) return setup;
  if (!setup.access.configured) {
    return {
      ok: false,
      error_code: 'cloudflare_access_missing_aud',
      error: 'Cloudflare Access AUD is required before CTM can enable the fallback.',
      setup,
    };
  }

  const shouldStart = !!(
    input.start_cloudflared
    || input.startCloudflared
    || input.install_service
    || input.installService
    || input.keep_running
    || input.keepRunning
    || input.run_cloudflared
    || input.runCloudflared
  );
  const shouldRun = !!(input.run_cloudflared || input.runCloudflared || input.create_tunnel || input.createTunnel || input.route_dns || input.routeDns || shouldStart);
  const shouldRoute = input.route_dns !== false && input.routeDns !== false;
  const execFile = options.execFile || defaultExecFile;
  const accountId = normalizeAccountId(input.account_id || input.accountId || '');
  const canUseCloudflareApi = !!(apiToken && accountId);
  let managedTunnel = null;
  let detected = null;
  let provisionedTunnel = null;
  if (shouldRun) {
    detected = await detectCloudflaredSetup(options);
    if (!detected.available) return { ok: false, error_code: detected.error_code, error: detected.error, setup, cloudflared: detected };

    if (canUseCloudflareApi) {
      provisionedTunnel = await provisionCloudflareTunnel({
        ...input,
        hostname: setup.hostname,
        tunnel_name: setup.tunnel_name,
        tunnel_id: setup.tunnel_id,
        local_service: setup.local_service,
        route_dns: shouldRoute,
      }, options);
      if (!provisionedTunnel.ok) return { ...provisionedTunnel, setup, cloudflared: detected };
      input = {
        ...input,
        tunnel_id: provisionedTunnel.tunnel_id,
        tunnel_token: provisionedTunnel.tunnel_token,
        remote_config: true,
      };
      setup = buildCloudflareFallbackSetup(input, options);
    } else if (!detected.login_cert_exists) {
      return {
        ok: false,
        error_code: 'cloudflared_login_missing',
        error: 'cloudflared is installed, but tunnel login has not completed. Enter a Cloudflare API token and account ID to let CTM set up the tunnel without cert.pem.',
        setup,
        cloudflared: detected,
      };
    } else if (!setup.tunnel_id) {
      const created = await execFile('cloudflared', setup.commands.create_tunnel.argv.slice(1), {
        encoding: 'utf8',
        timeout: options.timeoutMs || 60 * 1000,
        maxBuffer: 2 * 1024 * 1024,
      });
      const tunnelId = parseTunnelId(created?.stdout, created?.stderr);
      if (!tunnelId) {
        return {
          ok: false,
          error_code: 'cloudflared_tunnel_id_missing',
          error: 'cloudflared tunnel create did not report a tunnel UUID.',
          setup,
          cloudflared: detected,
        };
      }
      setup = buildCloudflareFallbackSetup({ ...input, tunnel_id: tunnelId }, options);
    }
    if (setup.remote_config) {
      setup.token_file_written = writeCloudflaredTokenFile(setup, options);
    } else {
      writeCloudflaredConfig(setup, options);
      setup.config_written = true;
    }
    if (shouldRoute && !setup.remote_config) {
      try {
        await execFile('cloudflared', setup.commands.route_dns.argv.slice(1), {
          encoding: 'utf8',
          timeout: options.timeoutMs || 60 * 1000,
          maxBuffer: 2 * 1024 * 1024,
        });
      } catch (err) {
        return {
          ok: false,
          error_code: 'cloudflared_route_dns_failed',
          error: String(err?.stderr || err?.message || err || 'cloudflared route dns failed').slice(0, 500),
          setup,
          cloudflared: detected,
        };
      }
    }
  } else if (setup.tunnel_id) {
    writeCloudflaredConfig(setup, options);
    setup.config_written = true;
  }

  if (shouldStart) {
    if (setup.remote_config && !setup.token_file_written) {
      setup.token_file_written = writeCloudflaredTokenFile(setup, options);
    } else if (!setup.remote_config && !setup.config_written) {
      writeCloudflaredConfig(setup, options);
      setup.config_written = true;
    }
    try {
      managedTunnel = await startCloudflaredTunnel(setup, options);
    } catch (err) {
      return {
        ok: false,
        error_code: 'cloudflared_start_failed',
        error: String(err?.stderr || err?.message || err || 'cloudflared tunnel start failed').slice(0, 500),
        setup,
        cloudflared: detected,
      };
    }
  } else {
    managedTunnel = await detectManagedCloudflaredTunnel(options);
  }

  return {
    ok: true,
    ...setup,
    managed_tunnel: managedTunnel,
    provisioned_access: provisioned ? {
      app_id: provisioned.app_id,
      policy_id: provisioned.policy_id,
      aud: provisioned.aud,
    } : null,
    cloudflare_context: cloudflareContext ? {
      account_id: cloudflareContext.account_id,
      account_name: cloudflareContext.account_name,
      zone_id: cloudflareContext.zone_id,
      zone_name: cloudflareContext.zone_name,
      zone_status: cloudflareContext.zone_status || '',
      zone_name_servers: cloudflareContext.zone_name_servers || [],
      created_zone: cloudflareContext.created_zone || null,
      team_domain: cloudflareContext.team_domain,
      organization_name: cloudflareContext.organization_name,
      sources: cloudflareContext.sources,
    } : {
      account_id: normalizeAccountId(input.account_id || input.accountId || ''),
      account_name: '',
      zone_id: normalizeZoneId(input.zone_id || input.zoneId || ''),
      zone_name: '',
      zone_status: '',
      zone_name_servers: [],
      created_zone: null,
      team_domain: normalizeHostname(input.team_domain || input.teamDomain || ''),
      organization_name: '',
      sources: {},
    },
    provisioned_tunnel: provisionedTunnel ? {
      tunnel_id: provisionedTunnel.tunnel_id,
      tunnel_name: provisionedTunnel.tunnel_name,
      remote_config: true,
      dns_record: provisionedTunnel.dns_record,
    } : null,
  };
}

module.exports = {
  applyCloudflareFallbackSetup,
  buildCloudflareFallbackSetup,
  cloudflaredLoginCertCandidates,
  detectCloudflaredLoginProcess,
  detectCloudflaredSetup,
  detectManagedCloudflaredTunnel,
  parseCloudflaredLoginProcesses,
  provisionCloudflareAccess,
  provisionCloudflareTunnel,
  createCloudflareZone,
  resolveCloudflareAccount,
  resolveCloudflareOrganization,
  resolveCloudflareSetupContext,
  resolveCloudflareZone,
  upsertCloudflareTunnelDns,
  normalizeHostname,
  startCloudflaredTunnel,
};
