import './servers/bootstrap';
import type { ServerWebSocket } from 'bun';
import { serve } from 'bun';
import { eq } from 'drizzle-orm';
import { honoServer, loadPlugins } from './servers/hono';
import { verify } from './servers/jwt';
import { officerdb, TokenBlacklist } from 'officerdb';
import { claudeWebsocket } from './servers/api/claude/websocket';
import { opencodeWebsocket } from './servers/api/opencode/websocket';
import { terminalWebsocket } from 'plugins/Terminal/server';
import officerWeb from './apps/officer-web/index.html';

const { PORT = '5000' } = process.env;
await loadPlugins();

type WSData = { userId: number; email: string; provider: 'claude' | 'opencode' | 'terminal' };

const handlers: Record<string, typeof claudeWebsocket> = {
  claude: claudeWebsocket,
  opencode: opencodeWebsocket,
  terminal: terminalWebsocket,
};

async function upgradeWs(req: Request, server: any, provider: 'claude' | 'opencode' | 'terminal') {
  const token = new URL(req.url).searchParams.get('token');
  if (!token) return new Response('Unauthorized', { status: 401 });

  try {
    const user = await verify(token);
    if (!user) return new Response('Unauthorized', { status: 401 });

    if (user.jti) {
      const blacklisted = await officerdb.query.TokenBlacklist.findFirst({
        where: eq(TokenBlacklist.jti, user.jti),
      });
      if (blacklisted) return new Response('Unauthorized', { status: 401 });
    }

    const ok = server.upgrade(req, { data: { userId: user.id, email: user.email, provider } });
    if (!ok) return new Response('Upgrade failed', { status: 500 });
  } catch {
    return new Response('Unauthorized', { status: 401 });
  }
}

const server = serve({
  port: Number(PORT),
  idleTimeout: 60,
  maxRequestBodySize: 1024 * 1024 * 1024 * 50, // 50 GB
  routes: {
    '/static/*': async (req) => {
      const path = new URL(req.url).pathname.slice('/static'.length);
      const file = Bun.file(`public${path}`);
      if (await file.exists()) return new Response(file);
      return new Response(null, { status: 404 });
    },
    '/api/harness/claudecode/ws': (req, server) => upgradeWs(req, server, 'claude'),
    '/api/harness/opencode/ws': (req, server) => upgradeWs(req, server, 'opencode'),
    '/api/terminal/ws': (req, server) => upgradeWs(req, server, 'terminal'),
    '/': officerWeb,
    '/*': officerWeb,
    '/api': honoServer.fetch,
    '/api/*': honoServer.fetch,
  },

  websocket: {
    open(ws) {
      const { provider } = (ws as unknown as ServerWebSocket<WSData>).data;
      handlers[provider]!.open(ws as any);
    },
    message(ws, raw) {
      const { provider } = (ws as unknown as ServerWebSocket<WSData>).data;
      handlers[provider]!.message(ws as any, raw);
    },
    close(ws) {
      const { provider } = (ws as unknown as ServerWebSocket<WSData>).data;
      handlers[provider]!.close(ws as any);
    },
    drain() {},
  },

  development: process.env.NODE_ENV !== 'production' && {
    hmr: true,
  },
});

console.log(`🚀 Server running at ${server.url}`);
