#!/bin/bash

# MiniPanel Installer for Debian 12
# Run as root

set -e # Exit on error

if [ "$EUID" -ne 0 ]
  then echo "Please run as root"
  exit
fi

# Initialize Argument Variables
HOSTNAME_ARG=""
OVERWRITE_ARG=false
UPDATE_ARG=false
PROXY_ARG=false
PROXY_PATH_ARG=""
MYSQL_ACTION="" # "install" or "existing"
MYSQL_PASS_ARG=""
INTERACTIVE_MODE=true

# Parse Arguments
if [[ $# -gt 0 ]]; then
    INTERACTIVE_MODE=false
fi

while [[ $# -gt 0 ]]; do
  case $1 in
    -h)
      HOSTNAME_ARG="$2"
      shift 2
      ;;
    -o)
      OVERWRITE_ARG=true
      shift
      ;;
    -U)
      UPDATE_ARG=true
      shift
      ;;
    -p)
      PROXY_ARG=true
      if [[ -n "$2" && "$2" != -* ]]; then
        PROXY_PATH_ARG="$2"
        shift 2
      else
        shift
      fi
      ;;
    -s)
      if [[ -n "$2" && "$2" != -* ]]; then
        MYSQL_ACTION="existing"
        MYSQL_PASS_ARG="$2"
        shift 2
      else
        MYSQL_ACTION="install"
        shift
      fi
      ;;
    *)
      echo "Unknown option $1"
      exit 1
      ;;
  esac
done

# Validate Arguments
if [ "$OVERWRITE_ARG" = true ] && [ "$UPDATE_ARG" = true ]; then
  echo "Error: -o (Overwrite) and -U (Update) cannot be used together."
  exit 1
fi

echo "Checking System Compatibility..."
# Check for Debian 12 or higher
if [ -f /etc/os-release ]; then
    . /etc/os-release
    if [ "$ID" != "debian" ]; then
        echo "Error: This script is designed for Debian."
        exit 1
    fi
    VERSION_ID_NUM=$(echo "$VERSION_ID" | cut -d. -f1)
    if [ "$VERSION_ID_NUM" -lt 12 ]; then
        echo "Error: Debian 12 or higher is required. Found version $VERSION_ID."
        exit 1
    fi
    echo "System detected: Debian $VERSION_ID (Compatible)"
else
    echo "Error: Cannot detect OS version."
    exit 1
fi

# 1. Ask for Hostname
if [ -n "$HOSTNAME_ARG" ]; then
    SERVER_HOSTNAME="$HOSTNAME_ARG"
elif [ "$INTERACTIVE_MODE" = true ]; then
    read -p "Enter the Hostname for this server (e.g., srv1.example.com): " SERVER_HOSTNAME
else
    # Non-interactive and no hostname provided
    # Attempt to use current hostname
    SERVER_HOSTNAME=$(hostname)
    echo "No hostname argument provided. Using current: $SERVER_HOSTNAME"
fi

if [ -z "$SERVER_HOSTNAME" ]; then
    echo "Hostname cannot be empty. Please use -h argument."
    exit 1
fi
echo "Setting hostname to $SERVER_HOSTNAME..."
hostnamectl set-hostname "$SERVER_HOSTNAME"
echo "127.0.0.1 $SERVER_HOSTNAME" >> /etc/hosts

# 2. Ask for Proxy
INSTALL_PROXY="N"
PROXY_PATH=""

