#!/bin/bash

# dsp-install-profile - Install DSP profile using REST API
# Copyright (c) 2025 HiFiBerry

set -e

SCRIPT_NAME="$(basename "$0")"
VERSION="1.3.2"
DEFAULT_HOST="localhost"
DEFAULT_PORT="13141"
TIMEOUT=30

# Function to show usage
show_usage() {
    cat << EOF
Usage: $SCRIPT_NAME [OPTIONS] PROFILE_FILE

Install a DSP profile XML file to HiFiBerry DSP using the REST API.

ARGUMENTS:
    PROFILE_FILE        Path to the XML profile file to install

OPTIONS:
    -h, --host HOST     DSP server hostname or IP address (default: $DEFAULT_HOST)
    -p, --port PORT     DSP server port (default: $DEFAULT_PORT)
    -t, --timeout SEC   Connection timeout in seconds (default: $TIMEOUT)
    -v, --verbose       Enable verbose output
    -q, --quiet         Suppress non-error output
    --help              Show this help message
    --version           Show version information

EXAMPLES:
    # Install profile to local DSP
    $SCRIPT_NAME /path/to/profile.xml
    
    # Install profile to remote DSP
    $SCRIPT_NAME -h 192.168.1.100 /path/to/profile.xml
    
    # Install with custom port and verbose output
    $SCRIPT_NAME -h dsp.local -p 8080 -v /path/to/profile.xml

EXIT CODES:
    0   Success
    1   General error
    2   Invalid arguments
    3   Profile file not found or not readable
    4   Connection error
    5   API error

For more information, see dsp-install-profile(1).
EOF
}

# Function to show version
show_version() {
    echo "$SCRIPT_NAME version $VERSION"
    echo "Part of HiFiBerry DSP toolkit"
}

# Function to log messages
log() {
    local level="$1"
    shift
    case "$level" in
        "ERROR")
            echo "ERROR: $*" >&2
            ;;
        "WARN")
            echo "WARNING: $*" >&2
            ;;
        "INFO")
            if [ "$QUIET" != "1" ]; then
                echo "INFO: $*"
            fi
            ;;
        "VERBOSE")
            if [ "$VERBOSE" = "1" ]; then
                echo "VERBOSE: $*"
            fi
            ;;
    esac
}

# Function to check if command exists
command_exists() {
    command -v "$1" >/dev/null 2>&1
}

# Function to validate XML file
validate_xml_file() {
    local file="$1"
    
    if [ ! -f "$file" ]; then
        log "ERROR" "Profile file '$file' not found"
        return 3
    fi
    
    if [ ! -r "$file" ]; then
        log "ERROR" "Profile file '$file' is not readable"
        return 3
    fi
    
    # Basic XML validation - check if it looks like XML
    if ! head -n 5 "$file" | grep -q "<?xml"; then
        log "WARN" "File '$file' does not appear to be an XML file"
    fi
    
    return 0
}

# Function to test API connectivity
test_api_connection() {
    local host="$1"
    local port="$2"
    local timeout="$3"
    
    log "VERBOSE" "Testing connection to $host:$port"
    
    if ! curl -sf --connect-timeout "$timeout" \
              "http://$host:$port/metadata" \
              >/dev/null 2>&1; then
        log "ERROR" "Cannot connect to DSP API at $host:$port"
        log "ERROR" "Make sure the sigmatcpserver is running and accessible"
        return 4
    fi
    
    log "VERBOSE" "Connection test successful"
    return 0
}

