#!/bin/bash -e

# Simple WiFi Access Point + Captive Portal for Dangerous Pi
# Compatible with Debian Trixie (uses NetworkManager, not dhcpcd)
# No PHP bloat, just hostapd + dnsmasq + nftables
# Date: 2025-12-29

echo "=== Setting up WiFi Access Point ==="

# Packages (hostapd, dnsmasq, nftables, nginx) installed by 00-apt-setup stage

# Note: We no longer use static config file for wlan0 management.
# The wifi_manager now uses 'nmcli device set wlan0 managed yes/no' dynamically.
# This allows switching between AP and client modes without file permission issues.
echo "NetworkManager will manage wlan0 dynamically..."

# Stop services while we configure
systemctl stop hostapd || true
systemctl stop dnsmasq || true

# Configure hostapd (WiFi Access Point)
echo "Configuring hostapd..."
cat > /etc/hostapd/hostapd.conf << 'EOF'
# Dangerous Pi WiFi Access Point Configuration

# Interface and driver
interface=wlan0
driver=nl80211

# Network name (SSID)
ssid=Dangerous-Pi

# WiFi channel (1-11 for 2.4GHz)
channel=6

# Country code (US = United States, change as needed)
country_code=US

# WiFi mode: a = IEEE 802.11a (5 GHz), b = IEEE 802.11b (2.4 GHz), g = IEEE 802.11g (2.4 GHz)
hw_mode=g

# Enable 802.11n
ieee80211n=1

# QoS support
wmm_enabled=1

# Security: WPA2-PSK
# Comment out wpa lines for open network
wpa=2
wpa_passphrase=dangerous123
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
rsn_pairwise=CCMP

# Logging
logger_syslog=-1
logger_syslog_level=2
logger_stdout=-1
logger_stdout_level=2
EOF

# Set hostapd to use our config
cat > /etc/default/hostapd << 'EOF'
# Defaults for hostapd initscript
DAEMON_CONF="/etc/hostapd/hostapd.conf"
EOF

# Configure dnsmasq (DHCP + DNS for captive portal)
echo "Configuring dnsmasq..."

# Backup original dnsmasq config
mv /etc/dnsmasq.conf /etc/dnsmasq.conf.orig || true

cat > /etc/dnsmasq.conf << 'EOF'
# Dangerous Pi Captive Portal Configuration

# Interface to listen on
interface=wlan0

# Bind to interfaces to prevent startup race conditions
bind-interfaces

# Don't use /etc/hosts
no-hosts

# Don't poll /etc/resolv.conf
no-resolv

# Upstream DNS servers (when acting as router)
server=8.8.8.8
server=8.8.4.4

# DHCP range
# Assign IPs from 192.168.4.2 to 192.168.4.20
# Lease time: 12 hours
dhcp-range=192.168.4.2,192.168.4.20,255.255.255.0,12h

# Gateway (this Pi)
dhcp-option=3,192.168.4.1

# DNS server (this Pi)
dhcp-option=6,192.168.4.1

# CAPTIVE PORTAL: Redirect ALL DNS queries to this Pi
# This makes browsers think there's a captive portal
address=/#/192.168.4.1

# Don't read /etc/resolv.conf
no-resolv

# Log DHCP
log-dhcp

# Log DNS
log-queries
EOF

# Configure static IP for wlan0 using systemd-networkd
# Note: Debian Trixie uses NetworkManager, but we've told it to ignore wlan0
# We use a simple systemd service to set the IP before hostapd starts
echo "Configuring network interface..."

# Enable IP forwarding (for NAT if connected to internet via eth0)
echo "Enabling IP forwarding..."
if ! grep -q "net.ipv4.ip_forward=1" /etc/sysctl.conf; then
    echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
fi

# Configure nftables for NAT and captive portal (modern replacement for iptables)
echo "Configuring nftables..."
cat > /etc/nftables.conf << 'EOF'
#!/usr/sbin/nft -f
# Dangerous Pi NAT + Captive Portal configuration (nftables)

# Flush existing rules
flush ruleset

table inet nat {
    # NAT chain for outgoing packets (masquerade)
    chain postrouting {
        type nat hook postrouting priority 100; policy accept;

        # Masquerade traffic from WiFi clients going out eth0
        oifname "eth0" ip saddr 192.168.4.0/24 masquerade
    }

    # Prerouting chain (no redirect - nginx handles port 80)
    chain prerouting {
        type nat hook prerouting priority -100; policy accept;
        # Note: nginx on port 80 proxies to frontend (3000) and backend (8000)
    }
}

table inet filter {
    # Filter rules for forwarding
    chain forward {
        type filter hook forward priority 0; policy drop;

        # Allow established/related connections
        ct state related,established accept

        # Allow WiFi clients to access internet via eth0
        iifname "wlan0" oifname "eth0" accept

        # Allow return traffic
        iifname "eth0" oifname "wlan0" ct state related,established accept
    }

    # Input rules
    chain input {
        type filter hook input priority 0; policy accept;

        # Allow loopback
        iifname "lo" accept

        # Allow established connections
        ct state related,established accept

        # Allow DHCP, DNS from WiFi clients
        iifname "wlan0" udp dport { 53, 67 } accept
        # Allow HTTP (nginx), HTTPS, backend (8000), and frontend (3000)
        iifname "wlan0" tcp dport { 53, 80, 443, 3000, 8000, 8080 } accept

        # Allow SSH from anywhere
        tcp dport 22 accept
    }
}
EOF

# Enable and start nftables
systemctl enable nftables
systemctl start nftables || true

