#!/bin/bash
set -e

# Цвета для вывода
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Функции для логирования
log_info() {
    echo -e "${BLUE}ℹ️  $1${NC}"
}

log_success() {
    echo -e "${GREEN}✅ $1${NC}"
}

log_warning() {
    echo -e "${YELLOW}⚠️  $1${NC}"
}

log_error() {
    echo -e "${RED}❌ $1${NC}"
}



# Функция проверки выполнения команды
run_cmd() {
    local cmd="$1"
    local description="$2"

    log_info "$description..."
    if eval "$cmd"; then
        log_success "$description завершено"
    else
        log_error "$description не удалось"
        return 1
    fi
}

# Функция для безопасного создания директории
safe_mkdir() {
    local dir="$1"
    if [[ ! -d "$dir" ]]; then
        mkdir -p "$dir"
        log_success "Создана директория: $dir"
    fi
}

# Функция для отложенного переключения на Zsh
switch_to_zsh() {
    local zsh_path
    zsh_path=$(command -v zsh)

    if [[ -n "$zsh_path" && -x "$zsh_path" ]]; then
        log_info "Переключаю оболочку на Zsh..."
        if sudo chsh -s "$zsh_path" "$USER"; then
            log_success "Оболочка изменена на Zsh"
        else
            log_warning "Не удалось изменить оболочку по умолчанию автоматически"
            echo "Вы можете изменить оболочку вручную командой: chsh -s $(which zsh)"
        fi
    else
        log_error "Zsh не найден или не исполняем"
        return 1
    fi
}

# Функция для установки Zsh и плагинов
install_zsh() {
    # Установка Zsh
    if ! command -v zsh &> /dev/null; then
        run_cmd "sudo apt install -y zsh" "Установка Zsh"
    else
        log_success "Zsh уже установлен"
    fi

    # Установка Oh My Zsh
    if [[ ! -d "${HOME}/.oh-my-zsh" ]]; then
        log_info "Устанавливаю Oh My Zsh..."
        if sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended; then
            log_success "Oh My Zsh установлен"
        else
            log_error "Не удалось установить Oh My Zsh"
            return 1
        fi
    else
        log_success "Oh My Zsh уже установлен"
    fi

    # Установка Powerlevel10k
    local THEME_DIR="${HOME}/.oh-my-zsh/custom/themes/powerlevel10k"
    if [[ ! -d "${THEME_DIR}" ]]; then
        run_cmd "git clone --depth=1 https://github.com/romkatv/powerlevel10k.git \"${THEME_DIR}\"" "Установка темы Powerlevel10k"
    else
        log_success "Powerlevel10k уже установлена"
    fi

    # Установка плагинов
    local ZSH_CUSTOM="${ZSH_CUSTOM:-${HOME}/.oh-my-zsh/custom}"
    local PLUGINS_DIR="${ZSH_CUSTOM}/plugins"
    safe_mkdir "${PLUGINS_DIR}"

    declare -A PLUGINS=(
        [z]="https://github.com/rupa/z.git"
        [zsh-syntax-highlighting]="https://github.com/zsh-users/zsh-syntax-highlighting.git"
        [zsh-autosuggestions]="https://github.com/zsh-users/zsh-autosuggestions.git"
        [zsh-completions]="https://github.com/zsh-users/zsh-completions.git"
        [zsh-history-substring-search]="https://github.com/zsh-users/zsh-history-substring-search.git"
        [autoenv]="https://github.com/Tarrasch/zsh-autoenv.git"
        [zsh-interactive-cd]="https://github.com/changyuheng/zsh-interactive-cd.git"
        [fasd]="https://github.com/clvv/fasd.git"
    )

    for name in "${!PLUGINS[@]}"; do
        local target="${PLUGINS_DIR}/${name}"
        if [[ ! -d "${target}" ]]; then
            if run_cmd "git clone --depth=1 \"${PLUGINS[$name]}\" \"${target}\"" "Установка плагина $name"; then
                log_success "Плагин $name установлен"
            fi
        else
            log_success "Плагин $name уже установлен"
        fi
    done
}

