#!/bin/bash
#
# Home Lab Control Panel Installer
# 
# Downloads and installs from: https://homelab-panel.allenjenkins.com/

set -e
set -o pipefail

# Configuration
APP_BASE_NAME="${APP_BASE_NAME:-homelab}"
APP_NAME="${APP_NAME:-${APP_BASE_NAME} Panel}"
APP_VERSION="1.0.0"
SOURCE_URL="${SOURCE_URL:-https://homelab-panel.allenjenkins.com}"
DOWNLOAD_ZIP="${SOURCE_URL}/app-latest.zip"

# Paths
INSTALL_DIR="/opt/${APP_BASE_NAME}"
CONFIG_DIR="/etc/${APP_BASE_NAME}"
DATA_DIR="/var/lib/${APP_BASE_NAME}"
LOG_DIR="/var/log/${APP_BASE_NAME}"

# Settings
PHP_VERSION="8.3"
NODE_VERSION="20"
ADMIN_USERNAME="${ADMIN_USERNAME:-admin}"
ADMIN_PASSWORD="${ADMIN_PASSWORD:-}"
ADMIN_EMAIL="${ADMIN_EMAIL:-admin@localhost}"
SSL_EMAIL="${SSL_EMAIL:-admin@localhost}"
DOMAIN="${DOMAIN:-}"

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[OK]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
log_section() { echo -e "\n${BLUE}══════════════════════════════════════════════════════════════${NC}\n${BLUE}  $1${NC}\n${BLUE}══════════════════════════════════════════════════════════════${NC}\n"; }

cleanup() {
    local exit_code=$?
    if [ $exit_code -ne 0 ]; then
        log_error "Installation failed with exit code $exit_code"
        [ -n "$TEMP_DIR" ] && [ -d "$TEMP_DIR" ] && log_info "Temp files kept at: $TEMP_DIR"
    else
        [ -n "$TEMP_DIR" ] && [ -d "$TEMP_DIR" ] && rm -rf "$TEMP_DIR"
    fi
}
trap cleanup EXIT

parse_args() {
    while [[ $# -gt 0 ]]; do
        case $1 in
            --app-name=*) APP_BASE_NAME="${1#*=}"; shift ;;
            --admin-user=*) ADMIN_USERNAME="${1#*=}"; shift ;;
            --admin-password=*) ADMIN_PASSWORD="${1#*=}"; shift ;;
            --admin-email=*) ADMIN_EMAIL="${1#*=}"; shift ;;
            --domain=*) DOMAIN="${1#*=}"; shift ;;
            --source-url=*) SOURCE_URL="${1#*=}"; DOWNLOAD_ZIP="${SOURCE_URL}/app-latest.zip"; shift ;;
            --force) FORCE_REINSTALL="true"; shift ;;
            *) shift ;;
        esac
    done
}

check_root() {
    if [ "$EUID" -ne 0 ]; then
        log_error "This installer must be run as root (use sudo)"
        exit 1
    fi
}

detect_os() {
    if [ -f /etc/os-release ]; then
        . /etc/os-release
        OS=$ID
        OS_VERSION=$VERSION_ID
    else
        log_error "Cannot detect OS"
        exit 1
    fi
    log_info "Detected OS: $OS $OS_VERSION"
}

download_files() {
    log_section "Downloading Application Files"
    
    TEMP_DIR=$(mktemp -d)
    log_info "Download directory: $TEMP_DIR"
    
    apt-get update > /dev/null 2>&1
    apt-get install -y curl unzip > /dev/null 2>&1
    
    curl -fsSL "${DOWNLOAD_ZIP}" -o "${TEMP_DIR}/app.zip"
    cd "$TEMP_DIR"
    unzip -q "app.zip"
    
    log_success "Files downloaded and extracted"
}

update_system() {
    log_section "Updating System Packages"
    export DEBIAN_FRONTEND=noninteractive
    apt-get update
    apt-get upgrade -y
    apt-get install -y curl wget git unzip software-properties-common apt-transport-https ca-certificates gnupg2 jq sqlite3
    log_success "System packages updated"
}

