import { Hono } from 'hono';
import { cors } from 'hono/cors';
import * as fs from 'node:fs';

// Configuration
const MODES_DIR = '/home/admin/Job-Info-Test';
const MODE_CONFIG_FILE = `${MODES_DIR}/ModeSwitch/activeMode.txt`;
const SHARED_PORT = 3005;  // Mode services run here - NEVER use 3000 or 3001
const ORCHESTRATOR_PORT = 3006;  // Orchestrator API runs here

// Mode folder mappings - only Mode6Test exists currently
const MODE_FOLDERS: Record<string, string> = {
  'Mode1': 'Mode1',
  'Mode1Svelte': 'Mode1Svelte',
  'Mode2Svelte': 'Mode2Svelte',
  'Mode6Test': 'Mode6Test',
};

let currentMode: string = 'Mode1Svelte';
let currentProcess: any = null;

// Helper: Read active mode from config file
function readActiveMode(): string {
  try {
    if (fs.existsSync(MODE_CONFIG_FILE)) {
      const content = fs.readFileSync(MODE_CONFIG_FILE, 'utf-8').trim();
      if (content && MODE_FOLDERS[content]) {
        return content;
      }
    }
  } catch (err) {
    console.error('Failed to read mode config:', err);
  }
  return 'Mode6Test';
}

// Helper: Write active mode to config file
function writeActiveMode(mode: string): void {
  try {
    fs.writeFileSync(MODE_CONFIG_FILE, mode, 'utf-8');
  } catch (err) {
    console.error('Failed to write mode config:', err);
  }
}

// Helper: Kill process on shared port
async function killProcessOnPort(port: number): Promise<void> {
  try {
    await Bun.spawn({
      cmd: ['pkill', '-f', `bun.*:${port}`],
      stdout: 'ignore',
      stderr: 'ignore',
    });
    // Fallback: Try to kill any Bun process we spawned
    if (currentProcess) {
      currentProcess.kill();
      currentProcess = null;
    }
    // Give OS time to release the port
    await new Promise(resolve => setTimeout(resolve, 500));
  } catch (err) {
    console.error(`Failed to kill process on port ${port}:`, err);
  }
}

// Helper: Start a mode
async function startMode(mode: string): Promise<boolean> {
  try {
    // Kill any existing process
    await killProcessOnPort(SHARED_PORT);

    const folderName = MODE_FOLDERS[mode];
    if (!folderName) {
      console.error(`Unknown mode: ${mode}`);
      return false;
    }

    const modePath = `${MODES_DIR}/${folderName}`;
    if (!fs.existsSync(modePath)) {
      console.error(`Mode folder not found: ${modePath}`);
      return false;
    }

    console.log(`[ModeSwitch] Starting ${mode} (${folderName}/) on port ${SHARED_PORT}...`);

    // Mode1Svelte and Mode2Svelte use Node.js adapter with build/index.js
    if (mode === 'Mode1Svelte' || mode === 'Mode2Svelte') {
      const buildPath = `${modePath}/build`;
      if (!fs.existsSync(buildPath)) {
        console.error(`Build directory not found for ${mode}. Run: cd ${modePath} && npm run build`);
        return false;
      }

      // Start with Node.js
      currentProcess = Bun.spawn({
        cmd: ['node', 'build/index.js'],
        cwd: modePath,
        env: {
          ...process.env,
          PORT: String(SHARED_PORT),
        },
        stdout: 'pipe',
        stderr: 'pipe',
      });
    } else {
      // Other modes (Mode1, Mode6Test) use Bun with backend/server.ts
      const serverPath = 'backend/server.ts';

      currentProcess = Bun.spawn({
        cmd: [process.execPath, 'run', serverPath],
        cwd: modePath,
        env: {
          ...process.env,
          PORT: String(SHARED_PORT),
        },
        stdout: 'pipe',
        stderr: 'pipe',
      });
    }

    currentMode = mode;
    writeActiveMode(mode);

    // Read and log output from the spawned process
    if (currentProcess.stdout) {
      (async () => {
        const reader = currentProcess.stdout.getReader();
        while (true) {
          const { done, value } = await reader.read();
          if (done) break;
          console.log(`[${mode}]`, new TextDecoder().decode(value));
        }
      })();
    }

    console.log(`✓ ${mode} started successfully on port ${SHARED_PORT}`);
    return true;
  } catch (err) {
    console.error(`Failed to start ${mode}:`, err);
    return false;
  }
}

// Initialize app
const app = new Hono();

// Enable CORS
app.use('*', cors());

// API: Get current mode status
app.get('/status', (c) => {
  return c.json({
    currentMode,
    availableModes: Object.keys(MODE_FOLDERS),
    sharedPort: SHARED_PORT,
    orchestratorPort: ORCHESTRATOR_PORT,
  });
});

// API: Switch to a different mode
app.post('/switch/:mode', async (c) => {
  const mode = c.req.param('mode');
  
  if (!MODE_FOLDERS[mode]) {
    return c.json({ 
      success: false, 
      error: `Unknown mode: ${mode}. Available: ${Object.keys(MODE_FOLDERS).join(', ')}` 
    }, 400);
  }
  
  if (mode === currentMode) {
    return c.json({ 
      success: true, 
      message: `Already running ${mode}`,
      currentMode 
    });
  }
  
  const success = await startMode(mode);
  
  if (success) {
    return c.json({ 
      success: true, 
      message: `Switched to ${mode}`,
      currentMode: mode 
    });
  } else {
    return c.json({ 
      success: false, 
      error: `Failed to start ${mode}` 
    }, 500);
  }
});

// API: Restart current mode
app.post('/restart', async (c) => {
  console.log(`[ModeSwitch] Restarting ${currentMode}...`);
  const success = await startMode(currentMode);
  
  return c.json({ 
    success, 
    message: success ? `Restarted ${currentMode}` : `Failed to restart ${currentMode}`,
    currentMode 
  });
});

// API: List available modes
app.get('/modes', (c) => {
  return c.json({
    modes: Object.keys(MODE_FOLDERS),
    currentMode
  });
});

// Startup message
console.log(`
================================================================================
[ModeSwitch Orchestrator]
================================================================================
Listening on port: ${ORCHESTRATOR_PORT}
Shared mode port: ${SHARED_PORT}
Config file: ${MODE_CONFIG_FILE}
================================================================================
`);

// Start initial mode
const initialMode = readActiveMode();
await startMode(initialMode);

// Export for Bun
export default {
  port: ORCHESTRATOR_PORT,
  fetch: app.fetch,
};
