#!/bin/bash -e

PROGRAM_NAME=`basename $0`
SDK_VERSION=36
QT_VERSION=6.10.1

display_help () {
    echo "Usage: $PROGRAM_NAME [options] [command]"
    echo ""
    echo "Available commands:"
    echo "    help                        Display this help."
    echo "    delete                      Delete a container."
    echo "    shell                       Enter a container."
    echo "    clean                       Clean the build dir."
    echo ""
    echo "Options:"
    echo "    --help, -h                  Display this help."
    echo "    --mount-ssh                 Mount ~/.ssh from host into the container"
    echo "    --sdk=<version>             Build using the given android SDK version. It has to be installed in the image. Default is $SDK_VERSION."
    echo "    --qt=<version>              Build using the given Qt version. It has to be installed in the image. Default is $QT_VERSION."
    echo "    --sign=, -s=<keystore>      Sign it with the given keystore"
    echo "    --cert-alias=, -c=<alias>   Use the certificate alias for the keytore"
    echo "    --keypass=, -k=<pass>       Provide a password to open the keystore given with --sign"
}

variables() {
    RED='\033[0;31m'
    GREEN='\033[0;32m'
    LIGHT_RED='\033[1;31m'
    LIGHT_GREEN='\033[1;32m'
    NC='\033[0m'
    ERROR_COLOR=$LIGHT_RED
    POSITIVE_COLOR=$GREEN

    USERNAME=`id --user --name`
    GROUPNAME=$USERNAME
    USERID=150000
    GROUPID=150000

    PACKAGE=`basename "$PWD"`

    LXD_IMAGE_NAME=android-qt6-builder
    LXD_IMAGE=$LXD_IMAGE_NAME
  
    LXD_CONTAINER=builder-$CONTAINER_PREFIX$LXD_IMAGE_NAME
    USERDIR=/home/$USERNAME
    MOUNTED_DIRECTORY=$PWD
    MOUNT_POINT=$USERDIR/$PACKAGE
    SOURCE_PATH_CONTAINER=$MOUNT_POINT

}