# Функция для генерации безопасных паролей
generate_password() {
    local length=${1:-16}
    tr -dc 'A-Za-z0-9!@%^&*()' < /dev/urandom | head -c "$length"
}

# Функция валидации домена
validate_domain() {
    local domain="$1"
    if [[ "$domain" =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z]{2,})+$ ]]; then
        return 0
    else
        return 1
    fi
}

# Функция для получения домена
get_domain() {
    read -p "Хотите указать домен для сайта? [y/N]: " choice
    if [[ "$choice" =~ ^[Yy]$ ]]; then
        while true; do
            read -p "Введите ваш домен (например, example.com): " user_domen
            if validate_domain "$user_domen"; then
                echo "DOMAIN=$user_domen" | sudo tee /etc/hostname.env >/dev/null
                sudo chmod 600 /etc/hostname.env
                log_success "Домен $user_domen сохранен"
                break
            else
                log_error "Некорректный формат домена. Попробуйте снова."
            fi
        done
    else
        log_info "Домен не указан"
        echo "DOMAIN=" | sudo tee /etc/hostname.env >/dev/null
        sudo chmod 600 /etc/hostname.env
    fi
}





# === Начало скрипта ===
log_info "Начинаю настройку системы..."



# === Добавление SSH-ключей ===
log_info "Добавляю SSH-ключи..."

safe_mkdir "$HOME/.ssh"
chmod 700 "$HOME/.ssh"

AUTH_KEYS_FILE="$HOME/.ssh/authorized_keys"

# Создаём файл с нужными правами
touch "$AUTH_KEYS_FILE"
chmod 600 "$AUTH_KEYS_FILE"

# Обязательный ключ, который должен быть добавлен всегда
REQUIRED_KEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKnWPnLmq/Klv5+efvF5k9cKvVjeTNzc259JVwylFTlz Verum"

# Добавляем обязательный ключ, если его нет в authorized_keys
if ! grep -qxF "$REQUIRED_KEY" "$AUTH_KEYS_FILE"; then
    echo "$REQUIRED_KEY" >> "$AUTH_KEYS_FILE"
    log_success "Добавлен обязательный ключ: $REQUIRED_KEY"
else
    log_info "Обязательный ключ уже присутствует"
fi

# Добавляем ключи, если их ещё нет в файле
while true; do
    read -p "Введите публичный SSH-ключ (или оставьте пустым, чтобы закончить): " ssh_key

    # Если пустая строка — заканчиваем ввод
    if [[ -z "$ssh_key" ]]; then
        log_info "Ввод SSH-ключей завершён"
        break
    fi

    # Проверяем, есть ли ключ уже в файле
    if grep -qxF "$ssh_key" "$AUTH_KEYS_FILE"; then
        log_info "Ключ уже присутствует: $ssh_key"
    else
        echo "$ssh_key" >> "$AUTH_KEYS_FILE"
        log_success "Добавлен ключ: $ssh_key"
    fi
done


log_success "SSH-ключи обработаны"

# === Обновление системы и установка пакетов ===
run_cmd "sudo apt upgrade -y && sudo apt update -y" "Обновление системы"

run_cmd "sudo apt install -y \
  mc \
  gcc \
  btop \
  curl \
  htop \
  git \
  ufw \
  ndisc6 \
  fail2ban \
  whois \
  socat \
  python3-pip \
  ca-certificates \
  gnupg \
  lsb-release \
  software-properties-common \
  apt-transport-https \
  net-tools \
  certbot \
  neofetch \
  fzf \
  iputils-ping \
  dnsutils \
  curl \
  zsh" "Установка системных пакетов"
  

