#!/bin/sh

SAVE=/tmp/run/fan_control
ACTION=${1}
shift

. /usr/share/fan-control/common.sh

load_config() {
    TEMP_MIN=$(uci get luci-fan.@luci-fan[0].temp_min 2>/dev/null || echo "40")
    TEMP_MAX=$(uci get luci-fan.@luci-fan[0].temp_max 2>/dev/null || echo "70")

    if [ "$TEMP_MIN" -gt 1000 ]; then
        TEMP_MIN=$((TEMP_MIN / 1000))
        uci set luci-fan.@luci-fan[0].temp_min="$TEMP_MIN"
        uci commit luci-fan
    fi

    if [ "$TEMP_MAX" -gt 1000 ]; then
        TEMP_MAX=$((TEMP_MAX / 1000))
        uci set luci-fan.@luci-fan[0].temp_max="$TEMP_MAX"
        uci commit luci-fan
    fi

    PWM_PATH=$(uci get luci-fan.@luci-fan[0].pwm_path 2>/dev/null || echo "")
    PWM_ENABLE_PATH=$(uci get luci-fan.@luci-fan[0].pwm_enable_path 2>/dev/null || echo "")
    PWM_INVERTED=$(uci get luci-fan.@luci-fan[0].pwm_inverted 2>/dev/null || echo "0")
    SLEEP_INTERVAL=$(uci get luci-fan.@luci-fan[0].sleep_interval 2>/dev/null || echo "15")
    THERMAL_ZONE_CPU=$(uci get luci-fan.@luci-fan[0].thermal_zone_cpu 2>/dev/null || echo "/sys/class/thermal/thermal_zone0/temp")
    MODEM_TEMP_METHOD=$(uci get luci-fan.@luci-fan[0].modem_temp_method 2>/dev/null || echo "AUTO")
    ENABLED=$(uci get luci-fan.@luci-fan[0].enabled 2>/dev/null || echo "0")

    CACHE_DIR="/var/cache/fan_control"
    MODEM_TEMP_CACHE="${CACHE_DIR}/modem_temp"
    CPU_TEMP_CACHE="${CACHE_DIR}/cpu_temp"
    AVG_TEMP_CACHE="${CACHE_DIR}/avg_temp"
    CURRENT_PWM="${CACHE_DIR}/current_pwm"
    LAST_MODEM_QUERY="${CACHE_DIR}/last_modem_query"
    DETECTED_MODEM_CACHE="${CACHE_DIR}/detected_modem"

    MODEM_QUERY_INTERVAL=30
    MODEM_QUERY_INTERVAL_STOPPED=5

    mkdir -p "$CACHE_DIR"
    [ ! -f "$MODEM_TEMP_CACHE" ] && echo "0" > "$MODEM_TEMP_CACHE"
    [ ! -f "$CPU_TEMP_CACHE" ] && echo "0" > "$CPU_TEMP_CACHE"
    [ ! -f "$AVG_TEMP_CACHE" ] && echo "0" > "$AVG_TEMP_CACHE"
    [ ! -f "$CURRENT_PWM" ] && echo "140" > "$CURRENT_PWM"
    [ ! -f "$LAST_MODEM_QUERY" ] && echo "0" > "$LAST_MODEM_QUERY"
}

is_running() {
    pgrep -f "/usr/libexec/fan-control daemon" >/dev/null 2>&1
    return $?
}

detect_supported_modem() {
    local modem_id=$(detect_modem_id)
    local modem_script="/usr/share/fan-control/modem/usb/$modem_id"
    
    if [ -f "$modem_script" ] && [ -x "$modem_script" ]; then
        echo "$modem_id"
        return 0
    else
        return 1
    fi
}

