#!/bin/bash

set -e

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'      # Ярко-жёлтый
BLUE='\033[1;34m'        # Ярко-синий
CYAN='\033[0;36m'        # Бирюзовый
WHITE='\033[1;37m'       # Белый жирный
GRAY='\033[0;37m'        # Серый
NC='\033[0m'             # No Color

# Функции вывода с цветами
info() { echo -e "${BLUE}[  INFO ]${NC} $1"; }
success() { echo -e "${GREEN}[    OK ]${NC} $1"; }
warn() { echo -e "${YELLOW}[  WARN ]${NC} $1"; }
error() { echo -e "${RED}[ ERROR ]${NC} $1"; }
debug() { echo -e "${GRAY}[ DEBUG ]${NC} $1"; }
title() { echo -e "${WHITE}==========================================${NC}"; }

# ==========================================
# ОСНОВНОЙ СКРИПТ DNS ОБНОВЛЕНИЯ (встраивается в установщик)
# ==========================================
MAIN_SCRIPT_CONTENT='#!/bin/bash

# ==========================================
# Автообновление DNS записи в Windows AD DNS
# протестировано на Ubuntu 24.04
# ==========================================

REALM="NVI-SOLUTIONS.RU"
DOMAIN="nvi-solutions.ru"
LOG_FILE="/var/log/dns-update.log"

log() {
    echo "$(date '\''+%Y-%m-%d %H:%M:%S'\'') - $1" | tee -a "$LOG_FILE"
}

echo "=== Обновление DNS записи в AD ==="

# --- Определение DNS сервера ---
DNS_SERVER=$(resolvectl dns | grep -oE '\''\b([0-9]{1,3}\.){3}[0-9]{1,3}\b'\'' | head -1)

if [[ -z "$DNS_SERVER" ]]; then
    DNS_SERVER=$(grep '\''^nameserver'\'' /etc/resolv.conf 2>/dev/null | awk '\''{print $2}'\'' | head -1)
fi

if [[ -z "$DNS_SERVER" ]]; then
    echo "Не удалось определить DNS сервер."
    exit 1
fi

# --- Имя хоста ---
HOSTNAME_FQDN=$(hostname -f)
HOSTNAME_SHORT=$(hostname -s)
IP_ADDR=$(hostname -I | awk '\''{print $1}'\'')

log ""
log "=== Старт обновления DNS ==="
log "Домен: $DOMAIN"
log "DNS сервер: $DNS_SERVER"
log "FQDN: $HOSTNAME_FQDN"
log "IP: $IP_ADDR"
log "============================"

# --- Автоматическое исправление FQDN ---
if [[ ! "$HOSTNAME_FQDN" == *".$DOMAIN" ]]; then
    log "WARNING: Имя хоста $HOSTNAME_FQDN не входит в домен $DOMAIN"
    log "Автоматически устанавливаем FQDN: $HOSTNAME_SHORT.$DOMAIN"
    sudo hostnamectl set-hostname "$HOSTNAME_SHORT.$DOMAIN"
    
    HOSTNAME_FQDN="$HOSTNAME_SHORT.$DOMAIN"
    log "Новый FQDN: $HOSTNAME_FQDN"
    
    echo "Имя хоста изменено на $HOSTNAME_FQDN"
    echo "Рекомендуется перезагрузить сервер: sudo reboot"
fi

# --- Получение Kerberos ticket через keytab ---
log "Получаем Kerberos ticket через keytab..."

PRINCIPAL=$(klist -k /etc/krb5.keytab 2>/dev/null | grep '\''\$@'\'' | head -1 | awk '\''{print $2}'\'')

if [[ -z "$PRINCIPAL" ]]; then
    log "ERROR: Не найден principal машинной учётной записи в /etc/krb5.keytab"
    exit 1
fi

log "Найден principal: $PRINCIPAL"

if kinit -k -t /etc/krb5.keytab "$PRINCIPAL" 2>/dev/null; then
    log "SUCCESS: Kerberos ticket получен"