new_container() {
    if lxc info $LXD_CONTAINER > /dev/null 2>&1 ; then
        echo "${POSITIVE_COLOR}LXD container $LXD_CONTAINER already exists.${NC}"
        # FIXME: check if the container is already started
        lxc start $LXD_CONTAINER || true
    else
        echo "${POSITIVE_COLOR}Creating LXD container $LXD_CONTAINER using $LXD_IMAGE.${NC}"
        lxc remote --public=true --accept-certificate=true add nymea https://jenkins.nymea.io || true
        lxc init nymea:$LXD_IMAGE $LXD_CONTAINER

        # Note: check the lxc version for lxc.id_map vs lxc.idmap
        LXCVERSION=$(lxc --version)
        LXCMAJORVERSION=$(echo ${LXCVERSION} | cut -d. -f1)
        if [ "${LXCMAJORVERSION}" -lt "3" ]; then
            echo "${POSITIVE_COLOR}Using lxc version 2 compatibility$LXD_IMAGE.${NC}"
            printf "lxc.id_map = g $GROUPID `id --group` 1\nlxc.id_map = u $USERID `id --user` 1" | lxc config set $LXD_CONTAINER raw.lxc -
        else
            printf "uid `id --user` 150000\ngid `id --group` 150000" | lxc config set $LXD_CONTAINER raw.idmap -

#            echo "Mapping uids: lxc.idmap = g $GROUPID `id --group` 1\nlxc.idmap = u $USERID `id --user` 1"
#            printf "lxc.idmap = g `id --group` 1\nlxc.idmap = u $USERID `id --user` 1" | lxc config set $LXD_CONTAINER raw.lxc -
        fi


        lxc start $LXD_CONTAINER
        lxc exec --env GROUPID=$GROUPID --env GROUPNAME=$GROUPNAME $LXD_CONTAINER -- deluser $USERNAME || true
        lxc exec --env GROUPID=$GROUPID --env GROUPNAME=$GROUPNAME $LXD_CONTAINER -- deluser ubuntu || true
        lxc exec --env GROUPID=$GROUPID --env GROUPNAME=$GROUPNAME $LXD_CONTAINER -- delgroup $GROUPNAME || true
        lxc exec $LXD_CONTAINER -- rm -rf /home/ubuntu
        lxc exec --env GROUPID=$GROUPID --env GROUPNAME=$GROUPNAME $LXD_CONTAINER -- addgroup --gid $GROUPID $GROUPNAME
        lxc exec --env GROUPID=$GROUPID --env USERNAME=$USERNAME --env USERID=$USERID $LXD_CONTAINER -- adduser --disabled-password --gecos "" --uid $USERID --gid $GROUPID $USERNAME
        lxc exec --env USERNAME=$USERNAME $LXD_CONTAINER -- usermod -aG sudo $USERNAME
        exec_container_root passwd --delete $USERNAME
        #exec_container_root echo "$USER ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/$USER
    fi

    if ! lxc config device get $LXD_CONTAINER current_dir_mount disk 2> /dev/null ; then
        echo "${POSITIVE_COLOR}Mounting $MOUNTED_DIRECTORY in container $MOUNT_POINT.${NC}"
        lxc config device add $LXD_CONTAINER current_dir_mount disk source=$MOUNTED_DIRECTORY path=$MOUNT_POINT
    else
        lxc config device set $LXD_CONTAINER current_dir_mount source $MOUNTED_DIRECTORY
    fi

    if ! lxc config device get $LXD_CONTAINER gradle_cache_dir_mount disk 2> /dev/null ; then
        echo "${POSITIVE_COLOR}Mounting gradle cache dir ($HOME/.gradle) in container.${NC}"
        if [ ! -d $HOME/.gradle ]; then mkdir $HOME/.gradle; fi
        lxc config device add $LXD_CONTAINER gradle_cache_dir_mount disk source=$HOME/.gradle/ path=$HOME/.gradle
    fi

    # if [ $ENTERPRISE -eq 1 ]; then
    #     echo "Copy Qt license file /home/$USERNAME/.qt-license into container home directory..."
    #     lxc file push /home/$USERNAME/.qt-license $LXD_CONTAINER/home/$USERNAME/
    # fi

    if [ $MOUNT_SSH -eq 1 ]; then
        if ! lxc config device get $LXD_CONTAINER ssh_dir_mount disk 2> /dev/null ; then
            echo "${POSITIVE_COLOR}Mounting ssh config dir ($HOME/.ssh) in container.${NC}"
            lxc config device add $LXD_CONTAINER ssh_dir_mount disk source=$HOME/.ssh/ path=$HOME/.ssh
        fi
    fi

    exec_container_root chgrp -R 150000 /opt/ || true
}

delete_container () {
    echo "${POSITIVE_COLOR}Deleting LXD container $LXD_CONTAINER.${NC}"
    lxc delete -f $LXD_CONTAINER
}

shell_container () {
    echo "${POSITIVE_COLOR}Entering shell in LXD container $LXD_CONTAINER.${NC}"
    lxc exec $LXD_CONTAINER -- su --login $USERNAME
}


check_command_parameter_count () {
    MIN_PARAMETERS=$1
    MAX_PARAMETERS=$2
    COUNT=$(echo $PARAMETERS | wc -w)
    if  [ -n $MIN_PARAMETERS ] && [ $COUNT -lt $MIN_PARAMETERS ] ; then
        display_help
        echo ""
        echo "${ERROR_COLOR}Command '$COMMAND' requires a minimum of $MIN_PARAMETERS parameters. $$
        exit 1
    fi
    if [ -n $MAX_PARAMETERS ] && [ $COUNT -gt $MAX_PARAMETERS ] ; then
        display_help
        echo ""
        echo "${ERROR_COLOR}Command '$COMMAND' accepts at most $MAX_PARAMETERS parameters. $COUNT $
        exit 1
    fi
}