# Configure nginx as reverse proxy for frontend and backend
echo "Configuring nginx reverse proxy..."
rm -f /etc/nginx/sites-enabled/default
cat > /etc/nginx/sites-available/dangerous-pi.conf << 'EOF'
# Dangerous Pi - Nginx reverse proxy configuration
# Serves frontend on / and proxies /api/*, /ws/* to backend

upstream frontend {
    server 127.0.0.1:3000;
}

upstream backend {
    server 127.0.0.1:8000;
}

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name dangerous-pi.local _;

    # ===========================================
    # CAPTIVE PORTAL DETECTION
    # ===========================================
    # These endpoints respond to OS connectivity checks.
    # When a device connects to the AP, the OS checks these URLs.
    # By responding correctly, we trigger the captive portal popup.

    # Android / Chrome OS connectivity check
    location = /generate_204 {
        return 204;
    }

    # Additional Android check paths
    location = /gen_204 {
        return 204;
    }

    # Google connectivity check
    location = /connectivitycheck/gstatic/generate_204 {
        return 204;
    }

    # iOS / macOS captive portal detection
    location = /hotspot-detect.html {
        return 200 '<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>';
        add_header Content-Type text/html;
    }

    # iOS alternate path
    location = /library/test/success.html {
        return 200 '<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>';
        add_header Content-Type text/html;
    }

    # Windows 10/11 connectivity check
    location = /connecttest.txt {
        return 200 'Microsoft Connect Test';
        add_header Content-Type text/plain;
    }

    # Windows NCSI check
    location = /ncsi.txt {
        return 200 'Microsoft NCSI';
        add_header Content-Type text/plain;
    }

    # Firefox / Mozilla connectivity check
    location = /success.txt {
        return 200 'success';
        add_header Content-Type text/plain;
    }

    # Kindle / Amazon devices
    location = /kindle-wifi/wifistub.html {
        return 200 '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"><html><head><title>Kindle</title></head><body>81ce4465-7167-4dcb-835b-dcc9e44c112a</body></html>';
        add_header Content-Type text/html;
    }

    # ===========================================
    # END CAPTIVE PORTAL DETECTION
    # ===========================================

    # Proxy API requests to FastAPI backend
    location /api/ {
        proxy_pass http://backend;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 300s;
        proxy_connect_timeout 75s;
    }

    # Proxy WebSocket connections to backend
    location /ws/ {
        proxy_pass http://backend;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }

    # Everything else goes to Remix frontend
    location / {
        proxy_pass http://frontend;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_cache_bypass $http_upgrade;
    }

    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # Gzip compression
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml application/json application/javascript application/xml;
}
EOF

ln -sf /etc/nginx/sites-available/dangerous-pi.conf /etc/nginx/sites-enabled/
systemctl enable nginx

# Unmask and enable hostapd
echo "Enabling hostapd service..."
systemctl unmask hostapd
systemctl enable hostapd

# Enable dnsmasq
systemctl enable dnsmasq

# NOTE: No separate web server needed - nftables redirects port 80 to the backend on 8000

# Create Avahi service for dangerous-pi.local
echo "Configuring mDNS..."
# Ensure avahi services directory exists
mkdir -p /etc/avahi/services
cat > /etc/avahi/services/dangerous-pi.service << 'EOF'
<?xml version="1.0" standalone='no'?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
  <name replace-wildcards="yes">Dangerous Pi on %h</name>
  <service>
    <type>_http._tcp</type>
    <port>80</port>
  </service>
</service-group>
EOF

# Create systemd service to set up AP network interface
# This sets static IP on wlan0 before hostapd/dnsmasq start
cat > /etc/systemd/system/dangerous-pi-ap.service << 'EOF'
[Unit]
Description=Dangerous Pi WiFi Access Point Setup
After=network.target NetworkManager.service
Before=hostapd.service dnsmasq.service nftables.service

[Service]
Type=oneshot
RemainAfterExit=yes
# Unblock WiFi
ExecStart=/usr/sbin/rfkill unblock wlan
# Wait for interface to appear
ExecStart=/bin/sleep 1
# Tell NetworkManager to not manage wlan0 (so hostapd can use it)
ExecStart=/usr/bin/nmcli device set wlan0 managed no
# Set static IP for AP mode
ExecStart=/sbin/ip addr add 192.168.4.1/24 dev wlan0
ExecStart=/sbin/ip link set wlan0 up
# Load nftables rules for captive portal
ExecStart=/usr/sbin/nft -f /etc/nftables.conf

[Install]
WantedBy=multi-user.target
EOF

systemctl enable dangerous-pi-ap.service

# Ensure NetworkManager is enabled (pi-gen may not carry the default)
systemctl enable NetworkManager

# Ensure hostapd and dnsmasq start AFTER network is configured
mkdir -p /etc/systemd/system/hostapd.service.d
cat > /etc/systemd/system/hostapd.service.d/override.conf << 'EOF'
[Unit]
After=dangerous-pi-ap.service
Requires=dangerous-pi-ap.service
EOF

mkdir -p /etc/systemd/system/dnsmasq.service.d
cat > /etc/systemd/system/dnsmasq.service.d/override.conf << 'EOF'
[Unit]
After=dangerous-pi-ap.service hostapd.service
Requires=dangerous-pi-ap.service
EOF

# Print configuration summary
echo "=== WiFi Access Point Configuration Complete ==="
echo "SSID: Dangerous-Pi"
echo "Password: dangerous123"
echo "AP IP: 192.168.4.1"
echo "DHCP Range: 192.168.4.2 - 192.168.4.20"
echo "Access via: http://dangerous-pi.local or http://192.168.4.1"
echo ""
echo "Captive portal detection enabled: OS connectivity checks will trigger portal popup"
echo ""
echo "✓ Access Point configuration successful"
