import { createServer } from 'node:http';
import { readFileSync, existsSync } from 'node:fs';
import { homedir } from 'node:os';
import { join } from 'node:path';
import { Command } from 'commander';
import qrcode from 'qrcode-terminal';
import { createApp } from './server/app.js';
import { AuthManager, generatePassphrase } from './server/auth.js';
import { WsServer } from './server/websocket.js';
import { NgrokTunnel } from './server/tunnel.js';
import { CmuxClient } from './bridge/cmux-client.js';
import { ScreenPoller } from './bridge/screen-poller.js';
import { SessionManager } from './bridge/session-manager.js';
import { InputHandler } from './bridge/input-handler.js';
import type { Config } from './utils/config.js';
import { DEFAULT_CONFIG } from './utils/config.js';

// Load ~/.cmux-remote/config
const configFile = join(homedir(), '.cmux-remote', 'config');
if (existsSync(configFile)) {
  for (const line of readFileSync(configFile, 'utf8').split('\n')) {
    const trimmed = line.trim();
    if (!trimmed || trimmed.startsWith('#')) continue;
    const eq = trimmed.indexOf('=');
    if (eq === -1) continue;
    const key = trimmed.slice(0, eq).trim();
    const value = trimmed.slice(eq + 1).trim();
    if (key && !(key in process.env)) process.env[key] = value;
  }
}

const program = new Command();

program
  .name('cmux-remote')
  .description('Browser-based remote terminal control for cmux')
  .version('0.1.0')
  .option('-p, --port <port>', 'Local port', String(DEFAULT_CONFIG.port))
  .option('-P, --password <pass>', 'Access password (or CMUX_REMOTE_PASSWORD env)')
  .option('--no-tunnel', 'Disable ngrok tunnel')
  .option('--tunnel-domain <domain>', 'Fixed ngrok domain (or NGROK_DOMAIN env)')
  .option('--poll-rate <ms>', 'Poll interval in ms', String(DEFAULT_CONFIG.pollRate))
  .option('--theme <theme>', 'Default theme (dark|light)', DEFAULT_CONFIG.theme)
  .option('-v, --verbose', 'Verbose logging', false)
  .action(async (opts) => {
    const config: Config = {
      port: parseInt(opts.port, 10),
      password: opts.password || process.env.CMUX_REMOTE_PASSWORD || null,
      tunnel: opts.tunnel !== false,
      tunnelDomain: opts.tunnelDomain || process.env.NGROK_DOMAIN || null,
      pollRate: parseInt(opts.pollRate, 10),
      theme: opts.theme as 'dark' | 'light',
      verbose: opts.verbose,
      cmuxPath: process.env.CMUX_PATH || 'cmux',
    };

    // Initialize components
    const auth = new AuthManager();
    if (config.password) {
      await auth.setPassword(config.password);
    } else {
      auth.disableAuth();
    }

    const cmux = new CmuxClient(config.cmuxPath);
    const poller = new ScreenPoller(cmux, config.pollRate);
    const sessions = new SessionManager(poller);
    const input = new InputHandler(cmux);

    const app = createApp(auth, cmux);
    const server = createServer(app);

    // WebSocket server
    const wsServer = new WsServer({
      server,
      auth,
      sessions,
      poller,
      input,
      cmux,
      verbose: config.verbose,
    });

    // Start listening
    server.listen(config.port, () => {
      console.log('');
      console.log('  cmux-remote v0.1.0');
      console.log('  ==================');
      console.log('');
      console.log(`  Local:    http://localhost:${config.port}`);
      if (config.password) {
        const p = config.password;
        const masked = p.length <= 4 ? '****' : p[0] + '*'.repeat(p.length - 2) + p[p.length - 1];
        console.log(`  Password: ${masked}`);
      } else {
        console.log(`  Auth:     disabled (use -P to set password)`);
      }
      console.log('');
    });

    // Start tunnel
    let tunnel: NgrokTunnel | null = null;
    let accessUrl = `http://localhost:${config.port}`;
    if (config.tunnel) {
      tunnel = new NgrokTunnel();
      try {
        accessUrl = await tunnel.start(config.port, config.tunnelDomain ?? undefined);
        console.log(`  Tunnel:   ${accessUrl}`);
      } catch (err) {
        console.warn(`  Tunnel:   Failed - ${(err as Error).message}`);
      }
    }

    // Print QR code to terminal
    console.log('');
    qrcode.generate(accessUrl, { small: true }, (code: string) => {
      for (const line of code.split('\n')) {
        console.log(`  ${line}`);
      }
      console.log('');
    });

    // Graceful shutdown
    let shuttingDown = false;
    const shutdown = async () => {
      if (shuttingDown) return;
      shuttingDown = true;
      console.log('\nShutting down...');
      auth.destroy();
      cmux.shutdown();
      poller.destroy();
      wsServer.close();
      await tunnel?.stop();
      server.close(() => process.exit(0));
      // Force exit after 3s if connections don't drain
      setTimeout(() => process.exit(0), 3000).unref();
    };

    process.on('SIGINT', shutdown);
    process.on('SIGTERM', shutdown);
  });

program.parse();