else
    log "ERROR: Не удалось получить Kerberos ticket"
    exit 1
fi

# --- Определение обратной зоны для PTR ---
TMP_FILE="/tmp/dns-update-$$.txt"

IFS=. read -r o1 o2 o3 o4 <<< "$IP_ADDR"

if [[ -n "$o1" && -n "$o2" && -n "$o3" && -n "$o4" ]]; then
    REVERSE_ZONE="$o3.$o2.$o1.in-addr.arpa"
    REVERSE_PTR="$o4.$o3.$o2.$o1.in-addr.arpa"
    log "Обратная зона: $REVERSE_ZONE"
    log "PTR запись: $REVERSE_PTR -> $HOSTNAME_FQDN"
fi

# --- Формируем команды для nsupdate ---
cat > "$TMP_FILE" <<EOF
server $DNS_SERVER
zone $DOMAIN.
update delete $HOSTNAME_FQDN. A
update add $HOSTNAME_FQDN. 3600 A $IP_ADDR
send
EOF

# Добавляем PTR если зона определена
if [[ -n "$REVERSE_ZONE" && -n "$REVERSE_PTR" ]]; then
    cat >> "$TMP_FILE" <<EOF
zone $REVERSE_ZONE.
update delete $REVERSE_PTR. PTR
update add $REVERSE_PTR. 3600 PTR $HOSTNAME_FQDN.
send
EOF
fi

log "Запускаем nsupdate..."

# --- Обновление DNS ---
if nsupdate -g "$TMP_FILE" >> "$LOG_FILE" 2>&1; then
    log "SUCCESS: DNS A запись обновлена: $HOSTNAME_FQDN -> $IP_ADDR"
    if [[ -n "$REVERSE_ZONE" ]]; then
        log "SUCCESS: DNS PTR запись обновлена: $REVERSE_PTR -> $HOSTNAME_FQDN"
    fi
    rm -f "$TMP_FILE"
    sudo kdestroy
    exit 0
else
    log "ERROR: Ошибка обновления DNS"
    echo "=== Содержимое TMP_FILE ===" >> "$LOG_FILE"
    cat "$TMP_FILE" >> "$LOG_FILE"
    rm -f "$TMP_FILE"
    kdestroy
    exit 1
fi
'

