import type { SidecarEvent } from '../protocol';
import { initEmailCron, stopEmailCron } from './email-cron';
import { initEmailIdle, stopEmailIdle } from './email-idle';
import { broadcastEmailNew } from './routes';
import { startEmailServer } from './http';
import { createSidecarConnector } from '../connect';
import { API_URL } from '../../officer-url.mjs';

// The sidecar used to reach BACK into the platform's queue over this socket to get a sync run —
// enqueueViaWs / listJobsViaWs and a pending-response map. Syncs run in this process now
// (sync-runner.ts), so the shim is gone and nothing but a port crosses the socket at startup.

// ── Command handlers ──

type ReplyFn = (msg: SidecarEvent) => void;

function handleCommand(cmd: Record<string, unknown>, reply: ReplyFn) {
  switch (cmd.type) {
    case 'ping':
      reply({ type: 'pong', id: cmd.id as string });
      break;

    default:
      reply({
        type: 'error',
        id: cmd.id as string,
        error: `Unknown command type: ${cmd.type}`,
      });
  }
}

// ── HTTP server ──
//
// Started before the registration socket so the port is known by the time we announce it. `/api/email/*`
// on the platform is a proxy onto this.
const serverPort = startEmailServer();

// ── Connect to API server ──

const connection = createSidecarConnector({
  apiUrl: `${API_URL}/api/sidecar/register`,
  name: 'email',
  capabilities: ['email'],
  onCommand(cmd, reply) {
    handleCommand(cmd as Record<string, unknown>, reply as ReplyFn);
  },
  onConnected() {
    // The platform forgets the port when the socket drops, and this listener outlives an officer restart,
    // so re-announce on every reconnect.
    connection.send({ type: 'email:server', port: serverPort });
    // Start email cron once connected (so queue commands can reach API server)
    initEmailCron();
    // Real-time push via IMAP IDLE; the cron above is the slow backstop. On new mail, tell the API
    // server so it can push an SSE event to that user's open /email page.
    // Straight to this process's own SSE clients — the /email/events stream lives here now, so the
    // round trip out to officer and back (the `email:new` wire event) is gone.
    initEmailIdle((userEmail) => broadcastEmailNew(userEmail));
  },
});

// ── Graceful shutdown ──

function shutdown(signal: string) {
  console.log(`[email] ${signal} received, shutting down...`);
  stopEmailIdle();
  stopEmailCron();
  connection.destroy();
  process.exit(0);
}

process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));
