#!/bin/bash
# Fibocom FM350-GL 5G Modem Configuration Script
# For Alpine Linux. Supports config file /etc/5g-router.conf
# Usage: ./configure_fm350_5g.sh
# Rev: 1  (see REVISION in repo root)

set -e

# Defaults (overridden by /etc/5g-router.conf if present)
AT_PORT="${AT_PORT:-/dev/ttyUSB1}"
APN="${APN:-internet}"
WAN_IF="${WAN_IF:-eth1}"
LAN_IF="${LAN_IF:-eth0.100}"
LOG_SIGNAL="${LOG_SIGNAL:-no}"
WEAK_SIGNAL_CSQ="${WEAK_SIGNAL_CSQ:-0}"
[ -f /etc/5g-router.conf ] && . /etc/5g-router.conf
LOG_FILE="${LOG_FILE:-/var/log/5g-router.log}"

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }

send_at_cmd() {
    local cmd="$1"
    local wait="${2:-2}"
    [ -c "$AT_PORT" ] || return 1
    cat $AT_PORT 2>/dev/null &
    local CAT_PID=$!
    sleep 0.3
    [ -c "$AT_PORT" ] || { kill $CAT_PID 2>/dev/null; return 1; }
    echo -e "${cmd}\r" > $AT_PORT
    sleep $wait
    kill $CAT_PID 2>/dev/null || true
}