exec_container_root () {
    command="$@"
    #echo lxc exec $LXD_CONTAINER "$@"
    lxc exec $LXD_CONTAINER -- sh -c "cd $SOURCE_PATH_CONTAINER; $command"
}

exec_container () {
    command="$@"
    #echo lxc exec $LXD_CONTAINER "$@"
    lxc exec $LXD_CONTAINER -- su -l -c "cd $SOURCE_PATH_CONTAINER; $command" $USERNAME
}


build () {   
    build_qmake6
}

build_qmake6 () {

    APP_VERSION=$(exec_container "cat $SOURCE_PATH_CONTAINER/version.txt | head -n 1")
    APP_REVISION=$(exec_container "cat $SOURCE_PATH_CONTAINER/version.txt | tail -n 1")
    APPLICATION_NAME=$(source $MOUNTED_DIRECTORY/config.pri && echo $APPLICATION_NAME)
    echo "App name: ${APPLICATION_NAME}"
    echo "App version: ${APP_VERSION} (${APP_REVISION})"

    declare -a TARGET_ABI_LIST=("armv7" "arm64_v8a" "x86" "x86_64")

    for ABI in "${TARGET_ABI_LIST[@]}"; do
        ANDROID_ABI=$ABI
        echo "Start building android bundle for ${ANDROID_ABI}..."
        QMAKE=/opt/Qt/${QT_VERSION}/android_${ANDROID_ABI}/bin/qmake

        BUILDDIR=${MOUNT_POINT}/build
        ANDROID_BUILDDIR=${BUILDDIR}/build-android-${ANDROID_ABI}
        OUTPUTDIR=${BUILDDIR}/android-${ANDROID_ABI}
        ARTIFACTS=${BUILDDIR}/android-artifacts

        exec_container "mkdir -p ${ANDROID_BUILDDIR};"
        exec_container "mkdir -p ${OUTPUTDIR};"
        exec_container "mkdir -p ${ARTIFACTS};"

        exec_container "cd ${ANDROID_BUILDDIR}; $QMAKE $MOUNT_POINT CONFIG+=release -spec android-clang $ADDITIONAL_ARGS; "\
            "make qmake_all; make -j$(nproc)"

        exec_container "cd ${ANDROID_BUILDDIR}; make INSTALL_ROOT=${OUTPUTDIR}/ install"

        FILES=$(exec_container "cd ${ANDROID_BUILDDIR}; find ${ANDROID_BUILDDIR} -name *deployment-settings.json")

        if [ "${KEYSTORE_PATH}" != "" ]; then
            echo "Signing with: ${KEYSTORE_CERT} certificate from ${KEYSTORE_PATH}"
            exec_container_root "if [ -f /tmp/key.keystore ]; then rm -f /tmp/key.keystore ; fi"
            lxc file push ${KEYSTORE_PATH} $LXD_CONTAINER/tmp/key.keystore
            
            exec_container "cd ${ANDROID_BUILDDIR}; androiddeployqt " \
                "--release " \
                "--input ${FILES} " \
                "--output ${OUTPUTDIR} " \
                "--android-platform android-${SDK_VERSION} " \
                "--jdk /usr/lib/jvm/java-21-openjdk-amd64 " \
                "--jarsigner --sign /tmp/key.keystore ${KEYSTORE_CERT}" \
                "--storepass ${KEYSTORE_PASS}"  \
                "--gradle --aab --verbose"

            exec_container "cp -rv ${OUTPUTDIR}/build/outputs/bundle/release/android-${ANDROID_ABI}-release.aab " \
                "${ARTIFACTS}/${APPLICATION_NAME}-android-${APP_VERSION}-${APP_REVISION}-${ANDROID_ABI}-release-signed.aab"

            # Note: the jarsigner can only sign apk using V1 signatures. Since Android 7 at least V2 signature is required.
            # https://source.android.com/docs/security/features/apksigning
            echo "Sign using apksigner"

            SIGNED_APK=android-${ANDROID_ABI}-release-signed.apk

            exec_container "cd ${OUTPUTDIR}/build/outputs/apk/release/ ; ls -l ; " \
                "/opt/android/sdk/build-tools/${SDK_VERSION}.0.0/apksigner sign " \
                "--ks /tmp/key.keystore " \
                "--ks-pass pass:$KEYSTORE_PASS ${SIGNED_APK}"
            
            exec_container "cd ${OUTPUTDIR}/build/outputs/apk/release/ ; "\
                "/opt/android/sdk/build-tools/${SDK_VERSION}.0.0/apksigner verify --verbose ${SIGNED_APK}"

            exec_container "cp -rv ${OUTPUTDIR}/build/outputs/apk/release/${SIGNED_APK} " \
                "${ARTIFACTS}/${APPLICATION_NAME}-android-${APP_VERSION}-${APP_REVISION}-${ANDROID_ABI}-release-signed.apk"

        else
            exec_container "cd ${ANDROID_BUILDDIR}; androiddeployqt " \
                 "--release " \
                 "--input ${FILES} " \
                 "--output ${OUTPUTDIR} " \
                 "--android-platform android-${SDK_VERSION} " \
                 "--jdk /usr/lib/jvm/java-21-openjdk-amd64 " \
                 "--gradle --aab --verbose"

            exec_container "cp -rv ${OUTPUTDIR}/build/outputs/bundle/release/android-${ANDROID_ABI}-release.aab " \
                "${ARTIFACTS}/${APPLICATION_NAME}-android-${APP_VERSION}-${APP_REVISION}-${ANDROID_ABI}-release.aab"

         fi
    done

    exec_container "ls -l ${ARTIFACTS}"
}