get_modem_temp() {
    FORCE=${1:-0}
    
    if [ "$MODEM_TEMP_METHOD" = "NONE" ]; then
        echo "0"
        return
    fi
    
    if [ "$MODEM_TEMP_METHOD" = "AUTO" ]; then
        current_time=$(date +%s)
        last_query_time=$(cat "$LAST_MODEM_QUERY" 2>/dev/null || echo "0")
        time_diff=$((current_time - last_query_time))

        if [ "$FORCE" = "0" ]; then
            if is_running; then
                interval=$MODEM_QUERY_INTERVAL
            else
                interval=$MODEM_QUERY_INTERVAL_STOPPED
            fi
            
            if [ "$time_diff" -lt "$interval" ]; then
                cached_temp=$(cat "$MODEM_TEMP_CACHE" 2>/dev/null)
                if [ -n "$cached_temp" ] && [ "$cached_temp" -gt 0 ]; then
                    echo "$cached_temp"
                    return
                fi
            fi
        fi

        detected_modem_info=$(cat "$DETECTED_MODEM_CACHE" 2>/dev/null)
        if [ -z "$detected_modem_info" ] || [ "$FORCE" = "1" ]; then
            detected_modem=$(detect_supported_modem)
            if [ -n "$detected_modem" ]; then
                echo "$detected_modem" > "$DETECTED_MODEM_CACHE"
                detected_modem_info="$detected_modem"
            else
                echo "0"
                return
            fi
        fi

        working_device=$(find_working_device "$detected_modem_info")
        if [ -z "$working_device" ]; then
            echo "0"
            return
        fi

        load_modem_driver "$detected_modem_info"
        temp=$(get_modem_temperature "$working_device" 2>/dev/null)
        temp_int=$(echo "${temp%.*}" | bc 2>/dev/null || echo "0")

        if [ "$temp_int" -gt 0 ] && [ "$temp_int" -lt 120 ]; then
            echo "$temp_int" > "$MODEM_TEMP_CACHE"
            echo "$current_time" > "$LAST_MODEM_QUERY"
            echo "$temp_int"
            return
        fi

        cpu_temp=$(cat "$CPU_TEMP_CACHE" 2>/dev/null || echo "0")
        if [ "$cpu_temp" -gt 0 ]; then
            estimated=$((cpu_temp + 10))
            echo "$estimated" > "$MODEM_TEMP_CACHE"
            echo "$current_time" > "$LAST_MODEM_QUERY"
            echo "$estimated"
        else
            echo "0"
        fi
    else
        echo "0"
    fi
}

calculate_pwm_value() {
    local calculated_pwm="$1"
    
    if [ "$PWM_INVERTED" = "1" ]; then
        if [ "$calculated_pwm" -eq 140 ]; then
            echo "140"
        elif [ "$calculated_pwm" -eq 0 ]; then
            echo "255"
        else
            pwm_value=$((255 - calculated_pwm))
            if [ "$pwm_value" -lt 140 ]; then
                pwm_value=140
            fi
            echo "$pwm_value"
        fi
    else
        echo "$calculated_pwm"
    fi
}

set_pwm_value() {
    local input_pwm="$1"
    local actual_pwm
    
    if [ "$PWM_INVERTED" = "1" ]; then
        actual_pwm=$(calculate_pwm_value "$input_pwm")
    else
        actual_pwm="$input_pwm"
    fi
    
    if [ ! -w "$PWM_PATH" ]; then
        chmod 666 "$PWM_PATH" 2>/dev/null
    fi

    if [ -w "$PWM_PATH" ]; then
        echo "$actual_pwm" > "$PWM_PATH" 2>/dev/null
        if [ $? -eq 0 ]; then
            echo "$actual_pwm" > "$CURRENT_PWM"
            return 0
        else
            return 1
        fi
    else
        return 1
    fi
}

start_fan_control() {
    load_config

    if [ "$ENABLED" != "1" ]; then
        return 1
    fi

    if [ ! -f "$PWM_PATH" ]; then
        return 1
    fi

    if [ ! -f "$THERMAL_ZONE_CPU" ]; then
        return 1
    fi

    if [ ! -w "$PWM_PATH" ]; then
        chmod 666 "$PWM_PATH" 2>/dev/null
    fi

    if [ -f "$PWM_ENABLE_PATH" ]; then
        if [ ! -w "$PWM_ENABLE_PATH" ]; then
            chmod 666 "$PWM_ENABLE_PATH" 2>/dev/null
        fi
    fi

    if [ ! -w "$PWM_PATH" ]; then
        return 1
    fi
    
    if [ "$TEMP_MIN" -eq 0 ] && [ "$TEMP_MAX" -eq 0 ]; then
        TEMP_MIN=40
        TEMP_MAX=70
    fi

    if [ "$TEMP_MIN" -ge "$TEMP_MAX" ]; then
        exit 1
    fi

    set_pwm_value 140

    if [ -f "$PWM_ENABLE_PATH" ] && [ -w "$PWM_ENABLE_PATH" ]; then
        echo "1" > "$PWM_ENABLE_PATH"
    fi

    while true; do
        cpu_temp=$(cat "$THERMAL_ZONE_CPU")
        cpu_temp_int=$((cpu_temp / 1000))
        echo "$cpu_temp_int" > "$CPU_TEMP_CACHE"

        modem_temp=$(get_modem_temp)
        modem_temp_int=${modem_temp%.*}

        if [ -z "$modem_temp_int" ] || [ "$modem_temp_int" -eq 0 ] || [ "$MODEM_TEMP_METHOD" = "NONE" ]; then
            avg_temp=$cpu_temp_int
        else
            avg_temp=$(( (modem_temp_int + cpu_temp_int) / 2 ))
        fi

        echo "$avg_temp" > "$AVG_TEMP_CACHE"

        if [ "$avg_temp" -lt "$TEMP_MIN" ]; then
            pwm_value=140
        elif [ "$avg_temp" -ge "$TEMP_MAX" ]; then
            pwm_value=0
        else
            temp_range=$((TEMP_MAX - TEMP_MIN))
            temp_offset=$((avg_temp - TEMP_MIN))
            pwm_value=$((140 - (140 * temp_offset / temp_range)))
        fi

        if [ "$pwm_value" -lt 0 ]; then
            pwm_value=0
        elif [ "$pwm_value" -gt 140 ]; then
            pwm_value=140
        fi

        set_pwm_value "$pwm_value"
        save_temp_history
        sleep "$SLEEP_INTERVAL"
    done

    return 0
}