if [ "$PROXY_ARG" = true ]; then
    INSTALL_PROXY="y"
    if [ -n "$PROXY_PATH_ARG" ]; then
        PROXY_PATH="$PROXY_PATH_ARG"
    else
        PROXY_PATH=$(openssl rand -hex 4)
    fi
    # Ensure path starts with /
    [[ "${PROXY_PATH}" != /* ]] && PROXY_PATH="/$PROXY_PATH"
elif [ "$INTERACTIVE_MODE" = true ]; then
    # Interactive check
    read -p "Do you want to expose the panel via Nginx Proxy (port 80/443)? [y/N]: " INSTALL_PROXY_INPUT
    INSTALL_PROXY=${INSTALL_PROXY_INPUT:-N}
    if [[ "$INSTALL_PROXY" =~ ^[yY]$ ]]; then
        DEFAULT_PATH=$(openssl rand -hex 4)
        read -p "Enter the secure path for the panel (default: /$DEFAULT_PATH): " PROXY_PATH
        PROXY_PATH=${PROXY_PATH:-$DEFAULT_PATH}
        # Ensure path starts with /
        [[ "${PROXY_PATH}" != /* ]] && PROXY_PATH="/$PROXY_PATH"
    fi
else
    # Non-interactive default
    INSTALL_PROXY="N"
fi

echo "Updating system..."
apt-get update && apt-get upgrade -y

echo "Installing Core Dependencies..."
apt-get install -y git curl wget unzip acl mdadm smartmontools sudo build-essential lsb-release ca-certificates apt-transport-https gnupg2 screen

echo "Installing Python Dependencies..."
apt-get install -y python3 python3-venv python3-pip python3-dev libffi-dev libssl-dev

echo "Installing Web Server Dependencies..."
apt-get install -y nginx certbot python3-certbot-nginx || true

# Ensure Zones exist
mkdir -p /etc/nginx/conf.d
echo "limit_conn_zone \$binary_remote_addr zone=addr:10m;" > /etc/nginx/conf.d/liper_zones.conf

# Fix any broken installs
apt-get install -f -y

# Setup Sury PHP Repo
echo "Setting up PHP repository..."
PHP_CODENAME=""
if [ -n "$VERSION_CODENAME" ]; then
    PHP_CODENAME="$VERSION_CODENAME"
else
    PHP_CODENAME=$(lsb_release -sc)
fi
echo "Detected distribution codename: $PHP_CODENAME"

curl -sSLo /usr/share/keyrings/deb.sury.org-php.gpg https://packages.sury.org/php/apt.gpg
echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ $PHP_CODENAME main" > /etc/apt/sources.list.d/php.list
apt-get update

# Create installation directory
INSTALL_DIR="/opt/liper"
echo "Installing to $INSTALL_DIR..."

DO_UPDATE=0

if [ -d "$INSTALL_DIR" ]; then
    echo "Liper is already installed."
    
    if [ "$OVERWRITE_ARG" = true ]; then
        UPDATE_CHOICE="o"
    elif [ "$UPDATE_ARG" = true ]; then
        UPDATE_CHOICE="U"
    elif [ "$INTERACTIVE_MODE" = true ]; then
        # Interactive
        read -p "Do you want to [U]pdate (keep data) or [O]verwrite (clean install)? [U/o]: " UPDATE_CHOICE
        UPDATE_CHOICE=${UPDATE_CHOICE:-U}
    else
        echo "Non-interactive mode: Defaulting to Update."
        UPDATE_CHOICE="U"
    fi
    
    if [[ "$UPDATE_CHOICE" =~ ^[oO]$ ]]; then
        echo "Overwriting... Backing up old install to ${INSTALL_DIR}_backup_$(date +%s)"
        mv $INSTALL_DIR "${INSTALL_DIR}_backup_$(date +%s)"
    else
        echo "Updating... Existing data will be preserved."
        DO_UPDATE=1
    fi
fi

# Generate Secret Key
if [ $DO_UPDATE -eq 0 ] || [ ! -f "$INSTALL_DIR/instance/config.json" ]; then
    SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_hex(32))")
fi

# Copy files
if [ $DO_UPDATE -eq 1 ]; then
    mkdir -p /tmp/liper_update_temp
    if [ -d "$INSTALL_DIR/instance" ]; then
        cp -r "$INSTALL_DIR/instance" /tmp/liper_update_temp/
    fi
    if [ -d "liper" ]; then
        cp -r liper/* $INSTALL_DIR/
    else
        echo "Error: liper source directory not found!"
        exit 1
    fi
    if [ -d "/tmp/liper_update_temp/instance" ]; then
        cp -r /tmp/liper_update_temp/instance/* "$INSTALL_DIR/instance/" 2>/dev/null || true
    fi
    rm -rf /tmp/liper_update_temp
else
    mkdir -p $INSTALL_DIR
    if [ -d "liper" ]; then
        cp -r liper/* $INSTALL_DIR/
        rm -f $INSTALL_DIR/instance/liper.sqlite
    else
        echo "Error: liper source directory not found!"
        exit 1
    fi
    # Also copy install.sh to the root of the installation directory for future self-updates
    if [ -f "install.sh" ]; then
        cp install.sh $INSTALL_DIR/
        chmod +x $INSTALL_DIR/install.sh
    fi
fi

# Create venv
echo "Creating virtual environment..."
python3 -m venv $INSTALL_DIR/venv
source $INSTALL_DIR/venv/bin/activate
pip install -r $INSTALL_DIR/requirements.txt

# Create Config if needed
mkdir -p $INSTALL_DIR/instance
if [ ! -f "$INSTALL_DIR/instance/config.json" ]; then
    echo "{\"SECRET_KEY\": \"$SECRET_KEY\"}" > $INSTALL_DIR/instance/config.json
fi

# Create default panel Nginx limits config
if [ ! -f "$INSTALL_DIR/instance/panel_nginx.conf" ]; then
    cat <<EOF > $INSTALL_DIR/instance/panel_nginx.conf
client_max_body_size 1M;
proxy_read_timeout 300s;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
EOF
fi

# Create Panel Self-Signed Certs
if [ ! -f "$INSTALL_DIR/instance/panel.key" ]; then
    echo "Generating Self-Signed Certificate for Panel..."
    openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
        -keyout $INSTALL_DIR/instance/panel.key \
        -out $INSTALL_DIR/instance/panel.crt \
        -subj "/C=IT/ST=Italy/L=Rome/O=Liper/OU=Panel/CN=liper-panel"
    chmod 600 $INSTALL_DIR/instance/panel.key
fi

# Create Systemd Service
echo "Creating systemd service..."
cat <<EOF > /etc/systemd/system/liper.service
[Unit]
Description=Liper Web Interface
After=network.target

[Service]
User=root
Group=root
WorkingDirectory=$INSTALL_DIR
Environment="PATH=$INSTALL_DIR/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
ExecStart=$INSTALL_DIR/venv/bin/gunicorn -w 1 -b 127.0.0.1:4317 'app:create_app()'
Restart=always

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable liper
systemctl restart liper

# Configure MySQL
INSTALL_MYSQL="N"
MYSQL_ROOT_PASS=""
MYSQL_CONFIG_FAILED=0

if [ "$MYSQL_ACTION" == "install" ]; then
    INSTALL_MYSQL="y"
elif [ "$MYSQL_ACTION" == "existing" ]; then
    INSTALL_MYSQL="N"
    # Validate connection immediately
    if ! mysql -u root -p"$MYSQL_PASS_ARG" -e "SELECT 1" >/dev/null 2>&1; then
        echo "Error: Provided MySQL password failed authentication."
        MYSQL_CONFIG_FAILED=1
    else
        MYSQL_ROOT_PASS="$MYSQL_PASS_ARG"
        # Save credential
        mkdir -p $INSTALL_DIR/instance
        echo "{\"host\": \"127.0.0.1\", \"user\": \"root\", \"password\": \"$MYSQL_ROOT_PASS\"}" > $INSTALL_DIR/instance/mysql_config.json
        chmod 600 $INSTALL_DIR/instance/mysql_config.json
    fi
elif [ "$INTERACTIVE_MODE" = true ]; then
    # Interactive
    read -p "Install MySQL/MariaDB Server? [y/N]: " INSTALL_MYSQL
    INSTALL_MYSQL=${INSTALL_MYSQL:-N}
else
    # Non-interactive default
    INSTALL_MYSQL="N"
fi

if [[ "$INSTALL_MYSQL" =~ ^[yY]$ ]]; then
    echo "Installing MariaDB Server..."
    apt-get install -y mariadb-server
    
    # Wait for MariaDB to be ready
    for i in {1..30}; do
        if mysql -e "SELECT 1" >/dev/null 2>&1; then
            break
        fi
        sleep 1
    done

    MYSQL_ROOT_PASS=$(openssl rand -base64 12)
    
    # Secure Installation
    # Use ALTER USER for compatibility with modern MariaDB (Debian 12 uses 10.11+)
    echo "ALTER USER 'root'@'localhost' IDENTIFIED BY '$MYSQL_ROOT_PASS';" | mysql
    
    # Export Password for subsequent commands (since socket auth might be disabled by ALTER USER)
    export MYSQL_PWD="$MYSQL_ROOT_PASS"
    mysql -e "DELETE FROM mysql.user WHERE User='';"
    mysql -e "DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');"
    mysql -e "DROP DATABASE IF EXISTS test;"
    mysql -e "DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';"
    mysql -e "FLUSH PRIVILEGES;"
    unset MYSQL_PWD
    
    # Configure bind-address
    if [ -f /etc/mysql/mariadb.conf.d/50-server.cnf ]; then
        sed -i 's/^bind-address.*/bind-address = 127.0.0.1/' /etc/mysql/mariadb.conf.d/50-server.cnf
        systemctl restart mariadb
    fi
    
    # Save credential
    mkdir -p $INSTALL_DIR/instance
    echo "{\"host\": \"127.0.0.1\", \"user\": \"root\", \"password\": \"$MYSQL_ROOT_PASS\"}" > $INSTALL_DIR/instance/mysql_config.json
    chmod 600 $INSTALL_DIR/instance/mysql_config.json
    
    echo "MySQL Installed and Secured."

elif [ "$MYSQL_ACTION" != "existing" ] && [ "$INTERACTIVE_MODE" = true ]; then
    # Interactive Ask for existing if not installed above and not pre-configured via CLI
    read -p "Enter existing MySQL Root Password (leave empty to skip): " MYSQL_ROOT_PASS_INPUT
    if [ ! -z "$MYSQL_ROOT_PASS_INPUT" ]; then
        # Validate loop
        while ! mysql -u root -p"$MYSQL_ROOT_PASS_INPUT" -e "SELECT 1" >/dev/null 2>&1; do
            echo "Error: Authentication failed."
            read -p "Enter existing MySQL Root Password (leave empty to skip): " MYSQL_ROOT_PASS_INPUT
            if [ -z "$MYSQL_ROOT_PASS_INPUT" ]; then break; fi
        done
        
        if [ ! -z "$MYSQL_ROOT_PASS_INPUT" ]; then
            MYSQL_ROOT_PASS=$MYSQL_ROOT_PASS_INPUT
            mkdir -p $INSTALL_DIR/instance
            echo "{\"host\": \"127.0.0.1\", \"user\": \"root\", \"password\": \"$MYSQL_ROOT_PASS\"}" > $INSTALL_DIR/instance/mysql_config.json
            chmod 600 $INSTALL_DIR/instance/mysql_config.json
        fi
    fi
fi

# Configure Panel Nginx
echo "Configuring Panel Nginx Block..."
cat <<EOF > /etc/nginx/sites-available/liper-panel
server {
    listen 8016;
    server_name _;
    return 301 https://\$host:4316\$request_uri;
}

server {
    listen 4316 ssl;
    server_name _;
    
    ssl_certificate $INSTALL_DIR/instance/panel.crt;
    ssl_certificate_key $INSTALL_DIR/instance/panel.key;
    
    include $INSTALL_DIR/instance/panel_nginx.conf;
    
    location / {
        proxy_pass http://127.0.0.1:4317;
        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;
    }
}
EOF
ln -sf /etc/nginx/sites-available/liper-panel /etc/nginx/sites-enabled/

FINAL_URL="https://$SERVER_HOSTNAME:4316/"

# Configure Proxy
if [[ "$INSTALL_PROXY" =~ ^[yY]$ ]]; then
    echo "Configuring Nginx Proxy on path $PROXY_PATH..."
    cat <<EOF > /etc/nginx/sites-available/liper
server {
    listen 80;
    server_name $SERVER_HOSTNAME;
    return 301 https://\$host\$request_uri;
}

server {
    listen 443 ssl;
    server_name $SERVER_HOSTNAME; 

    ssl_certificate $INSTALL_DIR/instance/panel.crt;
    ssl_certificate_key $INSTALL_DIR/instance/panel.key;

    # Panel Proxy
    location $PROXY_PATH {
        include $INSTALL_DIR/instance/panel_nginx.conf;
        
        # Note: Trailing slash in proxy_pass is critical for stripping the path prefix
        proxy_pass http://127.0.0.1:4317/;
        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 X-Forwarded-Prefix $PROXY_PATH;
    }

    # Default Welcome Page
    location / {
        root $INSTALL_DIR/static/default_page;
        index index.html;
    }
}
EOF
    ln -sf /etc/nginx/sites-available/liper /etc/nginx/sites-enabled/
    if [ -f /etc/nginx/sites-enabled/default ]; then
        rm /etc/nginx/sites-enabled/default
    fi
    
    FINAL_URL="https://$SERVER_HOSTNAME$PROXY_PATH"
    echo "Panel Proxy is available at $FINAL_URL"
fi

# Test and Reload
nginx -t && systemctl reload nginx || echo "Warning: Nginx reload failed. Check configuration."

if [ $DO_UPDATE -eq 0 ]; then
    # Generate Credentials (ONLY for fresh install)
    ADMIN_USER=$(date +%s%N)
    ADMIN_PASS=$(openssl rand -base64 24 | tr -dc 'a-zA-Z0-9' | head -c 32)

    echo "Setting up admin credentials..."
    $INSTALL_DIR/venv/bin/python3 -c "
import sys
sys.path.append('$INSTALL_DIR')
from app import create_app
from database import db
from models import Admin
from werkzeug.security import generate_password_hash

app = create_app()
with app.app_context():
    admin = Admin.query.first()
    if admin:
        admin.username = '$ADMIN_USER'
        admin.password = generate_password_hash('$ADMIN_PASS')
        db.session.commit()
    else:
        db.session.add(Admin(username='$ADMIN_USER', password=generate_password_hash('$ADMIN_PASS')))
        db.session.commit()
"
    echo "Installation Complete!"
    echo "Access Liper at $FINAL_URL"
    echo "---------------------------------------------------"
    echo "Username: $ADMIN_USER"
    echo "Password: $ADMIN_PASS"
    if [ ! -z "$MYSQL_ROOT_PASS" ]; then
        echo "MySQL Root Password: $MYSQL_ROOT_PASS"
    fi
    echo "---------------------------------------------------"
    echo "SAVE THESE CREDENTIALS NOW!"
else
    echo "Update Complete!"
    echo "Your existing credentials remain valid."
fi

# Alert if MySQL config failed via CLI
if [ "$MYSQL_CONFIG_FAILED" -eq 1 ]; then
    echo ""
    echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
    echo "WARNING: MySQL Configuration Failed!"
    echo "The password provided via CLI argument was incorrect."
    echo "MySQL features will not work until you configure it manually in:"
    echo "$INSTALL_DIR/instance/mysql_config.json"
    echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
    
    # Try sending alert (if settings exist)
    $INSTALL_DIR/venv/bin/python3 -c "
import sys
sys.path.append('$INSTALL_DIR')
try:
    from app import create_app
    from monitor import send_alert
    from models import Settings
    app = create_app()
    with app.app_context():
        s = Settings.query.first()
        if s:
            send_alert(s, 'Installation Warning', 'MySQL Configuration Failed during non-interactive install (Invalid Password).')
except:
    pass
"
fi