clean () {
    exec_container "rm build -rf"
}

KEYSTORE_PATH=""
KEYSTORE_CERT=""
KEYSTORE_PASS=""
MOUNT_SSH=0

while [ "$1" != "" ]; do
    OPTION=`echo $1 | awk -F= '{print $1}'`
    VALUE=`echo $1 | awk -F= '{print $2}'`
    VALUEVALUE=`echo $1 | awk -F= '{print $3}'`
    case $1 in
        -*)
            case $OPTION in
            --container-prefix)
                CONTAINER_PREFIX=$VALUE
            ;;
            --help | -h | help )
                display_help
                exit 0
            ;;
            --sign | -s )
                KEYSTORE_PATH=$VALUE
            ;;
            --cert-alias | -c )
                KEYSTORE_CERT=$VALUE
            ;;
            --keypass | -k )
                KEYSTORE_PASS=$VALUE
            ;;
            --sdk )
                SDK_VERSION=$VALUE
            ;;
            --qt )
                QT_VERSION=$VALUE
            ;;
            --config-args)
                ADDITIONAL_ARGS="$ADDITIONAL_ARGS $VALUE=$VALUEVALUE"
            ;;
            --mount-ssh)
                MOUNT_SSH=1
            ;;
            *)
                display_help
                echo ""
                echo "error: unknown option: $OPTION"
                exit 1
            ;;
            esac
            shift
        ;;
        *)
            break
        ;;
    esac
done

variables

COMMAND=$1
if [ -n "$COMMAND" ] ; then
    shift
fi

if [ "$COMMAND" = "help" ] ; then
    display_help
    exit 0
fi
if [ -z "$COMMAND" ] ; then
    new_container
    build
else
    PARAMETERS=$@
    case "$COMMAND" in
        delete) 
            check_command_parameter_count 0 1
            delete_container
        ;;
        shell)
            check_command_parameter_count 0 1
            new_container
            shell_container
        ;;
        build)
            new_container
            build
        ;;
        clean)
            new_container
            clean $@
        ;;
        *)
            display_help
            echo ""
            echo "${ERROR_COLOR}error: unknown command: $COMMAND${NC}"
            exit 1
        ;;
    esac
fi

