#!/bin/bash

#####################################################################
####### Script instalador Ogclient
####### Autor: Luis Gerardo Romero <lguillen@unizar.es>
#####################################################################

function globalSetup() {
    local current_dir
    current_dir=$(dirname "$0")
    PROGRAMDIR=$(readlink -e "$current_dir")
    PROGRAMNAME=$(basename "$0")
    OPENGNSYS_CLIENT_USER="ogdhcp"

    # Comprobar si se ha descargado el paquete comprimido (REMOTE=0) o sólo el instalador (REMOTE=1).
    if [ -d "$PROGRAMDIR/../installer" ]; then
        echo "REMOTE=0"
        REMOTE=0
    else
        echo "REMOTE=1"
        REMOTE=1
    fi

    BRANCH=${1:-"main"}

    GIT_REPO="ssh://git@ognproject.evlt.uma.es:21987/opengnsys/ogdhcp.git"

    # Directorios de instalación y destino de OpenGnsys.
    WORKDIR=/tmp/ogdhcp_installer
    INSTALL_TARGET=/opt/ogdhcp
    PATH=$PATH:$INSTALL_TARGET/bin

    if command -v service &>/dev/null; then
        STARTSERVICE="eval service \$service restart"
        STOPSERVICE="eval service \$service stop"
    else
        STARTSERVICE="eval /etc/init.d/\$service restart"
        STOPSERVICE="eval /etc/init.d/\$service stop"
    fi

    ENABLESERVICE="eval update-rc.d \$service defaults"
    DISABLESERVICE="eval update-rc.d \$service disable"

    APACHESERV=apache2
    APACHECFGDIR=/etc/apache2
    APACHESITESDIR=sites-available
    APACHEOGSITE=ogdhcp
    APACHEUSER="www-data"
    APACHEGROUP="www-data"
    APACHEENABLEMODS="a2enmod headers ssl rewrite proxy_fcgi fastcgi actions alias"
    APACHEENABLESSL="a2ensite default-ssl"
    APACHEENABLEOG="a2ensite $APACHEENABLEOG"
    APACHEMAKECERT="make-ssl-cert generate-default-snakeoil --force-overwrite"

    PHPFPMSERV=php7.2-fpm

    # Registro de incidencias.
    OGLOGFILE="$INSTALL_TARGET/var/log/${PROGRAMNAME%.sh}.log"
    LOG_FILE="/tmp/$(basename "$OGLOGFILE")"
}


function checkDependencies() {
    echoAndLog "Checking dependencies..."

    # Lista de dependencias
    local DEPENDENCIES=(
        php
        php-cli
        php-fpm
        php-json
        php-pdo
        php-mysql
        php-zip
        php-gd
        php-mbstring
        php-curl
        php-xml
        php-pear
        php-bcmath
        composer
        unzip
        apache2
        libapache2-mod-php
        kea-dhcp4-server
        kea-common
        kea-ctrl-agent
        jq
        net-tools
        
    )

    # Comprobar cada dependencia
    for dep in "${DEPENDENCIES[@]}"; do
        if ! dpkg -s "$dep" >/dev/null 2>&1; then
            echoAndLog "$dep is not installed. Installing..."
            sudo apt-get install -y "$dep"
        else
            echoAndLog "$dep is already installed."
        fi
    done

    echoAndLog "Dependencies checked."
}

# Función para instalar los paquetes necesarios para KEA-DHCP
install_kea() {
    sudo apt-get install -y isc-kea-common isc-kea-ctrl-agent isc-kea-dhcp4-server isc-kea-dhcp6-server isc-kea-admin
}

# Función para instalar Composer
install_composer() {
    curl -sS https://getcomposer.org/installer | php
    sudo mv composer.phar /usr/local/bin/composer
}

# Función para instalar Swagger UI
install_swagger() {
    sudo apt-get install -y unzip
    wget https://github.com/swagger-api/swagger-ui/archive/master.zip
    unzip master.zip -d /var/www/html/
    sudo mv /var/www/html/swagger-ui-master /var/www/html/swagger-ui
}