setup_user() {
    log_section "Creating System User"
    
    if ! getent group "$APP_BASE_NAME" >/dev/null 2>&1; then
        groupadd --system "$APP_BASE_NAME"
        log_success "Created group: $APP_BASE_NAME"
    fi
    
    if ! id -u "$APP_BASE_NAME" >/dev/null 2>&1; then
        useradd --system --gid "$APP_BASE_NAME" --home "$INSTALL_DIR" --shell /bin/bash "$APP_BASE_NAME"
        log_success "Created user: $APP_BASE_NAME"
    fi
    
    usermod -aG "$APP_BASE_NAME" www-data 2>/dev/null || true
    usermod -aG docker "$APP_BASE_NAME" 2>/dev/null || true
}

install_php() {
    log_section "Installing PHP ${PHP_VERSION}"
    
    if [ "$OS" = "ubuntu" ]; then
        add-apt-repository -y ppa:ondrej/php
    else
        curl -fsSL https://packages.sury.org/php/apt.gpg | gpg --dearmor -o /usr/share/keyrings/php.gpg
        echo "deb [signed-by=/usr/share/keyrings/php.gpg] https://packages.sury.org/php/ $(lsb_release -cs) main" > /etc/apt/sources.list.d/php.list
    fi
    
    apt-get update
    apt-get install -y php${PHP_VERSION}-fpm php${PHP_VERSION}-cli php${PHP_VERSION}-common php${PHP_VERSION}-sqlite3 php${PHP_VERSION}-curl php${PHP_VERSION}-mbstring php${PHP_VERSION}-xml php${PHP_VERSION}-zip php${PHP_VERSION}-bcmath
    
    cat > "/etc/php/${PHP_VERSION}/fpm/pool.d/${APP_BASE_NAME}.conf" <<EOF
[${APP_BASE_NAME}]
user = ${APP_BASE_NAME}
group = ${APP_BASE_NAME}
listen = /var/run/php/php${PHP_VERSION}-fpm-${APP_BASE_NAME}.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
EOF
    
    systemctl restart "php${PHP_VERSION}-fpm"
    systemctl enable "php${PHP_VERSION}-fpm"
    log_success "PHP ${PHP_VERSION} installed"
}

install_composer() {
    log_section "Installing Composer"
    if ! command -v composer &> /dev/null; then
        curl -fsSL https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
        log_success "Composer installed"
    else
        log_info "Composer already installed"
    fi
}

install_node() {
    log_section "Installing Node.js"
    if ! command -v node &> /dev/null; then
        curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash -
        apt-get install -y nodejs
        log_success "Node.js installed"
    fi
}

install_docker() {
    log_section "Installing Docker"
    if ! command -v docker &> /dev/null; then
        curl -fsSL https://get.docker.com | sh
        systemctl enable docker
        systemctl start docker
        log_success "Docker installed"
    fi
    docker network create "${APP_BASE_NAME}-network" 2>/dev/null || true
}

install_nginx() {
    log_section "Installing Nginx"
    if ! command -v nginx &> /dev/null; then
        apt-get install -y nginx
        systemctl enable nginx
        log_success "Nginx installed"
    fi
    rm -f /etc/nginx/sites-enabled/default
}

ensure_admin_password() {
    if [ -z "$ADMIN_PASSWORD" ]; then
        log_info "Generating random admin password..."
        ADMIN_PASSWORD=$(openssl rand -base64 24 2>/dev/null | tr -dc 'a-zA-Z0-9' | head -c 16)
        log_info "Password generated: ${ADMIN_PASSWORD}"
    fi
}