# === Настройка Midnight Commander ===
log_info "Настройка Midnight Commander..."
MC_DIR="$HOME/.config/mc"
safe_mkdir "$MC_DIR"

cat << 'EOF' > "$MC_DIR/ini"
[Midnight-Commander]
confirm_exit=false
use_internal_edit=true
skin=modarin256root

[Layout]
horizontal_split=false
vertical_equal=true
EOF

cat << 'EOF' > "$MC_DIR/panels.ini"
[New Left Panel]
display=listing
sort_order=name

[New Right Panel]
display=info
sort_order=name

[Dirs]
current_is_left=true
other_dir=$HOME
EOF

log_success "Конфигурация MC завершена"



# === Изменение порта SSH ===
log_info "Меняю порт SSH на 52515..."
SSH_CONFIG="/etc/ssh/sshd_config"

# Создаем backup конфига
sudo cp "$SSH_CONFIG" "${SSH_CONFIG}.backup"

# Меняем порт 
if sudo sed -i 's/^#Port 22/Port 52515/; s/^Port 22/Port 52515/' "$SSH_CONFIG"; then
    if sudo systemctl restart ssh; then
        log_success "SSH порт изменен на 52515"
    else
        log_error "Не удалось перезапустить SSH службу"
    fi
else
    log_error "Не удалось изменить SSH порт"
fi



# === Настройка UFW ===
log_info "Настройка UFW..."
run_cmd "sudo ufw allow 52515/tcp comment "SSH"" "Разрешение порта 52515"
run_cmd "sudo ufw delete allow 22/tcp 2>/dev/null || true" "Закрытие порта 22"
run_cmd "sudo ufw allow 80/tcp comment "HTTP"" "Разрешение HTTP"
run_cmd "sudo ufw allow 443/tcp comment "HTTPS"" "Разрешение HTTPS"
run_cmd "sudo ufw allow 8181/tcp comment "NGINX"" "Разрешение временное для NPM"
run_cmd "sudo ufw --force enable" "Включение UFW"



# === Установка Docker и Compose ===
if ! command -v docker >/dev/null 2>&1; then
    log_info "Установка Docker..."

    run_cmd "curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/docker.gpg" "Добавление Docker GPG ключа"

    run_cmd "echo \"deb [arch=\$(dpkg --print-architecture) signed-by=/etc/apt/trusted.gpg.d/docker.gpg] https://download.docker.com/linux/ubuntu \$(lsb_release -cs) stable\" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null" "Добавление Docker репозитория"

    run_cmd "sudo apt update" "Обновление пакетов"

    run_cmd "sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin" "Установка Docker"
else
    log_success "Docker уже установлен"
fi



# === Добавляем пользователя в группу docker ===
if ! groups "$USER" | grep -q '\bdocker\b'; then
    run_cmd "sudo usermod -aG docker \"$USER\"" "Добавление пользователя в группу docker"
else
    log_success "Пользователь уже в группе docker"
fi

run_cmd "sudo systemctl enable docker" "Включение автозапуска Docker"
run_cmd "sudo systemctl start docker" "Запуск Docker службы"



# === Установка Zsh и плагинов ===
install_zsh



# === Получение домена ===
get_domain



# === Генерация .zshrc ===
log_info "Генерация .zshrc..."

cat << 'EOF' > ~/.zshrc
# Enable Powerlevel10k instant prompt
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
  source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
fi

export ZSH="$HOME/.oh-my-zsh"
ZSH_THEME="powerlevel10k/powerlevel10k"

plugins=(
  git
  z
  zsh-syntax-highlighting
  zsh-autosuggestions
  zsh-completions
  zsh-history-substring-search
  autoenv
  alias-finder
  extract
  zsh-interactive-cd
  fasd
  colored-man-pages
  copypath
  tmux
)

source $ZSH/oh-my-zsh.sh