stop_fan_control() {
    load_config
    
    if [ -d "/var/cache/fan_control" ]; then
        echo "140" > "/var/cache/fan_control/current_pwm" 2>/dev/null
    fi

    if [ -w "$PWM_PATH" ]; then
        if [ "$PWM_INVERTED" = "1" ]; then
            echo "140" > "$PWM_PATH" 2>/dev/null
        else
            echo "140" > "$PWM_PATH" 2>/dev/null
        fi
    fi
}

status_fan_control() {
    if is_running; then
        echo "running"
    else
        echo "stopped"
    fi
}

init_fan_control() {
    load_config
    mkdir -p "$(dirname "$SAVE")"
    touch "$SAVE"

    rm -f "$MODEM_TEMP_CACHE" 2>/dev/null
    rm -f "$CPU_TEMP_CACHE" 2>/dev/null
    rm -f "$AVG_TEMP_CACHE" 2>/dev/null
    rm -f "$CURRENT_PWM" 2>/dev/null
    rm -f "$LAST_MODEM_QUERY" 2>/dev/null
    rm -f "$DETECTED_MODEM_CACHE" 2>/dev/null

    echo "0" > "$MODEM_TEMP_CACHE" 2>/dev/null
    echo "0" > "$CPU_TEMP_CACHE" 2>/dev/null
    echo "0" > "$AVG_TEMP_CACHE" 2>/dev/null
    echo "140" > "$CURRENT_PWM" 2>/dev/null
    echo "0" > "$LAST_MODEM_QUERY" 2>/dev/null

    if [ -w "$PWM_PATH" ]; then
        if [ "$PWM_INVERTED" = "1" ]; then
            echo "140" > "$PWM_PATH" 2>/dev/null
        else
            echo "140" > "$PWM_PATH" 2>/dev/null
        fi
    fi
}

get_temp_info() {
    load_config

    if [ -f "$THERMAL_ZONE_CPU" ]; then
        cpu_temp=$(cat "$THERMAL_ZONE_CPU" 2>/dev/null || echo "0")
        cpu_temp_int=$((cpu_temp / 1000))
        echo "$cpu_temp_int" > "$CPU_TEMP_CACHE"
    else
        cpu_temp_int=$(cat "$CPU_TEMP_CACHE" 2>/dev/null || echo "0")
    fi

    if is_running; then
        modem_temp=$(get_modem_temp 0)
    else
        if [ "$MODEM_TEMP_METHOD" = "AUTO" ]; then
            modem_temp=$(get_modem_temp 1)
        else
            modem_temp="0"
        fi
    fi

    if [ -z "$modem_temp" ] || [ "$modem_temp" = "0" ] || [ "$MODEM_TEMP_METHOD" = "NONE" ]; then
        avg_temp=$cpu_temp_int
    else
        avg_temp=$(( (modem_temp + cpu_temp_int) / 2 ))
    fi
    echo "$avg_temp" > "$AVG_TEMP_CACHE"

    current_pwm_display=$(cat "$CURRENT_PWM" 2>/dev/null || echo "140")

    if [ "$PWM_INVERTED" = "1" ]; then
        fan_percent=$(( current_pwm_display * 100 / 255 ))
    else
        fan_percent=$(( (255 - current_pwm_display) * 100 / 255 ))
    fi
    
    if ! is_running; then
        fan_percent=0
    fi

    echo "$cpu_temp_int $modem_temp $current_pwm_display $fan_percent $avg_temp"
}