setup_directories() {
    log_section "Creating Directories"
    
    # Remove existing installation if present
    if [ -d "$INSTALL_DIR" ]; then
        log_warn "Removing existing installation at $INSTALL_DIR"
        rm -rf "$INSTALL_DIR"
    fi
    if [ -d "$CONFIG_DIR" ]; then
        log_warn "Removing existing config at $CONFIG_DIR"
        rm -rf "$CONFIG_DIR"
    fi
    if [ -d "$DATA_DIR" ]; then
        log_warn "Removing existing data at $DATA_DIR"
        rm -rf "$DATA_DIR"
    fi
    if [ -d "$LOG_DIR" ]; then
        log_warn "Removing existing logs at $LOG_DIR"
        rm -rf "$LOG_DIR"
    fi
    
    mkdir -p "$INSTALL_DIR" "$CONFIG_DIR" "$CONFIG_DIR/library" "$DATA_DIR" "$LOG_DIR"
    chown -R "${APP_BASE_NAME}:${APP_BASE_NAME}" "$INSTALL_DIR" "$DATA_DIR" "$LOG_DIR"
    chmod 755 "$INSTALL_DIR" "$LOG_DIR"
    chmod 750 "$CONFIG_DIR" "$DATA_DIR"
    log_success "Directories created"
}

install_application() {
    log_section "Installing ${APP_NAME}"
    
    cp -r "${TEMP_DIR}/app/"* "$INSTALL_DIR/"
    cp -r "${TEMP_DIR}/app/".[^.]* "$INSTALL_DIR/" 2>/dev/null || true
    
    if [ -d "${TEMP_DIR}/config" ]; then
        cp "${TEMP_DIR}/config/"*.yml "$CONFIG_DIR/library/" 2>/dev/null || true
    fi
    
    chown -R "${APP_BASE_NAME}:${APP_BASE_NAME}" "$INSTALL_DIR"
    log_success "Application files installed"
}

generate_env() {
    log_info "Generating .env file..."
    
    cat > .env <<EOF
APP_BASE_NAME=${APP_BASE_NAME}
APP_NAME='${APP_NAME}'
APP_ENV=production
APP_KEY=
APP_DEBUG=false
APP_URL=http://localhost
APP_TIMEZONE=UTC
APP_LOCALE=en

DB_CONNECTION=sqlite
DB_DATABASE=${DATA_DIR}/database.sqlite

LOG_CHANNEL=daily
LOG_LEVEL=warning
LOG_PATH=${LOG_DIR}

FILESYSTEM_DISK=local

CACHE_STORE=file
SESSION_DRIVER=file
SESSION_LIFETIME=120
QUEUE_CONNECTION=sync

MAIL_MAILER=log

ADMIN_USERNAME=${ADMIN_USERNAME}
ADMIN_PASSWORD=${ADMIN_PASSWORD}
ADMIN_EMAIL=${ADMIN_EMAIL}

APP_PATH=${INSTALL_DIR}
CONFIG_PATH=${CONFIG_DIR}
DATA_PATH=${DATA_DIR}
DOCKER_NETWORK=${APP_BASE_NAME}-network

SSL_EMAIL=${SSL_EMAIL}
EOF
    
    chown "${APP_BASE_NAME}:${APP_BASE_NAME}" .env
    chmod 640 .env
}