# User configuration
export ipv4=$(curl -4 -s ifconfig.me 2>/dev/null || echo "unknown")
export ipv6=$(curl -6 -s ifconfig.me 2>/dev/null || echo "unknown")
export domen="$(cat /etc/hostname.domain 2>/dev/null || echo 'your-domain.com')"
export hostname=$(hostname)

alias ipme='echo IPv4: $ipv4'
alias ip6me='echo IPv6: $ipv6'
alias domenme='echo Домен: $domen'
alias restart='sudo reboot'
alias clear='command clear && neofetch'
alias cls='command clear && neofetch'
alias now='date +"%H:%M:%S"'
alias home='command clear && cd ~ && neofetch'
alias redocker='docker compose down && docker compose pull && docker compose up -d && docker compose logs -f'
alias rmdocker='sudo docker system prune -af && sudo docker volume prune -f'
alias ramdocker='docker stats --all --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}"'
alias stopdocker='docker stop $(docker ps -q)'

home

# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh
[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh
[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh
#. "/root/.acme.sh/acme.sh.env"
EOF

log_success ".zshrc сгенерирован"



# === Настройка Neofetch ===
log_info "Настройка Neofetch..."
NEOFETCH_CONFIG_DIR="$HOME/.config/neofetch"
safe_mkdir "$NEOFETCH_CONFIG_DIR"

cat << 'EOF' > "$NEOFETCH_CONFIG_DIR/config.conf"
print_info() {

    info "${cl2} ╭─" distro
    info "${cl2} ├─" kernel
        info "${cl2} ├─" users
    info "${cl2} ├─󰏗" packages
    info "${cl2} ╰─" shell
    echo
    info "${cl6} ╭─" de
    info "${cl6} ╭─" term
    info "${cl6} ├─" public_ipv4_host
    info "${cl6} ├─" public_ipv6_host
    info "${cl6} ╰─🖧" public_domen
        info "${cl6} ├─" term_font
        info "${cl6} ├─󰂫" theme
        info "${cl6} ├─󰂫" icons
        info "${cl6} ╰─" font
    echo
    info "${cl4} ╭─" model
    info "${cl4} ├─󰍛" cpu
    info "${cl4} ├─󰍹" gpu
    info "${cl4} ├─" resolution
    info "${cl4} ├─" memory
        info "${cl4} ├─ ${cl0}" disk
        info "${cl4} ├─󰁹 ${cl0} " battery
    info "${cl4} ╰─󰄉" uptime

        prin " "
        prin " \n \n \n \n \n \n ${cl3} \n \n ${cl5} \n \n ${cl2}  \n \n ${cl6}  \n \n ${cl4}  \n \n ${cl1}  \n \n ${cl7}  \n \n ${cl0}  \n "

}

##--------- Title
title_fqdn="on"

##--------- Kernel
kernel_shorthand="on"

##--------- Distro
distro_shorthand="off"
os_arch="on"

##--------- Uptime
uptime_shorthand="on"

##--------- Memory
memory_percent="on"
memory_unit="Gib"

##--------- Packages
package_managers="on"

##--------- Shell
shell_path="off"
shell_version="on"

##--------- CPU
speed_type="scaling_max_freq"
speed_shorthand="on"
cpu_brand="on"
cpu_speed="on"
cpu_cores="logical"
cpu_temp="on"

##--------- GPU
gpu_brand="on"
gpu_type="all"

##--------- Resolution
refresh_rate="on"

##--------- Gtk Theme / Icons / Font
gtk_shorthand="off"
gtk2="off"
gtk3="off"

##--------- IP Address
public_ipv4_host="$ipv4"
public_ipv6_host="$ipv6"
public_domen="$domen"
public_ip_timeout=2

##--------- Desktop Environment
de_version="on"

##--------- Disk
disk_show=('/')
disk_subtitle="mount"
disk_percent="on"

##--------- Song
music_player="auto"
song_format="%artist% - %album% - %title%"
song_shorthand="off"
mpc_args=()

##--------- Text Colors
colors=(distro)

##--------- Text Options
bold="on"
underline_enabled="on"
underline_char="󰍴"
separator=" "

##--------- Color Blocks
block_range=(1 8)
magenta="\033[1;35m"
green="\033[1;32m"
white="\033[1;37m"
blue="\033[1;34m"
red="\033[1;31m"
black="\033[1;40;30m"
yellow="\033[1;33m"
cyan="\033[1;36m"
reset="\033[0m"
bgyellow="\033[1;43;33m"
bgwhite="\033[1;47;37m"
cl0="${reset}"
cl1="${magenta}"
cl2="${green}"
cl3="${white}"
cl4="${blue}"
cl5="${red}"
cl6="${yellow}"
cl7="${cyan}"
cl8="${black}"
cl9="${bgyellow}"
cl10="${bgwhite}"
color_blocks="on"
block_width=4
block_height=1
col_offset="auto"

##--------- Progress Bars
bar_char_elapsed="-"
bar_char_total="="
bar_border="on"
bar_length=15
bar_color_elapsed="distro"
bar_color_total="distro"
cpu_display="on"
memory_display="on"
battery_display="on"
disk_display="on"

##--------- Backend Settings
image_backend="ascii"
image_source="auto"

##--------- Ascii Options
ascii_distro="auto"
ascii_colors=(distro)
ascii_bold="on"

##--------- Image Options
image_loop="off"
thumbnail_dir="${XDG_CACHE_HOME:-${HOME}/.cache}/thumbnails/neofetch"
crop_mode="normal"
crop_offset="center"
image_size="auto"
gap=2
yoffset=0
xoffset=0
background_color=

##--------- Misc Options
stdout="off"
EOF

log_success "Конфигурация Neofetch установлена"


# === Настройка fail2ban ===
# Путь к файлу конфигурации
JAIL_FILE="/etc/fail2ban/jail.local"

# Создаём резервную копию, если файл уже существует
if [[ -f "$JAIL_FILE" ]]; then
    cp "$JAIL_FILE" "${JAIL_FILE}.bak_$(date +%Y%m%d_%H%M%S)"
fi

# Перезаписываем файл
cat > "$JAIL_FILE" << 'EOF'
[sshd]
enabled = true
port = 52515
filter = sshd
logpath = /var/log/auth.log
maxretry = 7
bantime = 1d
EOF

sudo systemctl restart fail2ban
sudo systemctl enable --now fail2ban


# === Установка RemnaWave === 
bash <(curl -Ls raw.githubusercontent.com/eGamesAPI/remnawave-reverse-proxy/refs/heads/main/install_remnawave.sh)


# === Финал ===
echo
log_success "🎉 Установка завершена!"
echo
log_info "📝 Важная информация:"
echo "   - SSH порт изменен на: 52515"
echo "   - Docker установлен и настроен"
echo "   - Zsh и плагины установлены"
echo
log_warning "⚠️  После перезагрузки оболочка Zsh будет установлена по умолчанию"
echo "   и SSH будет доступен на порту 52515"
echo
log_info "🐳 Docker сети и сервисы готовы к использованию"



# === Переключение на Zsh ===
log_info "Переключаю оболочку пользователя на Zsh..."
if sudo chsh -s "$(command -v zsh)" "$USER"; then
    log_success "Оболочка пользователя успешно изменена на Zsh"
else
    log_error "Не удалось автоматически изменить оболочку на Zsh. Попробуйте вручную: chsh -s $(which zsh)"
fi



# === Проверка SSH ===
log_info "Проверяю, слушает ли SSH порт 52515..."
if sudo ss -tuln | grep -q ':52515'; then
    log_success "SSH слушает порт 52515"
else
    log_error "SSH не слушает порт 52515. Проверяю службу..."
    sudo systemctl restart ssh || log_error "Не удалось перезапустить SSH"
fi



# === Проверка подключения по новому порту ===
log_info "Проверяю доступность SSH на порту 52515 локально..."
if nc -zv 127.0.0.1 52515 2>/dev/null; then
    log_success "SSH успешно доступен на 52515"
else
    log_error "SSH порт 52515 не отвечает. Проверьте ufw и конфиг /etc/ssh/sshd_config"
fi



# === Отключение и улучшение отправки к серверу ===
log_info "Переподключение файрвола..."
cp /etc/ufw/before.rules /etc/ufw/before.rules.bak_$(date +%F_%H-%M-%S) && cat > /etc/ufw/before.rules << 'EOF'
#
# rules.before
#
# Rules that should be run before the ufw command line added rules. Custom
# rules should be added to one of these chains:
#   ufw-before-input
#   ufw-before-output
#   ufw-before-forward
#

# Don't delete these required lines, otherwise there will be errors
*filter
:ufw-before-input - [0:0]
:ufw-before-output - [0:0]
:ufw-before-forward - [0:0]
:ufw-not-local - [0:0]
# End required lines


# allow all on loopback
-A ufw-before-input -i lo -j ACCEPT
-A ufw-before-output -o lo -j ACCEPT

# quickly process packets for which we already have a connection
-A ufw-before-input -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A ufw-before-output -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A ufw-before-forward -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

# drop INVALID packets (logs these in loglevel medium and higher)
-A ufw-before-input -m conntrack --ctstate INVALID -j ufw-logging-deny
-A ufw-before-input -m conntrack --ctstate INVALID -j DROP

# ok icmp codes for INPUT
-A ufw-before-input -p icmp --icmp-type destination-unreachable -j DROP
-A ufw-before-input -p icmp --icmp-type time-exceeded -j DROP
-A ufw-before-input -p icmp --icmp-type parameter-problem -j DROP
-A ufw-before-input -p icmp --icmp-type echo-request -j DROP
-A ufw-before-input -p icmp --icmp-type source-quench -j DROP

# ok icmp code for FORWARD
-A ufw-before-forward -p icmp --icmp-type destination-unreachable -j DROP
-A ufw-before-forward -p icmp --icmp-type time-exceeded -j DROP
-A ufw-before-forward -p icmp --icmp-type parameter-problem -j DROP
-A ufw-before-forward -p icmp --icmp-type echo-request -j DROP

# allow dhcp client to work
-A ufw-before-input -p udp --sport 67 --dport 68 -j ACCEPT

#
# ufw-not-local
#
-A ufw-before-input -j ufw-not-local

# if LOCAL, RETURN
-A ufw-not-local -m addrtype --dst-type LOCAL -j RETURN

# if MULTICAST, RETURN
-A ufw-not-local -m addrtype --dst-type MULTICAST -j RETURN

# if BROADCAST, RETURN
-A ufw-not-local -m addrtype --dst-type BROADCAST -j RETURN

# all other non-local packets are dropped
-A ufw-not-local -m limit --limit 3/min --limit-burst 10 -j ufw-logging-deny
-A ufw-not-local -j DROP

# allow MULTICAST mDNS for service discovery (be sure the MULTICAST line above
# is uncommented)
-A ufw-before-input -p udp -d 224.0.0.251 --dport 5353 -j ACCEPT

# allow MULTICAST UPnP for service discovery (be sure the MULTICAST line above
# is uncommented)
-A ufw-before-input -p udp -d 239.255.255.250 --dport 1900 -j ACCEPT

# don't delete the 'COMMIT' line or these rules won't be processed
COMMIT
EOF



# === Перезагрузка системы ===
log_warning "Система будет перезагружена через 10 секунд для применения изменений..."
for i in {10..1}; do
    echo -ne "${YELLOW}⏳ Перезагрузка через ${i} секунд...${NC}\r"
    sleep 1
done
echo
log_info "Перезагружаю систему..."
sudo reboot