save_temp_history() {
    HISTORY_DIR="/var/cache/fan_control/history"
    mkdir -p "$HISTORY_DIR"
    
    TIMESTAMP=$(date +%s)
    
    cpu_temp_int=$(cat "$CPU_TEMP_CACHE" 2>/dev/null || echo "0")
    modem_temp_int=$(cat "$MODEM_TEMP_CACHE" 2>/dev/null || echo "0")
    avg_temp=$(cat "$AVG_TEMP_CACHE" 2>/dev/null || echo "0")
    current_pwm=$(cat "$CURRENT_PWM" 2>/dev/null || echo "140")
    
    if [ "$PWM_INVERTED" = "1" ]; then
        fan_percent=$(( current_pwm * 100 / 255 ))
    else
        fan_percent=$(( (255 - current_pwm) * 100 / 255 ))
    fi
    
    if ! is_running; then
        fan_percent=0
    fi
    
    MAX_ENTRIES=1440
    HISTORY_FILE="$HISTORY_DIR/temp_history.csv"
    
    if [ ! -f "$HISTORY_FILE" ]; then
        echo "timestamp,cpu_temp,modem_temp,avg_temp,fan_percent" > "$HISTORY_FILE"
    fi
    
    echo "$TIMESTAMP,$cpu_temp_int,$modem_temp_int,$avg_temp,$fan_percent" >> "$HISTORY_FILE"
    
    if [ $(wc -l < "$HISTORY_FILE") -gt $((MAX_ENTRIES + 1)) ]; then
        tail -n $MAX_ENTRIES "$HISTORY_FILE" > "$HISTORY_FILE.tmp"
        mv "$HISTORY_FILE.tmp" "$HISTORY_FILE"
    fi
}

get_modem_info() {
    load_config
    
    if [ "$MODEM_TEMP_METHOD" = "NONE" ]; then
        echo "method:NONE"
        return
    fi
    
    detected_modem=$(detect_supported_modem)
    if [ -n "$detected_modem" ]; then
        load_modem_driver "$detected_modem"
        working_device=$(find_working_device "$detected_modem")
        
        echo "method:AUTO usb_id:$detected_modem name:$NAME manufacturer:$MANUFACTURER port:$working_device"
    else
        echo "method:AUTO status:no_modem_detected"
    fi
}

usage() {
    echo "usage: $0 sub-command"
    echo "where sub-command is one of:"
    echo "      get                     Show current fan configuration"
    echo "      set MAX_TEMP [MIN_TEMP] Set maximum and (optional) minimum temperature thresholds"
    echo "      temp                    Display current CPU temperature and PWM value (legacy)"
    echo "      init                    Initialize cache files and default settings"
    echo "      stop                    Stop fan control and restore default fan speed"
    echo "      status                  Check if the fan control service is running"
    echo "      info                    Show CPU temp, modem temp, PWM and fan percentage"
    echo "      modem_info              Show detected modem information"
    echo "      history_update          Manually append the current status to the CSV log"
    echo "      daemon                  Start the fan control service (for internal use)"
}

case ${ACTION} in
    "get")
        load_config
        echo "temp_min: $TEMP_MIN"
        echo "temp_max: $TEMP_MAX"
        echo "pwm_path: $PWM_PATH"
        echo "pwm_enable_path: $PWM_ENABLE_PATH"
        echo "pwm_inverted: $PWM_INVERTED"
        echo "sleep_interval: $SLEEP_INTERVAL"
        echo "thermal_zone_cpu: $THERMAL_ZONE_CPU"
        echo "modem_temp_method: $MODEM_TEMP_METHOD"
        echo "enabled: $ENABLED"
    ;;
    "set")
        ON_TEMP="$1"
        OFF_TEMP="$2"
        if [ -n "$ON_TEMP" ]; then
            if [ "$ON_TEMP" -gt 1000 ]; then
                ON_TEMP=$((ON_TEMP / 1000))
            fi
            uci set luci-fan.@luci-fan[0].temp_max="$ON_TEMP"

            if [ -n "$OFF_TEMP" ]; then
                if [ "$OFF_TEMP" -gt 1000 ]; then
                    OFF_TEMP=$((OFF_TEMP / 1000))
                fi
                uci set luci-fan.@luci-fan[0].temp_min="$OFF_TEMP"
            else
                uci set luci-fan.@luci-fan[0].temp_min="$(($ON_TEMP - 5))"
            fi
            uci commit luci-fan
        fi
    ;;
    "temp")
        get_temp_info | awk '{print $1*1000, $3}'
    ;;
    "init")
        init_fan_control
    ;;
    "stop")
        stop_fan_control
    ;;
    "status")
        status_fan_control
    ;;
    "info")
        get_temp_info
    ;;
    "modem_info")
        get_modem_info
    ;;
    "history_update")
        load_config
        save_temp_history
    ;;
    "daemon")
        start_fan_control
    ;;
    *)
        usage
        exit 1
    ;;
esac