setup_laravel() {
    log_section "Configuring Laravel"
    
    cd "$INSTALL_DIR"
    
    # Create directories (make sure bootstrap/cache exists!)
    mkdir -p bootstrap/cache
    mkdir -p storage/app/public
    mkdir -p storage/framework/cache/data
    mkdir -p storage/framework/sessions
    mkdir -p storage/framework/views
    mkdir -p storage/framework/testing
    mkdir -p storage/logs
    
    # Set proper ownership
    chown -R "${APP_BASE_NAME}:${APP_BASE_NAME}" bootstrap storage
    chmod -R 775 bootstrap storage
    
    # Generate app key inline (avoid php artisan which boots the app)
    log_info "Generating application key..."
    local APP_KEY="base64:$(openssl rand -base64 32 2>/dev/null | tr -d '\n')"
    
    # Create .env with generated key
    cat > .env <<EOF
APP_BASE_NAME=${APP_BASE_NAME}
APP_NAME='${APP_NAME}'
APP_ENV=production
APP_KEY=${APP_KEY}
APP_DEBUG=false
APP_URL=http://localhost
APP_TIMEZONE=UTC
APP_LOCALE=en

DB_CONNECTION=sqlite
DB_DATABASE=${DATA_DIR}/database.sqlite

LOG_CHANNEL=daily
LOG_LEVEL=warning

FILESYSTEM_DISK=local
CACHE_STORE=file
SESSION_DRIVER=file
SESSION_LIFETIME=120
QUEUE_CONNECTION=sync

MAIL_MAILER=log

ADMIN_USERNAME=${ADMIN_USERNAME}
ADMIN_PASSWORD=${ADMIN_PASSWORD}
ADMIN_EMAIL=${ADMIN_EMAIL}

APP_PATH=${INSTALL_DIR}
CONFIG_PATH=${CONFIG_DIR}
DATA_PATH=${DATA_DIR}
DOCKER_NETWORK=${APP_BASE_NAME}-network

SSL_EMAIL=${SSL_EMAIL}
EOF
    
    chown "${APP_BASE_NAME}:${APP_BASE_NAME}" .env
    chmod 640 .env
    
    # Install composer deps
    log_info "Installing PHP dependencies..."
    COMPOSER_ALLOW_SUPERUSER=1 composer install --no-dev --optimize-autoloader --no-interaction --no-scripts
    
    # Database
    log_info "Setting up database..."
    touch "${DATA_DIR}/database.sqlite"
    chown "${APP_BASE_NAME}:${APP_BASE_NAME}" "${DATA_DIR}/database.sqlite"
    chmod 644 "${DATA_DIR}/database.sqlite"
    
    # Clear any compiled config before migrations
    rm -f bootstrap/cache/*.php 2>/dev/null || true
    
    # Try to run migrations (may fail if artisan has issues, but continue anyway)
    log_info "Running database migrations..."
    php artisan migrate --force 2>&1 || {
        log_warn "Migrations could not run automatically."
        log_warn "You may need to run manually: cd ${INSTALL_DIR} && php artisan migrate --force"
        log_warn "Or check: cat ${INSTALL_DIR}/.env"
    }
    
    # Build assets
    if [ -f "package.json" ]; then
        log_info "Building frontend assets..."
        npm install 2>&1 | tail -5
        npm run build 2>&1 | tail -10 || log_warn "Asset build had warnings"
    fi
    
    # Storage link
    php artisan storage:link --force 2>/dev/null || true
    
    # Final permissions
    find "$INSTALL_DIR" -type d -exec chmod 755 {} \;
    find "$INSTALL_DIR" -type f -exec chmod 644 {} \;
    chmod -R 775 "$INSTALL_DIR/storage" "$INSTALL_DIR/bootstrap/cache"
    chown -R "${APP_BASE_NAME}:${APP_BASE_NAME}" "$INSTALL_DIR" "$DATA_DIR"
    
    log_success "Laravel configured"
}

configure_nginx() {
    log_section "Configuring Nginx"
    
    local DOMAIN_CONFIG="${DOMAIN:-_}"
    
    cat > "/etc/nginx/sites-available/${APP_BASE_NAME}" <<EOF
upstream ${APP_BASE_NAME}_php {
    server unix:/var/run/php/php${PHP_VERSION}-fpm-${APP_BASE_NAME}.sock;
}

server {
    listen 80;
    listen [::]:80;
    server_name ${DOMAIN_CONFIG};
    root ${INSTALL_DIR}/public;
    index index.php;

    access_log ${LOG_DIR}/nginx-access.log;
    error_log ${LOG_DIR}/nginx-error.log;

    location / {
        try_files \$uri \$uri/ /index.php?\$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 /index.php;

    location ~ \.php$ {
        fastcgi_pass ${APP_BASE_NAME}_php;
        fastcgi_param SCRIPT_FILENAME \$realpath_root\$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_hide_header X-Powered-By;
    }

    location ~ /\.well-known { allow all; }
    location ~ /\. { deny all; }

    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
}
EOF
    
    ln -sf "/etc/nginx/sites-available/${APP_BASE_NAME}" "/etc/nginx/sites-enabled/${APP_BASE_NAME}"
    nginx -t && systemctl reload nginx
    log_success "Nginx configured"
}

setup_systemd() {
    log_section "Setting up Systemd Services"
    
    cat > "/etc/systemd/system/${APP_BASE_NAME}-scheduler.service" <<EOF
[Unit]
Description=${APP_NAME} Scheduler
After=network.target

[Service]
Type=simple
User=${APP_BASE_NAME}
Group=${APP_BASE_NAME}
ExecStart=/usr/bin/php ${INSTALL_DIR}/artisan schedule:work
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
EOF
    
    cat > "/etc/systemd/system/${APP_BASE_NAME}-worker.service" <<EOF
[Unit]
Description=${APP_NAME} Queue Worker
After=network.target

[Service]
Type=simple
User=${APP_BASE_NAME}
Group=${APP_BASE_NAME}
ExecStart=/usr/bin/php ${INSTALL_DIR}/artisan queue:work --sleep=3 --tries=3
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
EOF
    
    cat > "/etc/systemd/system/${APP_BASE_NAME}-monitor.service" <<EOF
[Unit]
Description=${APP_NAME} Container Monitor
After=docker.service

[Service]
Type=oneshot
User=root
Group=docker
ExecStart=/usr/bin/php ${INSTALL_DIR}/artisan containers:health-check
StandardOutput=journal
StandardError=journal
EOF
    
    cat > "/etc/systemd/system/${APP_BASE_NAME}-monitor.timer" <<EOF
[Unit]
Description=${APP_NAME} Container Monitor Timer

[Timer]
OnBootSec=2min
OnUnitActiveSec=5min
Unit=${APP_BASE_NAME}-monitor.service

[Install]
WantedBy=timers.target
EOF
    
    systemctl daemon-reload
    systemctl enable "${APP_BASE_NAME}-scheduler" "${APP_BASE_NAME}-worker" "${APP_BASE_NAME}-monitor.timer"
    systemctl start "${APP_BASE_NAME}-scheduler" "${APP_BASE_NAME}-worker" "${APP_BASE_NAME}-monitor.timer"
    
    log_success "Systemd services configured"
}

show_summary() {
    log_section "Installation Complete!"
    
    # Get the actual IP address
    local IP_ADDRESS=$(hostname -I 2>/dev/null | awk '{print $1}' || echo "$(ip route get 1 | awk '{print $7}' | head -1)")
    [ -z "$IP_ADDRESS" ] && IP_ADDRESS="$(cat /etc/hostname 2>/dev/null || echo 'localhost')"
    
    echo "${APP_NAME} has been successfully installed!"
    echo ""
    echo "Installation Details:"
    echo "  Install Path: ${INSTALL_DIR}"
    echo "  Config Path:  ${CONFIG_DIR}"
    echo "  Data Path:    ${DATA_DIR}"
    echo ""
    echo "Admin Access:"
    echo "  Username: ${ADMIN_USERNAME}"
    if [ -n "$ADMIN_PASSWORD" ]; then
        echo "  Password: ${ADMIN_PASSWORD}"
    else
        echo "  Password: (not set - check ${INSTALL_DIR}/.env)"
    fi
    echo "  URL:      http://${IP_ADDRESS}/admin"
}

main() {
    log_section "${APP_NAME} Installer v${APP_VERSION}"
    
    parse_args "$@"
    check_root
    detect_os
    download_files
    update_system
    setup_user
    install_php
    install_composer
    install_node
    install_docker
    install_nginx
    setup_directories
    ensure_admin_password
    install_application
    setup_laravel
    configure_nginx
    setup_systemd
    show_summary
}

main "$@"