# ==========================================
# ФУНКЦИЯ ДОБАВЛЕНИЯ В ДОМЕН
# ==========================================
join_domain() {
    echo ""
    title
    echo -e "${WHITE}       Добавление сервера в домен AD${NC}"
    title
    echo ""
    
    # Проверяем, уже ли в домене
    if realm list 2>/dev/null | grep -q "$DOMAIN"; then
        warn "Сервер уже в домене $DOMAIN"
        info "Пропускаем добавление в домен"
        return 0
    fi
    
    # Запрос параметров домена
    echo ""
    info "Введите параметры домена:"
    echo ""
    
    read -p "  Имя домена (по-умолчанию: nvi-solutions.ru): " INPUT_DOMAIN
    if [[ -n "$INPUT_DOMAIN" ]]; then
        DOMAIN="$INPUT_DOMAIN"
    else
        DOMAIN="nvi-solutions.ru"
    fi
    
    read -p "  Имя пользователя AD (например: ivan.ivanov): " USERNAME
    while [[ -z "$USERNAME" ]]; do
        error "Имя пользователя не может быть пустым"
        read -p "  Имя пользователя AD: " USERNAME
    done
    
    read -s -p "  Пароль пользователя: " PASSWORD
    echo ""
    while [[ -z "$PASSWORD" ]]; do
        error "Пароль не может быть пустым"
        read -s -p "  Пароль пользователя: " PASSWORD
        echo ""
    done
    
    # Верхний регистр для REALM
    REALM=$(echo "$DOMAIN" | tr '[:lower:]' '[:upper:]')
    
    echo ""
    info "Домен: $DOMAIN"
    info "Realm: $REALM"
    info "Пользователь: $USERNAME"
    echo ""
    
    # # Установка пакетов для входа в домен
    # info "Установка необходимых пакетов..."
    # apt update
    # apt -y install realmd sssd sssd-tools libnss-sss libpam-sss adcli \
    #     samba-common-bin oddjob oddjob-mkhomedir packagekit
    
    # Вход в домен
    info "Вход в домен $DOMAIN..."
    echo "$PASSWORD" | realm join "$DOMAIN" --user="$USERNAME" --automatic-id-mapping=no
    
    if [ $? -ne 0 ]; then
        error "Не удалось войти в домен. Проверьте параметры и сетевое подключение."
        return 1
    fi
    
    success "Успешно вошли в домен $DOMAIN"
    
    HOSTNAME_SHORT=$(hostname -s)

    # Настройка pam_mkhomedir
    info "Настройка автоматического создания домашних директорий..."
    cat > /usr/share/pam-configs/mkhomedir <<EOF
Name: activate mkhomedir
Default: yes
Priority: 900
Session-Type: Additional
Session:
required pam_mkhomedir.so umask=0022 skel=/etc/skel
EOF
    
    pam-auth-update --enable mkhomedir --force
    
    # Создание конфигурации SSSD
    info "Настройка SSSD..."
    cat > /etc/sssd/sssd.conf <<EOF
[sssd]
domains = $DOMAIN
config_file_version = 2
services = nss, pam

[domain/$DOMAIN]
default_shell = /bin/bash
cache_credentials = True
krb5_realm = $REALM
realmd_tags = manages-system joined-with-adcli
id_provider = ad
fallback_homedir = /home/%u
ad_domain = $DOMAIN
use_fully_qualified_names = False
ldap_id_mapping = True
access_provider = simple
dyndns_update = false
EOF
    
    chmod 600 /etc/sssd/sssd.conf
    # systemctl restart sssd
    
    # Разрешение входа для группы Domain Admins
    info "Разрешение входа для группы Domain Admins..."
    realm permit -g 'Domain Admins' 2>/dev/null || true
    
    # Разрешение входа для группы Domain Admins
    info "Разрешение входа для группы $HOSTNAME_SHORT Admins..."
    realm permit -g "$HOSTNAME_SHORT Admins" 2>/dev/null || true

    # Разрешение входа для группы Domain Admins
    info "Разрешение входа для группы $HOSTNAME_SHORT Users..."
    realm permit -g "$HOSTNAME_SHORT Users" 2>/dev/null || true    

    # Добавление Domain Admins в sudoers
    info "Добавление Domain Admins в sudoers..."
    cat > /etc/sudoers.d/domain_admins <<EOF
%domain\ admins ALL=(ALL) ALL
EOF

    # Добавление Domain Admins в sudoers
    info "Добавление $HOSTNAME_SHORT Admins в sudoers..."
    cat > /etc/sudoers.d/"$HOSTNAME_SHORT"_admins <<EOF
%$HOSTNAME_SHORT\ admins ALL=(ALL) ALL
EOF

    info "Перезапуск SSSD"
    # sleep 3 
    systemctl restart sssd
    
    echo ""
    success "Настройка домена завершена!"
    echo ""
    info "Проверка:"
    echo "  - Статус: sudo realm list"
    echo "  - Тест входа: ssh $USERNAME@localhost"
    echo "  - Права sudo: sudo -l"
    echo ""
    
    return 0
}

# ==========================================
# ФУНКЦИИ УСТАНОВЩИКА DNS АВТООБНОВЛЕНИЯ
# ==========================================