get_at_response() {
    local cmd="$1"
    local wait="${2:-2}"
    [ -c "$AT_PORT" ] || return 1
    timeout $((wait + 3)) sh -c "
        [ -c \"$AT_PORT\" ] || exit 1
        cat $AT_PORT 2>/dev/null &
        CAT_PID=\$!
        sleep 0.3
        echo -e '${cmd}\r' > $AT_PORT
        sleep $wait
        kill \$CAT_PID 2>/dev/null
    " 2>&1
}

check_modem() {
    log_info "Checking for FM350-GL modem..."
    
    if ! lsusb | grep -qi "fibocom"; then
        log_error "Fibocom modem not detected via USB"
        exit 1
    fi
    
    local usb_id=$(lsusb | grep -i fibocom | grep -oE '0e8d:[0-9a-f]+')
    log_info "Modem detected: $usb_id"
    
    if [ "$usb_id" = "0e8d:7127" ]; then
        log_warn "Modem is in Mode 41 (7127). AT commands may not work."
        log_warn "Attempting to switch to Mode 40 (modem will reset)..."
        get_at_response "AT+GTUSBMODE=40" 2 >/dev/null || true
        get_at_response "AT+CFUN=1,1" 5 >/dev/null || true
        log_info "Wait ~30s for modem to reappear, then re-run this script."
        exit 1
    fi
    
    if [ ! -c "$AT_PORT" ]; then
        log_error "AT port $AT_PORT not available"
        exit 1
    fi
    
    log_info "AT port available: $AT_PORT"
}

test_at_commands() {
    log_info "Testing AT command communication..."
    
    local response=$(get_at_response "AT" 1)
    
    if echo "$response" | grep -q "OK"; then
        log_info "AT communication working"
        return 0
    else
        log_error "AT commands not responding"
        return 1
    fi
}

check_signal() {
    log_info "Checking signal strength..."
    
    local response=$(get_at_response "AT+CSQ" 1)
    local csq=$(echo "$response" | grep "+CSQ:" | grep -oE '[0-9]+' | head -1)
    
    if [ -n "$csq" ]; then
        if [ "$csq" -lt 10 ]; then
            log_warn "Signal strength: $csq (weak)"
        elif [ "$csq" -lt 20 ]; then
            log_info "Signal strength: $csq (moderate)"
        else
            log_info "Signal strength: $csq (good)"
        fi
        [ "$LOG_SIGNAL" = "yes" ] && echo "$(date -Iseconds) CSQ=$csq" >> "$LOG_FILE" 2>/dev/null || true
        if [ -n "$WEAK_SIGNAL_CSQ" ] && [ "$WEAK_SIGNAL_CSQ" -gt 0 ] && [ "$csq" -lt "$WEAK_SIGNAL_CSQ" ]; then
            log_warn "Signal below threshold ($WEAK_SIGNAL_CSQ): $csq"
            [ -w "$LOG_FILE" ] && echo "$(date -Iseconds) WARN weak signal CSQ=$csq" >> "$LOG_FILE" || true
        fi
    else
        log_warn "Could not read signal strength"
    fi
}

configure_apn() {
    log_info "Configuring APN: $APN"
    
    local response=$(get_at_response "AT+CGDCONT=1,\"IP\",\"$APN\"" 2)
    
    if echo "$response" | grep -q "OK"; then
        log_info "APN configured successfully"
    else
        log_warn "APN configuration may have failed"
    fi
}

activate_pdp() {
    log_info "Activating PDP context..."
    
    local response=$(get_at_response "AT+CGACT=1,1" 3)
    
    if echo "$response" | grep -qE "(OK|CGEV)"; then
        log_info "PDP context activated"
    else
        log_warn "PDP activation response: $response"
    fi
}

get_modem_ip() {
    log_info "Getting modem IP address..."
    
    local response=$(get_at_response "AT+CGPADDR=1" 2)
    local ip=$(echo "$response" | grep "+CGPADDR:" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)
    
    if [ -n "$ip" ]; then
        log_info "Modem IP: $ip"
        echo "$ip"
    else
        log_error "Could not get modem IP"
        return 1
    fi
}

configure_interface() {
    local ip="$1"
    
    log_info "Configuring network interface $WAN_IF..."
    
    ip link set $WAN_IF up 2>/dev/null || true
    ip addr flush dev $WAN_IF 2>/dev/null || true
    ip addr add $ip/32 dev $WAN_IF
    ip route add default dev $WAN_IF metric 50 2>/dev/null || true
    
    log_info "Interface configured with IP: $ip"
}

setup_nat() {
    log_info "Setting up NAT for LAN ($LAN_IF)..."
    
    # Enable IP forwarding
    echo 1 > /proc/sys/net/ipv4/ip_forward
    
    # Add NAT rules (check if they exist first)
    iptables -t nat -C POSTROUTING -o $WAN_IF -j MASQUERADE 2>/dev/null || \
        iptables -t nat -A POSTROUTING -o $WAN_IF -j MASQUERADE
    
    iptables -C FORWARD -i $LAN_IF -o $WAN_IF -j ACCEPT 2>/dev/null || \
        iptables -A FORWARD -i $LAN_IF -o $WAN_IF -j ACCEPT
    
    iptables -C FORWARD -i $WAN_IF -o $LAN_IF -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || \
        iptables -A FORWARD -i $WAN_IF -o $LAN_IF -m state --state RELATED,ESTABLISHED -j ACCEPT
    
    log_info "NAT configured"
}

test_connectivity() {
    log_info "Testing internet connectivity..."
    
    if ping -c 3 8.8.8.8 >/dev/null 2>&1; then
        log_info "Ping to 8.8.8.8: SUCCESS"
    else
        log_error "Ping to 8.8.8.8: FAILED"
        return 1
    fi
    
    if ping -c 2 google.com >/dev/null 2>&1; then
        log_info "DNS resolution: SUCCESS"
    else
        log_warn "DNS resolution failed - check /etc/resolv.conf"
    fi
}

show_status() {
    echo ""
    echo "========================================="
    echo "     5G Modem Configuration Summary     "
    echo "========================================="
    echo ""
    echo "Modem: $(lsusb | grep -i fibocom | cut -d' ' -f6-)"
    echo "AT Port: $AT_PORT"
    echo "APN: $APN"
    echo ""
    echo "Interface: $WAN_IF"
    ip addr show $WAN_IF 2>/dev/null | grep -E "(state|inet )" | sed 's/^/  /'
    echo ""
    echo "Routing:"
    ip route show | grep -E "(default|$WAN_IF)" | sed 's/^/  /'
    echo ""
    echo "========================================="
}

# Main execution
main() {
    log_info "Starting FM350-GL 5G modem configuration..."
    echo ""
    
    check_modem
    test_at_commands || exit 1
    check_signal
    configure_apn
    activate_pdp
    
    local modem_ip=$(get_modem_ip)
    if [ -z "$modem_ip" ]; then
        log_error "Failed to get modem IP. Exiting."
        exit 1
    fi
    
    configure_interface "$modem_ip"
    setup_nat
    test_connectivity
    
    show_status
    
    log_info "5G modem configuration complete!"
}

main "$@"
