import { NextRequest, NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/server/auth/config';
import { exec } from 'child_process';
import { promisify } from 'util';

const execPromise = promisify(exec);

// ⚠️ CLOUDFLARE CONSTRAINT: Hard timeout is 100s. maxDuration=90 keeps Next.js within that.
// MUST stay at 90 — setting 120 is meaningless because Cloudflare kills the connection at 100s.
export const maxDuration = 90;

export async function POST(request: NextRequest) {
  try {
    const session = await getServerSession(authOptions);
    if (!session) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }
    const { 
      action, 
      host, 
      username, 
      password, 
      port = 22,
      // L2TP connection config
      vpnServerIp,
      l2tpUsername,
      l2tpPassword,
      vpnSubnet,    // VPN subnet for routing (e.g., "10.20.30.0/24")
    } = await request.json();

    if (!action || !host || !username || !password) {
      return NextResponse.json({
        success: false,
        message: 'Missing required fields: action, host, username, password'
      }, { status: 400 });
    }

    // Validate host and username to prevent shell command injection
    if (!/^[a-zA-Z0-9._-]+$/.test(host)) {
      return NextResponse.json({ success: false, message: 'Invalid host' }, { status: 400 });
    }
    if (!/^[a-zA-Z0-9._-]+$/.test(username)) {
      return NextResponse.json({ success: false, message: 'Invalid username' }, { status: 400 });
    }
    const portNum = parseInt(String(port));
    if (isNaN(portNum) || portNum < 1 || portNum > 65535) {
      return NextResponse.json({ success: false, message: 'Invalid port' }, { status: 400 });
    }

    let command = '';
    let description = '';

    switch (action) {
      case 'configure':
        // Configure L2TP client connection — plain L2TP without IPSec daemon
        if (!vpnServerIp || !l2tpUsername || !l2tpPassword) {
          return NextResponse.json({
            success: false,
            message: 'Missing L2TP config: vpnServerIp, l2tpUsername, l2tpPassword required'
          }, { status: 400 });
        }
        {
          // Build the bash script as a Node.js string (no SSH quoting issues),
          // then base64-encode and send as: echo 'B64' | base64 -d | bash
          const effectiveSubnet = vpnSubnet || '10.20.30.0/24';
          const scriptContent = `#!/bin/bash
# L2TP Configure Script (plain L2TP, no IPSec daemon) — generated by salfanet-radius
VPN_SERVER="${vpnServerIp}"
L2TP_USER="${l2tpUsername}"
L2TP_PASS="${l2tpPassword}"
VPN_SUBNET="${effectiveSubnet}"

echo "=== Step 1: Install packages if missing ==="
DEBIAN_FRONTEND=noninteractive apt-get -qq install -y xl2tpd ppp 2>/dev/null | tail -3 || true
# Stop/disable strongswan if installed — it causes constant IPSec SA rekeying loop
systemctl stop strongswan-starter 2>/dev/null || true
systemctl stop ipsec 2>/dev/null || true
systemctl disable strongswan-starter 2>/dev/null || true
systemctl disable ipsec 2>/dev/null || true

echo "=== Step 2: PPP device & modules ==="
[ -c /dev/ppp ] || ( mknod /dev/ppp c 108 0 2>/dev/null && chmod 600 /dev/ppp ) || true
modprobe ppp_generic 2>/dev/null || true
modprobe ppp_mppe 2>/dev/null || true

echo "=== Step 3: xl2tpd config ==="
mkdir -p /etc/xl2tpd
cat > /etc/xl2tpd/xl2tpd.conf << 'XLEOF'
[global]
port = 1701
access control = no
XLEOF
printf '\n[lac vpn-server]\nlns = %s\nppp debug = no\npppoptfile = /etc/ppp/options.l2tpd.client\nlength bit = yes\nautodial = yes\nredial = yes\nredial timeout = 10\n' "$VPN_SERVER" >> /etc/xl2tpd/xl2tpd.conf
echo "xl2tpd.conf written"
grep "lns" /etc/xl2tpd/xl2tpd.conf

printf 'ipcp-accept-local\nipcp-accept-remote\nrefuse-eap\nrequire-mschap-v2\nnoccp\nnoauth\nnodefaultroute\nusepeerdns\nconnect-delay 5000\nname %s\npassword %s\n' "$L2TP_USER" "$L2TP_PASS" > /etc/ppp/options.l2tpd.client
chmod 600 /etc/ppp/options.l2tpd.client
echo "ppp options written"
grep "name " /etc/ppp/options.l2tpd.client

echo "=== Step 5: CHAP secrets ==="
sed -i "/^$L2TP_USER /d" /etc/ppp/chap-secrets 2>/dev/null || true
printf '%s * %s *\n' "$L2TP_USER" "$L2TP_PASS" >> /etc/ppp/chap-secrets
chmod 600 /etc/ppp/chap-secrets
echo "chap-secrets written"


mkdir -p /etc/ppp/ip-up.d /etc/ppp/ip-down.d
cat > /etc/ppp/ip-up.d/99-vpn-routes << 'ROUTEEOF'
#!/bin/bash
IFACE=$1; LOCAL_IP=$4; REMOTE_IP=$5
VPN_SUBNET_PLACEHOLDER=""
logger -t vpn-route "PPP $IFACE up local=$LOCAL_IP remote=$REMOTE_IP"
ip route replace $VPN_SUBNET_PLACEHOLDER via $REMOTE_IP dev $IFACE metric 100 2>/dev/null || \
  ip route add $VPN_SUBNET_PLACEHOLDER via $REMOTE_IP dev $IFACE metric 100 2>/dev/null || true
iptables -C INPUT -s $VPN_SUBNET_PLACEHOLDER -p udp --dport 1812 -j ACCEPT 2>/dev/null || \
  iptables -I INPUT -s $VPN_SUBNET_PLACEHOLDER -p udp --dport 1812 -j ACCEPT 2>/dev/null || true
iptables -C INPUT -s $VPN_SUBNET_PLACEHOLDER -p udp --dport 1813 -j ACCEPT 2>/dev/null || \
  iptables -I INPUT -s $VPN_SUBNET_PLACEHOLDER -p udp --dport 1813 -j ACCEPT 2>/dev/null || true
iptables -C INPUT -s $VPN_SUBNET_PLACEHOLDER -p udp --dport 3799 -j ACCEPT 2>/dev/null || \
  iptables -I INPUT -s $VPN_SUBNET_PLACEHOLDER -p udp --dport 3799 -j ACCEPT 2>/dev/null || true
logger -t vpn-route "Routes+firewall applied for $VPN_SUBNET_PLACEHOLDER"
ROUTEEOF
sed -i "s|VPN_SUBNET_PLACEHOLDER|$VPN_SUBNET|g" /etc/ppp/ip-up.d/99-vpn-routes
chmod +x /etc/ppp/ip-up.d/99-vpn-routes

cat > /etc/ppp/ip-down.d/99-vpn-routes << 'DOWNEOF'
#!/bin/bash
IFACE=$1
VPN_SUBNET_PLACEHOLDER=""
ip route del $VPN_SUBNET_PLACEHOLDER dev $IFACE 2>/dev/null || true
logger -t vpn-route "PPP $IFACE down — route removed"
DOWNEOF
sed -i "s|VPN_SUBNET_PLACEHOLDER|$VPN_SUBNET|g" /etc/ppp/ip-down.d/99-vpn-routes
chmod +x /etc/ppp/ip-down.d/99-vpn-routes

# --- Auto-reconnect hook: triggered immediately on PPP link drop ---------
cat > /etc/ppp/ip-down.d/98-l2tp-reconnect << 'RECONNEOF'
#!/bin/bash
# Immediately trigger L2TP reconnect when the PPP link drops
logger -t l2tp-reconnect "PPP $1 dropped — scheduling reconnect in 5s"
(sleep 5 && mkdir -p /var/run/xl2tpd && \
  { systemctl is-active xl2tpd &>/dev/null || systemctl start xl2tpd; } && \
  echo "c vpn-server" > /var/run/xl2tpd/l2tp-control && \
  logger -t l2tp-reconnect "Reconnect command sent") &
RECONNEOF
chmod +x /etc/ppp/ip-down.d/98-l2tp-reconnect

# --- Watchdog: runs every 2 minutes via cron ----------------------------
cat > /usr/local/bin/l2tp-watchdog << 'WDEOF'
#!/bin/bash
LOG_TAG="l2tp-watchdog"
# Dynamically find the PPP peer IP from active interface
PPP_IFACE=$(ip addr show 2>/dev/null | grep -o 'ppp[0-9]*' | head -1)
if [ -n "$PPP_IFACE" ]; then
    VPN_PEER=$(ip addr show "$PPP_IFACE" 2>/dev/null | grep 'inet ' | awk '{print $4}')
    if [ -n "$VPN_PEER" ] && ping -c 2 -W 5 "$VPN_PEER" &>/dev/null; then
        logger -t $LOG_TAG "VPN OK on $PPP_IFACE peer=$VPN_PEER"
        exit 0
    fi
    logger -t $LOG_TAG "Peer $VPN_PEER unreachable on $PPP_IFACE — reconnecting"
else
    logger -t $LOG_TAG "No PPP interface found — reconnecting"
fi
# Kill stale pppd connections
pkill -f 'pppd plugin pppol2tp' 2>/dev/null || true
sleep 2
# Ensure xl2tpd is running
systemctl is-active xl2tpd &>/dev/null || systemctl start xl2tpd
sleep 3
# Trigger reconnect via control pipe
mkdir -p /var/run/xl2tpd
echo "d vpn-server" > /var/run/xl2tpd/l2tp-control 2>/dev/null || true
sleep 1
echo "c vpn-server" > /var/run/xl2tpd/l2tp-control 2>/dev/null || true
logger -t $LOG_TAG "Reconnect triggered"
WDEOF
chmod +x /usr/local/bin/l2tp-watchdog
# Install cron if not already present (runs every 2 minutes)
( crontab -l 2>/dev/null | grep -v 'l2tp-watchdog' ; echo '*/2 * * * * /usr/local/bin/l2tp-watchdog >> /var/log/l2tp-watchdog.log 2>&1' ) | crontab -
echo "Watchdog installed → /usr/local/bin/l2tp-watchdog (cron every 2 min)"

echo "=== Step 7: Ensure runtime dirs ==="
mkdir -p /var/run/xl2tpd

echo "=== Step 8: Stop existing xl2tpd ==="
echo "d vpn-server" | tee /var/run/xl2tpd/l2tp-control 2>/dev/null || true
systemctl stop xl2tpd 2>/dev/null || true
sleep 2

echo "=== Step 9: Start xl2tpd (autodial=yes will connect automatically) ==="
systemctl start xl2tpd
systemctl enable xl2tpd 2>/dev/null || true
sleep 6

echo "=== Connection Status Check ==="
echo "--- PPP interfaces ---"
ip addr show | grep -A3 "ppp" || echo "PPP: not up yet (may take a few seconds)"
echo "--- xl2tpd service ---"
systemctl is-active xl2tpd 2>/dev/null || true
echo "--- Recent xl2tpd logs ---"
journalctl -u xl2tpd -n 20 --no-pager 2>/dev/null | tail -20
echo "--- Recent pppd logs ---"
grep -E 'pppd|ppp0' /var/log/syslog 2>/dev/null | tail -10 || journalctl -n 10 --no-pager 2>/dev/null | grep -i ppp | tail -10 || echo 'No ppp syslog'
echo "--- PPP routes ---"
ip route show | grep ppp || echo "No PPP routes yet"
echo "=== Done. autodial+redial active. Watchdog cron installed. ==="
`;
          // Base64-encode the script — safe to pass through SSH single-quoted args
          const scriptB64 = Buffer.from(scriptContent).toString('base64');
          command = `echo '${scriptB64}' | base64 -d > /tmp/l2tp_setup_vps.sh && bash /tmp/l2tp_setup_vps.sh`;
        }
        description = 'Configuring and connecting L2TP client';
        break;
      case 'start':
        command = `
mkdir -p /var/run/xl2tpd
systemctl start xl2tpd
sleep 2
echo "c vpn-server" | tee /var/run/xl2tpd/l2tp-control
sleep 5
echo "--- PPP ---"
ip addr show | grep -A2 "ppp" || echo "PPP not up yet"
echo "--- xl2tpd ---"
systemctl is-active xl2tpd 2>/dev/null
echo "Services started and L2TP connection initiated"`;
        description = 'Starting L2TP/IPSec services and initiating connection';
        break;
      case 'stop':
        command = `
echo "d vpn-server" | tee /var/run/xl2tpd/l2tp-control 2>/dev/null || true
sleep 1
systemctl stop xl2tpd 2>/dev/null || true
echo "L2TP disconnected and services stopped"`;
        description = 'Disconnecting L2TP and stopping services';
        break;
      case 'restart':
        command = `
echo "d vpn-server" | tee /var/run/xl2tpd/l2tp-control 2>/dev/null || true
systemctl stop xl2tpd 2>/dev/null || true
sleep 2
mkdir -p /var/run/xl2tpd
systemctl start xl2tpd
sleep 2
echo "c vpn-server" | tee /var/run/xl2tpd/l2tp-control
sleep 5
echo "--- PPP ---"
ip addr show | grep -A2 "ppp" || echo "PPP not up yet"
echo "--- xl2tpd ---"
systemctl is-active xl2tpd 2>/dev/null
echo "Services restarted and L2TP reconnected"`;
        description = 'Restarting L2TP/IPSec and reconnecting';
        break;
      case 'status':
        command = `
PPP_IFACE=$(ip addr show 2>/dev/null | grep -o 'ppp[0-9]*' | head -1)
PPP_IP=$(ip addr show $PPP_IFACE 2>/dev/null | grep 'inet ' | awk '{print $2}' | head -1)
PPP_PEER=$(ip addr show $PPP_IFACE 2>/dev/null | grep 'inet ' | awk '{print $4}' | head -1)
if [ -n "$PPP_IFACE" ]; then echo "connected"; else echo "disconnected"; fi
echo "\${PPP_IP:-none}"
echo "\${PPP_PEER:-none}"
echo "\${PPP_IFACE:-none}"
echo "none"`;
        description = 'Checking VPN connection status';
        break;
      case 'enable':
        command = `
mkdir -p /var/run/xl2tpd
systemctl enable xl2tpd 2>/dev/null || true
systemctl start xl2tpd
sleep 2
echo "c vpn-server" | tee /var/run/xl2tpd/l2tp-control
echo "Services enabled, started, and L2TP connected"`;
        description = 'Enabling, starting, and connecting L2TP/IPSec';
        break;
      case 'disable':
        command = `
echo "d vpn-server" | tee /var/run/xl2tpd/l2tp-control 2>/dev/null || true
systemctl stop xl2tpd 2>/dev/null || true
systemctl disable xl2tpd 2>/dev/null || true
echo "L2TP disconnected, services disabled and stopped"`;
        description = 'Disconnecting, disabling and stopping L2TP/IPSec';
        break;
      case 'logs':
        command = `
echo "=== journalctl xl2tpd ==="
journalctl -u xl2tpd -n 50 --no-pager 2>/dev/null || echo "No xl2tpd journal"
echo "=== pppd syslog ==="
grep -E "pppd|xl2tpd|ppp0" /var/log/syslog 2>/dev/null | tail -40 || echo "No syslog entries"
echo "=== PPP interfaces ==="
ip addr show | grep -A4 ppp || echo "No PPP interface"`;
        description = 'Fetching L2TP/IPSec logs';
        break;
      case 'connections':
        command = `
echo "=== PPP interfaces ==="
ip addr show | grep -A3 "ppp" || echo "No PPP interface"
echo "=== Active L2TP sessions ==="
ss -unp 2>/dev/null | grep "1701" || echo "No active L2TP sessions"
echo "=== VPN routes ==="
ip route show | grep ppp || echo "No PPP routes"`;
        description = 'Listing active VPN connections';
        break;
      default:
        return NextResponse.json({
          success: false,
          message: 'Invalid action. Supported: configure, start, stop, restart, status, enable, disable, logs, connections'
        }, { status: 400 });
    }

    // Execute SSH command with proper escaping
    // Use base64 encoding for password to avoid escaping issues
    const passwordBase64 = Buffer.from(password).toString('base64');
    
    // Escape command properly - use single quotes for the entire command
    const escapedCommand = command.replace(/'/g, "'\"'\"'");
    
    // Use SSHPASS env variable (-e flag) so sshpass works correctly in
    // non-interactive/no-tty environments (e.g. PM2 daemon processes)
    const sshCommand = `SSHPASS="$(echo '${passwordBase64}' | base64 -d)" sshpass -e ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10 -p ${portNum} ${username}@${host} '${escapedCommand}'`;
    
    console.log('[L2TP Control] Executing action:', action);
    console.log('[L2TP Control] Target:', `${username}@${host}:${port}`);
    
    // configure needs more time (package install + service restart)
    const timeoutMs = action === 'configure' ? 120000 : 45000;

    try {
      const { stdout, stderr } = await execPromise(sshCommand, {
        timeout: timeoutMs,
        maxBuffer: 1024 * 1024, // 1MB buffer
        shell: '/bin/bash'
      });

      // Parse status output if it's a status check
      let parsedResult: any = {
        output: stdout || stderr || 'Command executed successfully',
        rawOutput: stdout,
        rawError: stderr
      };

      if (action === 'status') {
        const lines = stdout.trim().split('\n');
        const connected = lines[0]?.trim() === 'connected';
        const vpnIp = lines[1]?.trim() !== 'none' ? lines[1]?.trim() : null;
        const vpnPeer = lines[2]?.trim() !== 'none' ? lines[2]?.trim() : null;
        const pppIface = lines[3]?.trim() !== 'none' ? lines[3]?.trim() : null;
        const ipsecState = lines[4]?.trim() === 'established';
        parsedResult = {
          connected,
          vpnIp,
          vpnPeer,
          pppIface,
          ipsecEstablished: ipsecState,
          isRunning: connected,
          // keep legacy fields so other code doesn't break
          xl2tpd: { active: connected, status: connected ? 'running' : 'stopped' },
          ipsec: { active: ipsecState, status: ipsecState ? 'running' : 'stopped' },
          connection: vpnIp ?? 'Not connected',
        };
      } else if (action === 'connections') {
        parsedResult.connections = stdout.trim() || 'No active connections';
      } else if (action === 'logs') {
        const logLines = stdout.split('\n').filter(line => line.trim());
        parsedResult.logs = logLines.length > 0 ? logLines : ['No logs available'];
      }

      return NextResponse.json({
        success: true,
        message: `${description} - Success`,
        action,
        result: parsedResult
      });

    } catch (execError: any) {
      console.error('SSH Command Error:', execError);
      
      // Check if it's a connection error
      if (execError.message.includes('Connection refused') || execError.message.includes('Connection timed out')) {
        return NextResponse.json({
          success: false,
          message: `Cannot connect to ${host}:${port}. Check SSH service and firewall.`,
          error: 'Connection failed'
        }, { status: 500 });
      }

      // Check if it's authentication error
      if (execError.message.includes('Permission denied') || execError.message.includes('Authentication failed')) {
        return NextResponse.json({
          success: false,
          message: 'Authentication failed. Check username and password.',
          error: 'Authentication failed'
        }, { status: 401 });
      }

      // Check if sshpass is not installed
      if (execError.message.includes('sshpass: command not found')) {
        return NextResponse.json({
          success: false,
          message: 'SSH client (sshpass) not installed on server. Please install: apt-get install sshpass',
          error: 'Missing dependency'
        }, { status: 500 });
      }
      
      return NextResponse.json({
        success: false,
        message: `${description} - Failed: ${execError.message}`,
        error: execError.message,
        output: execError.stdout,
        errorOutput: execError.stderr
      }, { status: 500 });
    }

  } catch (error: any) {
    console.error('L2TP Control Error:', error);
    return NextResponse.json({
      success: false,
      message: 'Internal server error',
      error: error.message
    }, { status: 500 });
  }
}
