// @ts-nocheck
import type { ExtensionAPI } from '@helios-agent/pi-coding-agent';
import { existsSync, readFileSync } from 'node:fs';
import { join } from 'node:path';
import { homedir } from 'node:os';
import { spawnFireAndForget } from '../lib/spawn-with-timeout.cjs.js';
import { registerService } from '../lib/infrastructure-registry.ts';
import { readConsent } from '../lib/index-gateway.ts';
const { elynticPath, HOME } = require('./lib/elyntic-root');

export default function atlasIntegration(pi: ExtensionAPI): void {
  if (process.env.PI_SKIP_DEFERRED === '1') return;
  if (process.env.ELYNTIC_SKIP_ATLAS === '1') return;

  const ATLAS_DIR = elynticPath('git', 'github.com', 'helios-agi', 'code-atlas');
  const DAEMON_SCRIPT = elynticPath('scripts', 'start-atlas-daemon.sh');
  const PID_FILE = '/tmp/elyntic-atlas-daemon.pid';
  const UV_BIN = process.env.UV_PATH || join(homedir(), '.local/bin/uv');

  if (!existsSync(ATLAS_DIR)) return;

  function isDaemonRunning(): boolean {
    try {
      if (!existsSync(PID_FILE)) return false;
      const pid = parseInt(readFileSync(PID_FILE, 'utf-8').trim(), 10);
      if (!pid || pid <= 0) return false;
      process.kill(pid, 0);
      return true;
    } catch { return false; }
  }

  function startDaemon(): void {
    if (isDaemonRunning()) return;
    if (!existsSync(DAEMON_SCRIPT)) return;
    try {
      spawnFireAndForget('bash', [DAEMON_SCRIPT], {
        env: { ...process.env, HOME: homedir(), PATH: `${join(homedir(), '.local/bin')}:${process.env.PATH}` },
        timeoutMs: 300_000,
      });
      registerService('atlas-daemon', 'up', { script: DAEMON_SCRIPT });
      process.stderr.write('[atlas-integration] Daemon started\n');
    } catch (e) {
      process.stderr.write(`[atlas-integration] Daemon start failed: ${String(e)}\n`);
    }
  }

  function indexCurrentProject(projectPath: string): void {
    // Respect user consent — same file as codebase-index.ts / auto-discovery.ts
    const consent = readConsent(projectPath);
    if (consent === 'no') {
      if (process.env.DEBUG) process.stderr.write(`[atlas-integration] skip: user declined indexing for ${projectPath}\n`);
      return;
    }
    if (consent === 'ask') {
      // codebase-index.ts will surface the prompt; skip here to avoid duplicate
      if (process.env.DEBUG) process.stderr.write(`[atlas-integration] skip: awaiting consent for ${projectPath}\n`);
      return;
    }
    try {
      process.stderr.write(`[atlas-integration] Indexing ${projectPath}\n`);
      spawnFireAndForget(UV_BIN, ['run', 'atlas', 'index', projectPath, '--no-embed'], {
        cwd: ATLAS_DIR,
        env: { ...process.env, HOME: homedir(), ATLAS_QUIET: '1', PATH: `${join(homedir(), '.local/bin')}:${process.env.PATH}` },
        timeoutMs: 180_000,
      });
    } catch (e) {
      process.stderr.write(`[atlas-integration] Index failed: ${String(e)}\n`);
    }
  }

  // P2-10 NX PassiveDaemonWatcher fix: replace setInterval polling on
  // __elyntic_graph_ready with a one-time event bus subscription.
  // Also replace execSync('git rev-parse ...') with async execFile to avoid
  // blocking the event loop thread.
  //
  // NX equivalent: PassiveDaemonWatcher subscribes to daemon file-change events
  // once, then reacts. We subscribe to the 'graph_ready' bus event once.
  //
  // Old approach: setInterval(3000) + 300s hard-kill timeout = 100 wasted polls
  //               + execSync blocks event loop for up to 2s
  // New approach: single event subscription + async execFile

  let _atlasInitDone = false;

  const runAtlasInit = async () => {
    if (_atlasInitDone) return;
    _atlasInitDone = true;

    startDaemon();

    // 15s grace before indexing (same as before, but now async)
    setTimeout(async () => {
      try {
        const cwd = process.cwd();
        let gitRoot = cwd;
        try {
          // P2-10: execFile (async) instead of execSync (blocking)
          const { execFile } = require('child_process');
          gitRoot = await new Promise<string>((resolve) => {
            execFile('git', ['rev-parse', '--show-toplevel'], { cwd, encoding: 'utf-8', timeout: 2000 }, (err: Error | null, stdout: string) => {
              resolve(err ? cwd : (stdout?.trim() || cwd));
            });
          });
        } catch { /* not a git repo — use cwd */ }
        if (existsSync(join(gitRoot, '.git'))) indexCurrentProject(gitRoot);
      } catch (e) {
        process.stderr.write(`[atlas-integration] 15s indexing init failed (non-fatal): ${String(e)}\n`);
      }
    }, 15_000);

    // Cross-model reconciliation (unchanged — already async, just moved inside handler)
    setTimeout(async () => {
      try {
        const mg = await import('../lib/graph/graph-transport.js').then((m: any) => m.default ?? m);
        await mg.safeWrite(`
          MATCH (cf:CodeFile), (c:Callable)
          WHERE cf.path IS NOT NULL AND c.file_path IS NOT NULL
            AND cf.path = c.file_path
            AND NOT (cf)-[:CONTAINS_CALLABLE]->(c)
          WITH cf, c LIMIT 500
          MERGE (cf)-[:CONTAINS_CALLABLE]->(c)
        `);
        await mg.safeWrite(`
          MATCH (cf:CodeFile), (td:TypeDef)
          WHERE cf.path IS NOT NULL AND td.file_path IS NOT NULL
            AND cf.path = td.file_path
            AND NOT (cf)-[:CONTAINS_TYPEDEF]->(td)
          WITH cf, td LIMIT 500
          MERGE (cf)-[:CONTAINS_TYPEDEF]->(td)
        `);
        process.stderr.write('[atlas-integration] Cross-model edges reconciled\n');
      } catch (e) {
        process.stderr.write(`[atlas-integration] Cross-model reconciliation failed (non-fatal): ${String(e)}\n`);
      }
    }, 120_000);
  };

  // Subscribe to graph_ready event (one-shot, no polling)
  // Try event bus subscription first; fall back to globalThis polling with fast 50ms tick
  let _subscribed = false;
  try {
    const bus = require('../lib/event-bus.js').default;
    if (bus && typeof bus.on === 'function') {
      bus.once('graph_ready', runAtlasInit);
      _subscribed = true;
    }
  } catch { /* event bus not available yet */ }

  if (!_subscribed) {
    // Fallback: fast 50ms poll (much better than 3000ms) with 300s hard stop
    const checkInterval = setInterval(() => {
      if ((globalThis as any).__elyntic_graph_ready !== true) return;
      clearInterval(checkInterval);
      runAtlasInit().catch(() => {});
    }, 50); // 50ms instead of 3000ms — 60× faster detection
    checkInterval.unref();
    setTimeout(() => clearInterval(checkInterval), 300_000);
  }

  // Also check immediately in case graph_ready already fired
  if ((globalThis as any).__elyntic_graph_ready === true) {
    runAtlasInit().catch(() => {});
  }
}