# Obtiene el código fuente del proyecto desde el repositorio de GitHub.
function downloadCode() {
    if [ $# -ne 1 ]; then
        errorAndLog "${FUNCNAME}(): invalid number of parameters"
        exit 1
    fi

    local url="$1"

    echoAndLog "${FUNCNAME}(): downloading code from '$url'..."

    GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=accept-new" git archive --remote="$url" --format zip --output opengnsys.zip --prefix=opengnsys/ "$BRANCH" && unzip opengnsys.zip
    if [ $? -ne 0 ]; then
        errorAndLog "${FUNCNAME}(): error getting OpenGnsys code from $url"
        return 1
    fi
    rm -f opengnsys.zip
    echoAndLog "${FUNCNAME}(): code was downloaded"
    return 0
}

# Crea la estructura base de la instalación de opengnsys
function createDirs() {
    if [ $# -ne 1 ]; then
        errorAndLog "${FUNCNAME}(): invalid number of parameters"
        exit 1
    fi

    local path_opengnsys_base="$1"

    # Crear estructura de directorios.
    echoAndLog "${FUNCNAME}(): creating directory paths in $path_opengnsys_base"
    mkdir -p "$path_opengnsys_base"/{bin,config,docs,public,src,etc/kea/backup,templates,var/{cache,log},vendor}
    if [ $? -ne 0 ]; then
        errorAndLog "${FUNCNAME}(): error while creating dirs. Do you have write permissions?"
        return 1
    fi

    # Crear usuario ficticio.
    if id -u "$OPENGNSYS_CLIENT_USER" &>/dev/null; then
        echoAndLog "${FUNCNAME}(): user \"$OPENGNSYS_CLIENT_USER\" is already created"
    else
        echoAndLog "${FUNCNAME}(): creating OpenGnsys user"
        useradd "$OPENGNSYS_CLIENT_USER" 2>/dev/null
        if [ $? -ne 0 ]; then
            errorAndLog "${FUNCNAME}(): error creating OpenGnsys user"
            return 1
        fi
    fi

    # Mover el fichero de registro de instalación al directorio de logs.
    echoAndLog "${FUNCNAME}(): moving installation log file"
    mv "$LOG_FILE" "$path_opengnsys_base/var/log" && LOG_FILE="$OGLOGFILE"
    chmod 777 "$LOG_FILE"
    sudo chmod -R 777 "$path_opengnsys_base/etc"

    # Mover el fichero de registro de instalación al directorio de logs.
    echoAndLog "${FUNCNAME}(): moving installation log file"
    touch "$path_opengnsys_base/var/log/dev.log"
    chmod 777 "$path_opengnsys_base/var/log/dev.log"

    echoAndLog "${FUNCNAME}(): directory paths created"
    return 0

    # Cambiar permisos de usuario
    echoAndLog "Changing user permission"
    chown -R "$OPENGNSYS_CLIENT_USER:$OPENGNSYS_CLIENT_USER" "$INSTALL_TARGET"

    # Copiar .env
    cp -a "$WORKDIR/ogdhcp/.env" "${path_opengnsys_base}/.env"
}

function create_ogdhcp_project {
    # Cambia al usuario ogdhcp y crea el proyecto Symfony
    local path_opengnsys_base="$1"
    composer create-project symfony/website-skeleton "$path_opengnsys_base"
    pushd "$path_opengnsys_base" || return
    # Elimina el archivo composer.lock
    rm composer.lock
    popd || return
    echoAndLog "Esqueleto de la aplicación creado y archivo composer.lock eliminado."
}


function copyServerFiles() {
    if [ $# -ne 1 ]; then
        errorAndLog "${FUNCNAME}(): invalid number of parameters"
        exit 1
    fi

    local path_opengnsys_base="$1"

    # Lista de ficheros y directorios origen y de directorios destino.
    local SOURCES=(
        config
        #public
        src
        etc
        templates
        tests
        vendor
        .env
        composer.json
        composer.lock
        phpunit.xml.dist
        symfony.lock
    )
    local TARGETS=(
        config
        #public
        src
        etc
        templates
        tests
        vendor
        .env
        composer.json
        composer.lock
        phpunit.xml.dist
        symfony.lock
    )

    if [ "${#SOURCES[@]}" != "${#TARGETS[@]}" ]; then
        errorAndLog "${FUNCNAME}(): inconsistent number of array items"
        exit 1
    fi

    # Copiar ficheros.
    echoAndLog "${FUNCNAME}(): copying files to server directories"

    pushd "$WORKDIR/ogdhcp" || return
    local i
    for (( i = 0; i < ${#SOURCES[@]}; i++ )); do
        if [ -f "${SOURCES[$i]}" ]; then
            echoAndLog "Copying ${SOURCES[$i]} to $path_opengnsys_base/${TARGETS[$i]}"
            cp -a "${SOURCES[$i]}" "$path_opengnsys_base/${TARGETS[$i]}"
        elif [ -d "${SOURCES[$i]}" ]; then
            echoAndLog "Copying content of ${SOURCES[$i]} to $path_opengnsys_base/${TARGETS[$i]}"
            cp -a "${SOURCES[$i]}"/* "$path_opengnsys_base/${TARGETS[$i]}"
        else
            warningAndLog "Unable to copy ${SOURCES[$i]} to $path_opengnsys_base/${TARGETS[$i]}"
        fi
    done
    echoAndLog "Changing user permission"
    chown -R "$OPENGNSYS_CLIENT_USER:$OPENGNSYS_CLIENT_USER" "$INSTALL_TARGET"

    popd || return
}

function downloadComposer() {
    echoAndLog "Downloading composer.phar..."

    # Crear el directorio de trabajo si no existe
    mkdir -p "$WORKDIR/ogdhcp/bin" || return

    # Cambiar al directorio de trabajo
    pushd "$WORKDIR/ogdhcp/bin" || return

    # Descargar composer.phar
    curl -sS https://getcomposer.org/installer | php

    # Comprobar si la descarga fue exitosa
    if [ ! -f composer.phar ]; then
        errorAndLog "Failed to download composer.phar"
        popd
        return 1
    fi

    # Crear el directorio de destino si no existe
    mkdir -p "/opt/ogdhcp/bin" || return

    # Mover composer.phar a /opt/ogdhcp/bin
    mv composer.phar "/opt/ogdhcp/bin/"

    # Comprobar si el movimiento fue exitoso
    if [ ! -f "/opt/ogdhcp/bin/composer.phar" ]; then
        errorAndLog "Failed to move composer.phar to /opt/ogdhcp/bin"
        popd
        return 1
    fi

    # Volver al directorio original
    popd || return

    echoAndLog "composer.phar downloaded and moved to /opt/ogdhcp/bin"
    return 0
}

function runComposer() {
    echoAndLog "Running composer.phar to install dependencies..."

    # Cambiar al directorio donde está composer.phar
    pushd /opt/ogdhcp/bin || return

    # Ejecutar composer.phar
    sudo -u "$OPENGNSYS_CLIENT_USER" php composer.phar install

    # Comprobar si la ejecución fue exitosa
    if [ $? -ne 0 ]; then
        errorAndLog "Failed to run composer.phar"
        popd
        return 1
    fi

    # Volver al directorio original
    popd || return

    echoAndLog "composer.phar ran successfully and dependencies were installed"
    return 0
}

function install_swagger_ui {
    # Define la URL del archivo de Swagger UI que quieres descargar
    swagger_ui_url="https://github.com/swagger-api/swagger-ui/archive/refs/heads/master.zip"

    # Define la ruta donde quieres descomprimir Swagger UI
    swagger_ui_path="/tmp/swagger-ui"

    # Define la ruta de destino para los archivos de Swagger UI
    destination_path="/opt/ogdhcp/public"

    # Crea los directorios si no existen
    mkdir -p "$swagger_ui_path"
    mkdir -p "$destination_path"

    # Descarga el archivo de Swagger UI
    wget "$swagger_ui_url" -O /tmp/swagger-ui.zip

    # Descomprime el archivo de Swagger UI en la ruta especificada
    unzip /tmp/swagger-ui.zip -d "$swagger_ui_path"

    # Copia los archivos de Swagger UI al directorio de destino
    cp -r "$swagger_ui_path"/swagger-ui-master/dist/* "$destination_path"

    # Elimina el archivo descargado y el directorio temporal
    rm /tmp/swagger-ui.zip
    rm -r "$swagger_ui_path"
    /opt/ogdhcp/vendor/bin/openapi /opt/ogdhcp/src/DhcpBundle/Controller/ -o "$destination_path/swagger.json"
    echo "Swagger UI instalado en $destination_path."
}

function installWebConsoleApacheConf() {
    if [ $# -ne 2 ]; then
        errorAndLog "${FUNCNAME}(): invalid number of parameters"
        exit 1
    fi

    local path_opengnsys_base="$1"
    local path_apache2_confd="$2"
    local OGHDPCDIR="${path_opengnsys_base}/public"
    local sockfile

    if [ ! -d "$path_apache2_confd" ]; then
        errorAndLog "${FUNCNAME}(): path to apache2 conf.d can not found, verify your server installation"
        return 1
    fi

    mkdir -p "$path_apache2_confd/{sites-available,sites-enabled}"

    echoAndLog "${FUNCNAME}(): creating apache2 config file.."

    # Activar PHP-FPM.
    echoAndLog "${FUNCNAME}(): configuring PHP-FPM"
    service="$PHPFPMSERV"
    $ENABLESERVICE; $STARTSERVICE
    sockfile=$(find /run/php -name "php*.sock" -type s -print 2>/dev/null | tail -1)

    # Activar módulos de Apache.
    $APACHEENABLEMODS

    # Generar configuración de consola web a partir del archivo de plantilla.
    if [ -n "$sockfile" ]; then
        sed -e "s,OGHDPCDIR,$OGHDPCDIR,g" \
            -e "s,proxy:fcgi:.*,proxy:unix:${sockfile%% *}|fcgi://localhost\",g" \
            "$WORKDIR/ogdhcp/etc/apache.conf.tmpl" > "$path_apache2_confd/$APACHESITESDIR/${APACHEOGSITE}.conf"
    else
        sed -e "s,OGHDPCDIR,$OGHDPCDIR,g" \
            "$WORKDIR/ogdhcp/server/etc/apache.conf.tmpl" > "$path_apache2_confd/$APACHESITESDIR/${APACHEOGSITE}.conf"
    fi
    $APACHEENABLEOG
    if [ $? -ne 0 ]; then
        errorAndLog "${FUNCNAME}(): config file can't be linked to apache conf, verify your server installation"
        return 1
    fi
    echoAndLog "${FUNCNAME}(): config file created and linked, restarting apache daemon"
    service="$APACHESERV"
    $ENABLESERVICE; $STARTSERVICE
    return 0
}

#####################################################################
####### Algunas funciones útiles de propósito general:
#####################################################################

# Obtiene la fecha y hora actual en el formato especificado
function getDateTime() {
    date "+%Y%m%d-%H%M%S"
}

# Escribe un mensaje en el archivo de registro y lo muestra por pantalla
function echoAndLog() {
    local DATETIME=$(getDateTime)
    echo "$1"
    echo "$DATETIME;$SSH_CLIENT;$1" >> "$LOG_FILE"
}

# Escribe un mensaje de error en el archivo de registro y lo muestra por pantalla
function errorAndLog() {
    local DATETIME=$(getDateTime)
    echo "ERROR: $1"
    echo "$DATETIME;$SSH_CLIENT;ERROR: $1" >> "$LOG_FILE"
}

# Escribe un mensaje de advertencia en el archivo de registro y lo muestra por pantalla
function warningAndLog() {
    local DATETIME=$(getDateTime)
    echo "Warning: $1"
    echo "$DATETIME;$SSH_CLIENT;Warning: $1" >> "$LOG_FILE"
}

##########################################################################
################################main######################################

# Sólo ejecutable por usuario root
if [ "$(whoami)" != 'root' ]; then
		echo "ERROR: this program must run under root privileges!!"
		exit 1
fi

globalSetup

echoAndLog "OpenGnsys installation begins at $(date)"

mkdir -p $WORKDIR
pushd $WORKDIR

checkDependencies
install_kea
# Si es necesario, descarga el repositorio de código en directorio temporal
if [ $REMOTE -eq 1 ]; then
	downloadCode $GIT_REPO
	if [ $? -ne 0 ]; then
		errorAndLog "Error while getting code from the repository"
		exit 1
	fi
else
	ln -fs "$(dirname $PROGRAMDIR)" ogdhcp
fi

create_ogdhcp_project ${INSTALL_TARGET}
if [ $? -ne 0 ]; then
        errorAndLog "Error while creating skeleton directory!"
        exit 1
fi

# Arbol de directorios de OpenGnsys.
createDirs ${INSTALL_TARGET}
if [ $? -ne 0 ]; then
	errorAndLog "Error while creating directory paths!"
	exit 1
fi


# Copiar ficheros de servicios OpenGnsys Server.
copyServerFiles ${INSTALL_TARGET}
if [ $? -ne 0 ]; then
	errorAndLog "Error while copying the server files!"
	exit 1
fi

downloadComposer

runComposer
install_swagger_ui
# Creando configuración de Apache.
installWebConsoleApacheConf $INSTALL_TARGET $APACHECFGDIR
if [ $? -ne 0 ]; then
	errorAndLog "Error configuring Apache for OpenGnsys Admin"
	exit 1
fi

sudo apt-get update
# install_kea
# install_php
# install_composer
# install_symfony
# install_swagger
# Ahora puedes clonar e instalar el componente ogDhcp
# git clone <URL del repositorio de ogDhcp>
# cd <directorio de ogDhcp>
# composer install