# Function to install profile
install_profile() {
    local host="$1"
    local port="$2"
    local timeout="$3"
    local profile_file="$4"
    
    log "INFO" "Installing profile '$profile_file' to DSP at $host:$port"
    
    # Validate XML content
    if ! validate_xml_file "$profile_file"; then
        log "ERROR" "Invalid XML content in profile file"
        return 3
    fi
    
    log "VERBOSE" "Sending profile to API endpoint"
    
    # Make API call with raw XML content
    local response
    local http_code
    
    response="$(curl -s --connect-timeout "$timeout" \
                     -w "HTTPSTATUS:%{http_code}" \
                     -H "Content-Type: application/xml" \
                     -X POST \
                     --data-binary "@$profile_file" \
                     "http://$host:$port/dspprofile" 2>&1)"
    
    if [ $? -ne 0 ]; then
        log "ERROR" "Failed to connect to DSP API"
        log "ERROR" "Response: $response"
        return 4
    fi
    
    # Extract HTTP status code
    http_code="$(echo "$response" | grep "HTTPSTATUS:" | cut -d: -f2)"
    response="$(echo "$response" | sed 's/HTTPSTATUS:.*$//')"
    
    log "VERBOSE" "HTTP Status: $http_code"
    log "VERBOSE" "Response: $response"
    
    # Check HTTP status
    case "$http_code" in
        "200")
            log "INFO" "Profile installed successfully"
            
            # Parse response for additional info
            if echo "$response" | grep -q '"status":"success"'; then
                log "INFO" "Installation verified"
                
                # Show checksum info if available
                if echo "$response" | grep -q '"checksums"'; then
                    log "VERBOSE" "Checksum verification completed"
                fi
            else
                log "WARN" "Profile uploaded but verification status unclear"
            fi
            ;;
        "400")
            log "ERROR" "Bad request - invalid profile data"
            log "ERROR" "Response: $response"
            return 5
            ;;
        "404")
            log "ERROR" "API endpoint not found - check server version"
            return 5
            ;;
        "500")
            log "ERROR" "Server error during profile installation"
            log "ERROR" "Response: $response"
            return 5
            ;;
        *)
            log "ERROR" "Unexpected HTTP status: $http_code"
            log "ERROR" "Response: $response"
            return 5
            ;;
    esac
    
    return 0
}

# Main function
main() {
    local host="$DEFAULT_HOST"
    local port="$DEFAULT_PORT"
    local timeout="$TIMEOUT"
    local profile_file=""
    local VERBOSE=0
    local QUIET=0
    
    # Check for required tools
    if ! command_exists curl; then
        log "ERROR" "curl is required but not found"
        log "ERROR" "Please install curl: apt-get install curl"
        exit 1
    fi
    
    # Parse arguments
    while [ $# -gt 0 ]; do
        case "$1" in
            -h|--host)
                shift
                if [ -z "$1" ]; then
                    log "ERROR" "Host argument requires a value"
                    exit 2
                fi
                host="$1"
                ;;
            -p|--port)
                shift
                if [ -z "$1" ]; then
                    log "ERROR" "Port argument requires a value"
                    exit 2
                fi
                if ! echo "$1" | grep -q '^[0-9]\+$'; then
                    log "ERROR" "Port must be a number"
                    exit 2
                fi
                port="$1"
                ;;
            -t|--timeout)
                shift
                if [ -z "$1" ]; then
                    log "ERROR" "Timeout argument requires a value"
                    exit 2
                fi
                if ! echo "$1" | grep -q '^[0-9]\+$'; then
                    log "ERROR" "Timeout must be a number"
                    exit 2
                fi
                timeout="$1"
                ;;
            -v|--verbose)
                VERBOSE=1
                ;;
            -q|--quiet)
                QUIET=1
                ;;
            --help)
                show_usage
                exit 0
                ;;
            --version)
                show_version
                exit 0
                ;;
            -*)
                log "ERROR" "Unknown option: $1"
                show_usage >&2
                exit 2
                ;;
            *)
                if [ -z "$profile_file" ]; then
                    profile_file="$1"
                else
                    log "ERROR" "Too many arguments"
                    show_usage >&2
                    exit 2
                fi
                ;;
        esac
        shift
    done
    
    # Validate arguments
    if [ -z "$profile_file" ]; then
        log "ERROR" "Profile file argument is required"
        show_usage >&2
        exit 2
    fi
    
    # Validate XML file
    validate_xml_file "$profile_file"
    local ret=$?
    if [ $ret -ne 0 ]; then
        exit $ret
    fi
    
    # Test API connection
    test_api_connection "$host" "$port" "$timeout"
    ret=$?
    if [ $ret -ne 0 ]; then
        exit $ret
    fi
    
    # Install profile
    install_profile "$host" "$port" "$timeout" "$profile_file"
    ret=$?
    if [ $ret -ne 0 ]; then
        exit $ret
    fi
    
    log "INFO" "Profile installation completed successfully"
    exit 0
}

# Run main function
main "$@"