# Определение активного сетевого менеджера
detect_network_manager() {
    info "Определение активного сетевого менеджера..."
    
    if systemctl is-active --quiet NetworkManager 2>/dev/null; then
        NETWORK_MANAGER="NetworkManager"
        success "Активен: NetworkManager"
        return 0
    fi
    
    if systemctl is-active --quiet systemd-networkd 2>/dev/null; then
        NETWORK_MANAGER="systemd-networkd"
        success "Активен: systemd-networkd"
        return 0
    fi
    
    if systemctl is-active --quiet networking 2>/dev/null; then
        NETWORK_MANAGER="ifupdown"
        success "Активен: ifupdown"
        return 0
    fi
    
    NETWORK_MANAGER="unknown"
    warn "Не удалось определить активный сетевой менеджер"
    return 1
}

# Установка зависимостей
install_dependencies() {
    info "Проверка зависимостей..."
    
    local deps=("krb5-user" "bind9utils" "realmd" "sssd" "sssd-tools" "libnss-sss" "libpam-sss" "adcli"
        "samba-common-bin" "oddjob" "oddjob-mkhomedir" "packagekit")
    local missing=()
    
    for dep in "${deps[@]}"; do
        if ! dpkg -l | grep -q "^ii.*$dep"; then
            missing+=("$dep")
        fi
    done
    
    if [ ${#missing[@]} -gt 0 ]; then
        info "Установка пакетов: ${missing[*]}"
        apt update
        apt install -y "${missing[@]}"
        success "Зависимости установлены"
    else
        success "Все зависимости уже установлены"
    fi
}

# Установка основного скрипта
install_main_script() {
    info "Установка основного скрипта dns-update.sh..."
    
    # Создаём резервную копию если скрипт уже существует
    if [ -f /usr/local/bin/dns-update.sh ]; then
        warn "Скрипт уже существует. Создаю резервную копию..."
        cp /usr/local/bin/dns-update.sh /usr/local/bin/dns-update.sh.bak.$(date +%Y%m%d_%H%M%S)
        success "Резервная копия создана"
    fi
    
    # Записываем содержимое скрипта
    echo "$MAIN_SCRIPT_CONTENT" | sudo tee /usr/local/bin/dns-update.sh > /dev/null
    chmod +x /usr/local/bin/dns-update.sh
    
    success "Основной скрипт установлен: /usr/local/bin/dns-update.sh"
}

# Создание лог-файла
setup_log() {
    if [ ! -f /var/log/dns-update.log ]; then
        touch /var/log/dns-update.log
        chmod 666 /var/log/dns-update.log
        success "Лог-файл создан: /var/log/dns-update.log"
    else
        success "Лог-файл уже существует: /var/log/dns-update.log"
    fi
}

# Настройка для NetworkManager
setup_networkmanager() {
    info "Настройка для NetworkManager..."
    
    sudo tee /etc/NetworkManager/dispatcher.d/50-dns-update > /dev/null << 'EOF'
#!/bin/bash
INTERFACE=$1
EVENT=$2

if [ "$EVENT" == "up" ] || [ "$EVENT" == "dhcp4-change" ]; then
    /usr/local/bin/dns-update.sh &
fi
exit 0
EOF
    
    chmod +x /etc/NetworkManager/dispatcher.d/50-dns-update
    systemctl restart NetworkManager
    
    success "NetworkManager настроен"
}

# Настройка для systemd-networkd
setup_systemd_networkd() {
    info "Настройка для systemd-networkd..."
    
    if ! command -v networkd-dispatcher &>/dev/null; then
        info "Установка networkd-dispatcher..."
        apt update && apt install -y networkd-dispatcher
    fi
    
    mkdir -p /etc/networkd-dispatcher/routable.d
    
    tee /etc/networkd-dispatcher/routable.d/50-dns-update > /dev/null << 'EOF'
#!/bin/bash
/usr/local/bin/dns-update.sh &
exit 0
EOF
    
    chmod 755 /etc/networkd-dispatcher/routable.d/50-dns-update
    systemctl restart networkd-dispatcher
    
    success "systemd-networkd настроен"
}

# Настройка для ifupdown
setup_ifupdown() {
    info "Настройка для ifupdown..."
    
    mkdir -p /etc/dhcp/dhclient-exit-hooks.d
    
    tee /etc/dhcp/dhclient-exit-hooks.d/dns-update > /dev/null << 'EOF'
#!/bin/bash
case "$reason" in
    BOUND|RENEW|REBIND|REBOOT)
        /usr/local/bin/dns-update.sh &
        ;;
esac
EOF
    
    chmod +x /etc/dhcp/dhclient-exit-hooks.d/dns-update
    systemctl restart networking 2>/dev/null || /etc/init.d/networking restart
    
    success "ifupdown настроен"
}

# Настройка cron
setup_cron() {
    info "Настройка периодического запуска через cron..."
    
    CRON_JOB="*/30 * * * * /usr/local/bin/dns-update.sh"
    
    if crontab -l 2>/dev/null | grep -q "dns-update.sh"; then
        warn "Задача в cron уже существует"
    else
        (crontab -l 2>/dev/null; echo "$CRON_JOB") | crontab -
        success "Задача добавлена в cron (каждые 30 минут)"
    fi
}


# Проверка keytab
check_keytab() {
    info "Проверка keytab файла..."
    
    if [ -f /etc/krb5.keytab ]; then
        success "Keytab файл найден: /etc/krb5.keytab"
        PRINCIPAL=$(klist -k /etc/krb5.keytab 2>/dev/null | grep '\$@' | head -1 | awk '{print $2}')
        if [ -n "$PRINCIPAL" ]; then
            success "Найден principal: $PRINCIPAL"
        else
            warn "Не найден principal машинной учётной записи"
            warn "Убедитесь, что сервер введён в домен: sudo realm list"
        fi
    else
        warn "Keytab файл не найден: /etc/krb5.keytab"
        warn "Убедитесь, что сервер введён в домен"
    fi
}

# ==========================================
# ОСНОВНАЯ ФУНКЦИЯ
# ==========================================
main() {
    echo ""
    title
    echo -e "${WHITE}  Добавление в домен и автообновление DNS для AD${NC}"
    title
    echo ""
    
    if [ "$EUID" -ne 0 ]; then
        error "Пожалуйста, запустите скрипт с sudo:"
        echo "  sudo $0"
        exit 1
    fi

    info "ШАГ 0: Установка зависимостей"
    install_dependencies

    # ШАГ 1: Ввод в домен
    info "ШАГ 1: Ввод хоста в домен Active Directory"
    join_domain
    
    if [ $? -ne 0 ]; then
        error "Не удалось ввести хост в домен. Установка прервана."
        exit 1
    fi
    
    # ШАГ 2: Настройка DNS автообновления
    echo ""
    title
    echo -e "${WHITE}  ШАГ 2: Настройка автообновления DNS${NC}"
    title
    echo ""
    
    info "Настройка автоматического обновления DNS..."
    
    detect_network_manager
    install_main_script
    setup_log
    setup_cron
    
    # Настройка в зависимости от сетевого менеджера
    case "$NETWORK_MANAGER" in
        NetworkManager)
            setup_networkmanager
            ;;
        systemd-networkd)
            setup_systemd_networkd
            ;;
        ifupdown)
            setup_ifupdown
            ;;
        *)
            warn "Неизвестный сетевой менеджер. Настройка только через cron и systemd"
            ;;
    esac
    
    check_keytab
    
    echo ""
    title
    success "Установка завершена!"
    title
    echo ""
    echo "Установленные компоненты:"
    echo "  - Основной скрипт: /usr/local/bin/dns-update.sh"
    echo "  - Лог-файл: /var/log/dns-update.log"
    echo "  - Systemd сервис: dns-update.service"
    echo "  - Cron: каждые 30 минут"
    echo "  - Сетевой менеджер: $NETWORK_MANAGER"
    echo ""
    echo "Проверка работы:"
    echo "  sudo /usr/local/bin/dns-update.sh"
    echo "  tail -f /var/log/dns-update.log"
    echo ""
    
    title
    info "Запуск обновления DNS"
    title
    /usr/local/bin/dns-update.sh
}

main "$@"
