#!/bin/bash
cd "$(dirname "$0")" || exit
# Commands such as git pull return exit code if there are no changes
# set -e

if [[ -a ".env" ]]; then
    source .env
fi

function help-table() {
    # Define column widths
    cmd_width=25
    opt_width=20
    desc_width=90

    # Print table header
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "Command" "Option" "Description"
    echo "|$(printf '%*s' $((cmd_width + 2)) '' | tr ' ' '-')|$(printf '%*s' $((opt_width + 2)) '' | tr ' ' '-')|$(printf '%*s' $((desc_width + 2)) '' | tr ' ' '-')|"

    # Print table rows
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "activate-venv" "" "Activate virtualenv."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "build" "[platform]" "Build Odoo Conainer image. Optionally define the target platform."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "change-uuid" "[env]" "Change database uuid via xmlrpc."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "checkout" "[branch]" "Checkout Odoo version / branch."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "checkout-config-files" "[branch]" "Checkout config files from another branch."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "checkout-revision" "[revision]" "Run Odoo revision script or checkout revision set by env var."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "clear-assets" "[db]" "Clear all assets of Odoo database."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "clear-views" "[db]" "Clear all views of Odoo database."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "clear-filestore" "[db]" "Clear local filestore folder. No param will clear all filestores. Default is branch name."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "convert-database" "[db]" "Convert database backup file from PostgreSQL 9.5 to latest. Default is branch name."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "create-module" "[path]" "Create new Odoo module from template."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "create-module-repo" "[path]" "Initialize Odoo module repo from template."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "create-revision" "[revision]" "Create new Odoo revision."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "create-nextcloud-env" "[env]" "Create env file for Nextcloud instance."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "create-odoo-env" "[env]" "Create env file for Odoo Instance."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "create-snippet" "[id]" "Create snippet from template."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "disable-mailserver" "[env]" "Disable mail server settings via xmlrpc."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "disable-snippet" "[env][path]" "Disable snippet definition."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "container-login" "" "Setup container hub login credentials."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "drop-db" "[db]" "Drop target Odoo database. Default is branch name."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "edit-env" "[env]" "Open env file in default editor."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "generate-admin-passwd" "[pass]" "Generate hash for Odoo master password."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "translate-module" "[env][path][lang]" "Generate translation for Odoo module."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "generate-help-doc" "" "Write help table to task.md file."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "generate-module-overview" "" "Update module overview doc file."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "generate-module-security" "[path][model]" "Generate model access file for a selected model of a module."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "generate-module-model" "[path][model]" "Generate model files from templates."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "generate-module-snippet" "[path][ref]" "Generate view snippet from template."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "generate-snippets-doc" "" "Update snippets doc file."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "generate-revisions-doc" "" "Update revisions doc file."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "get-addons-path" "" "Output addons path."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "get-module-version" "[path]" "Get module version from manifest."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "get-modules" "[path][option]" "Get list of modules in path. Option is 'basename' or 'dirname'."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-feature-branch" "[path]" "Create feature branch for Odoo module."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-fetch" "" "Fetch all Odoo version branches."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-mig-branch" "[path]" "Create migration branch for Odoo module."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-submodule-add" "[url] [path]" "Add git submodule."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-submodule-checkout" "" "Checkout submodule commits."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-submodule-ls" "" "List submodule path space separated."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-submodule-list" "" "List path and url of submodules."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-submodule-init" "" "Init submodules listed in the .gitmodules file."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-submodule-pull" "" "Pull all submodules listed in the .gitmodules file."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-submodule-remove" "[path]" "Remove a git submodule."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-submodule-delete" "" "Delete all submodule folders."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-submodule-switch" "[branch]" "Switch branch for all submodules listed in the .gitmodules file."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "git-submodule-sync" "" "Switch, stash and pull all submodules."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "import-csv" "[db][path]" "Import data from csv. Filename must match PostgreSQL table name."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "info" "" "Show values of project env vars."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "init-db" "[db]" "Initialize the Odoo database. Default is branch name."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "init-venv" "" "Initialize python virtual env."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "init-module" "[db][path,module]" "Initialize Odoo module. Default database is branch name."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "load-language" "[db][lang]" "Install language package in Odoo db."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "install-native" "" "Install Odoo requirements in source folder."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "install-odoo-scripts" "" "Install Odoo scripts."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "install-requirements" "[db][path]" "Install python packages from requirements.txt."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "install-snippet" "[env][path]" "Install snippet definition."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "k8s-apply" "" "Apply the Odoo K8s manifests."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "lint-module" "[path]" "Run pylint odoo for module."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "lint-module-repo" "[path]" "Run pylint odoo for modules in repo folder."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "lint-snippets" "" "Run checks for all snippets."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "list-modules" "[path]" "Get modules in path as list."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "list-env" "" "List env files."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "list-revision" "" "List available Odoo revisions."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "llm-update" "[path]" "Feed module files with prompt to LLM and apply updates with git path."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "logs" "" "Tail Odoo container logs."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "node-install" "" "Install build dependencies."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "node-dev" "" "Start vuepress development server."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "node-build" "" "Create vuepress build."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "node-serve-build" "" "Serve vuepress build."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "odoo-cloc" "[db]" "Count custom line of codes. Default is branch name."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "pass-store-dotenv" "" "Store content of .env in pass entry."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "pass-restore-dotenv" "" "Restore content of .env from pass entry."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "patch-database" "[db][path]" "Apply sql file to database. Default database is branch name."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "publish" "" "Publish Odoo container image."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "ps" "" "List container processes."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "pytest-module" "[db][name,path]" "Run module tests with pytest."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "release-module" "[path]" "Create GitHub release for a module."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "remove" "[name]" "Remove containers and volumes. Options: none, db, admin, odoo, mail."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "remove-env" "[env]" "Remove environment config."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "remove-module" "[db][name]" "Remove target Odoo module."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "remove-snippet" "[env][path]" "Remove snippet definition."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "reset-views" "[db][key]" "Execute hard reset on views matching keys."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "restart" "[name]" "Restart container."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "save-config" "[name]" "Save Odoo database config."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "setup-mail" "[db]" "Setup mail config in Odoo db."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "setup-mail-sql" "[db]" "Setup mail config in Odoo db with SQL."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "set-admin" "[db]" "Sets the password for the first user in database. Default is branch name."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "set-addons-path" "" "Set Odoo addons path env variable."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "source" "" "Source the Python virtual env."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "show-env" "[env]" "Output content of the env file."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "show-revision" "[revision]" "Show references of Odoo revision."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "start" "[name][db]" "Start container. Options: none, db, admin, odoo, native, mail."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "start-kind" "" "Start kind Kubernetes cluster."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "start-minikube" "" "Start minikube Kubernetes cluster."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "start-psql" "[db]" "Start PSQL shell in container container. Default is branch name."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "start-shell" "[db]" "Start Odoo shell from source folder. Default is branch name."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "stop" "[name]" "Stop containers."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "template-odoo-rc" "" "Template the Odoo config file."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "template-docker-compose" "" "Template the Docker compose file."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "test-container" "" "Test container environment."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "test-xmlrpc" "[env]" "Test json rpc connection."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "test-k8s" "" "Test Kubernetes environment."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "test-module" "[db][name,path]" "Test target Odoo module."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "test-module-repo" "[db][path]" "Test target Odoo modules in repo folder."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "update-app-list" "[db]" "Update app list."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "update-docs" "" "Update project docs."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "upgrade-module" "[path][version]" "Upgrade code of module from target Odoo version."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "upgrade-odoo" "[db][version][mode]" "Run the Odoo upgrade scripts. Default mode ist 'test'."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "update-module" "[db][name,path]" "Update target Odoo module."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "update-readme" "[path]" "Update Readme file of Odoo module collection."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "update-snippet" "[env][path]" "Update snippet definition."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "upload-module" "[env][path]" "Zip and upload Odoo module."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "visualize-dependencies" "[path]" "Generate visualizations of module dependencies."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "version" "" "Show version of required tools."
    printf "| %-${cmd_width}s | %-${opt_width}s | %-${desc_width}s |\n" "zip-module" "[path]" "Create zip file for module."
}

function help() {
    echo
    echo "$1 <command> [options]"
    echo
    echo "commands:"
    echo
    help-table
    echo
}

# Static env vars

PASS_ENTRY=env/Odoo-Build
ODOO_RC="odoo.conf"
ODOO_BUILD_CONFIG_DIR="$HOME/.config/odoo-build"

# Dynamic env vars

GIT_BRANCH=$(git symbolic-ref --short -q HEAD)
ODOO_DATABASE=${ODOO_DATABASE:="$GIT_BRANCH"}
ODOO_REVISION=${ODOO_REVISION:="$GIT_BRANCH"}
ODOO_LANGUAGE=${ODOO_LANGUAGE:="de_CH"}
ODOO_PORT=${ODOO_PORT:="8069"}
POSTGRES_PORT=${POSTGRES_PORT:="5432"}
LOG_LEVEL=${LOG_LEVEL:="info"}
CONTAINER_REGISTRY=${CONTAINER_REGISTRY:="mintsystem/"}
CONTAINER_TAG=${CONTAINER_TAG:="odoo:${ODOO_REVISION}"}
CONTAINER_CONFIG="$HOME/.docker/$CONTAINER_REGISTRY"
BROWSER_OPEN=${BROWSER_OPEN:=true}
ODOO_REVISION_CONTAINER_PULL=${ODOO_REVISION_CONTAINER_PULL:=true}
CONTAINER_ENGINE=${CONTAINER_ENGINE:="docker"}
COMPOSE_COMMAND=${COMPOSE_COMMAND:="docker compose"}
LLM_MODEL=${LLM_MODEL:="deepseek-coder"}

# Conditional env vars

if [[ "$CONTAINER_ENGINE" == "podman" ]]; then
    COMPOSE_COMMAND="podman-compose"
fi

if [ -n "$SERVER_WIDE_MODULES" ]; then
    SERVER_WIDE_MODULES="base,web,$SERVER_WIDE_MODULES"
else
    SERVER_WIDE_MODULES="base,web"
fi

if [[ "$(uname)" == "Darwin" ]]; then
    OS_RELEASE="Darwin"
    PYTHON_NOTIFY=""
    OS_OPEN="open"
else
    OS_RELEASE=$(awk -F= '/^NAME/{print $2}' /etc/os-release | tr -d '"')
    PYTHON_NOTIFY="inotify"
    OS_OPEN="xdg-open"
fi

# Help Commands

function info() {
    set-addons-path
    echo "OS Release: $OS_RELEASE"
    echo "Git Branch: $GIT_BRANCH"
    echo "Odoo Revision: $ODOO_REVISION"
    echo "Odoo Port: $ODOO_PORT"
    echo "Postgres Port: $POSTGRES_PORT"
    echo "Odoo Language: $ODOO_LANGUAGE"
    echo "Container Registry: $CONTAINER_REGISTRY"
    echo "Container Config: $CONTAINER_CONFIG"
    echo "Container Tag: $CONTAINER_TAG"
    echo "Addons Path: $ADDONS_PATH"
}

function version() {
    activate-venv
    uv --version
    wkhtmltopdf -V
    if [ "$CONTAINER_ENGINE" == "docker" ]; then
        docker -v
        docker compose version
    else
        podman --version
        podman-compose --version
    fi
    minikube version
    kind version
}

function generate-admin-passwd() {
    activate-venv
    if test -z "$1"; then echo "\$1 is empty."; exit; fi
    ODOO_PASSWORD="$1"
    scripts/hash_password
}

# Environment Commands

function init-venv() {
    if [ ! -d "venv$GIT_BRANCH" ]; then
        echo "Init venv$GIT_BRANCH with $(uv --version)."
        uv venv "venv$GIT_BRANCH"
    fi
}

function activate-venv() {
    echo "Source virtualenv venv$GIT_BRANCH."
    source "venv$GIT_BRANCH/bin/activate"
    echo "$(python --version) is active."
}

function load-env() {
    ENV_FILE="$ODOO_BUILD_CONFIG_DIR/.env.$1"
    echo "Load env file $ENV_FILE"

    export $(cat "$ENV_FILE" | sed 's/#.*//g' | xargs)
}

function get-addons-path() {
    set-addons-path
    echo "$ADDONS_PATH"
}

function template-odoo-rc() {
    echo "Template $ODOO_RC"

    export SERVER_WIDE_MODULES
    export MODULE_AUTO_INSTALL_DISABLED

    if [ -n "$GIT_SSH_PRIVATE_KEY" ]; then
        GIT_SSH_PRIVATE_KEY=$(echo -e "$GIT_SSH_PRIVATE_KEY" | base64 -w0)
    fi
    export GIT_SSH_PRIVATE_KEY
    export GIT_SSH_PUBLIC_KEY

    export MAIL_DEFAULT_FROM=${MAIL_DEFAULT_FROM:="notification"}
    export MAIL_CATCHALL_ALIAS=${MAIL_CATCHALL_ALIAS:="catchall"}

    envsubst < "odoo.conf.template" > "$ODOO_RC"
}

function set-addons-path() {

    # Read addons path from git submodules
    SUBMODULES_PATH="$(git config --file .gitmodules --get-regexp path | awk '{ print $2 }' | tr '\n' ',' |  sed 's/,*$//g')"

    # Remove excluded addons
    EXCLUDES="addons/theme_mint_system addons/company addons/web"
    for EXCLUDE in $EXCLUDES; do
        SUBMODULES_PATH=$(echo "$SUBMODULES_PATH" | sed "s|${EXCLUDE},||g")
    done

    # Check if addons dir exist
    for ADDON in $SUBMODULES_PATH; do
        if [ -d "$ADDON" ]; then
            echo "Path does not exist: $ADDON"
            exit 1
        fi
    done

    # Convert to native paths
    ADDONS_PATH="$(echo $SUBMODULES_PATH | sed 's|odoo,|odoo/addons,|g')"

    # Append paths from config env var
    if [ -n "$ODOO_ADDONS_PATH" ]; then
        ADDONS_PATH="${ODOO_ADDONS_PATH},${ADDONS_PATH}"
    fi
}

function init-config-dir() {
    echo "Ensure $ODOO_BUILD_CONFIG_DIR exists"
    mkdir -p "$ODOO_BUILD_CONFIG_DIR"
}

function create-odoo-env() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    init-config-dir
    ENV_FILEPATH="$ODOO_BUILD_CONFIG_DIR/.env.$1"
    if [ -f "$ENV_FILEPATH" ]; then
        echo "Env file already exists: $ENV_FILEPATH"
        exit 1
    fi

    echo "Init env file: $ENV_FILEPATH"
    echo "ODOO_URL=$ODOO_URL" > "$ENV_FILEPATH"
    echo "ODOO_DATABASE=$ODOO_DATABASE" >> "$ENV_FILEPATH"
    echo "ODOO_USERNAME=$ODOO_USERNAME" >> "$ENV_FILEPATH"
    echo "ODOO_PASSWORD=$ODOO_PASSWORD" >> "$ENV_FILEPATH"

    echo "Edit with: task edit-env $1"
}

function create-nextcloud-env() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    init-config-dir
    ENV_FILEPATH="$ODOO_BUILD_CONFIG_DIR/.env.$1"
    if [ -f "$ENV_FILEPATH" ]; then
        echo "Env file already exists: $ENV_FILEPATH"
        exit 1
    fi

    echo "Init env file: $ENV_FILEPATH"
    echo "NEXTCLOUD_URL=" > "$ENV_FILEPATH"
    echo "NEXTCLOUD_USERNAME=" >> "$ENV_FILEPATH"
    echo "NEXTCLOUD_PASSWORD=" >> "$ENV_FILEPATH"

    echo "Edit with: task edit-env $1"
}

function list-env() {
    ls -a1 "$ODOO_BUILD_CONFIG_DIR"
}

function show-env() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi
    ENV_FILEPATH="$ODOO_BUILD_CONFIG_DIR/.env.$1"
    cat "$ENV_FILEPATH"
}

function edit-env() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi
    ENV_FILEPATH="$ODOO_BUILD_CONFIG_DIR/.env.$1"
    "$EDITOR" "$ENV_FILEPATH"
}

function remove-env() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi
    ENV_FILEPATH="$ODOO_BUILD_CONFIG_DIR/.env.$1"
    rm "$ENV_FILEPATH"
}

# Docs Commands

generate-help-doc() {
    help-table > task.md 
}

function update-readme() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi
    README_PATH="$1"
    FILE_NAME=$(basename "$README_PATH")

    if [[ "$FILE_NAME" != "README.md" ]]; then
        README_PATH="$1/README.md"
        FILE_NAME="README.md"
    fi

    REPO_PATH=$(dirname "$README_PATH")
    
    MANIFEST_FILES="$REPO_PATH/*/__manifest__.py"

    # Find marker in readme and clear content after
    echo "Clear modules table for $README_PATH."
    MARKER="## Available modules"
    sed -i "/$MARKER/Q" "$README_PATH"

    echo "$MARKER" >> "$README_PATH"
    echo "" >> "$README_PATH"
    echo "| Module | Summary |" >> "$README_PATH"
    echo "| --- | --- |" >> "$README_PATH"

    # Clear table after a marker
    for MANIFEST_FILE in $MANIFEST_FILES; do
        MODULE_DIR=$(dirname "$MANIFEST_FILE")
        MODULE_NAME=$(basename "$MODULE_DIR")
        echo "Add summary of $MODULE_NAME to readme file."
        SUMMARY=$(grep 'summary' "$MANIFEST_FILE" -A 1 | tail -1)
        echo "| [$MODULE_NAME]($MODULE_NAME) | $SUMMARY |" >> "$README_PATH"
    done
}


function generate-snippets-doc() {

    echo "Update snippets doc file."
    
    echo "# Snippets" > snippets.md
    echo "In Odoo everything is described as an XML document. \
    Snippets are modifications (edits) for these XML documents. \
    With a snippet you can e.g. hide a field on the contact form. \
    A snippet name is unique and follows the \`\$COMPANY.\$MODULE.\$XML_ID.\$DESCRIPTION\` schema." >> snippets.md

    PATH_URL="https://github.com/Mint-System/Odoo-Build/tree/16.0"

    # Get all modules
    MODULES=$(ls snippets/*.xml | xargs -n 1 basename | cut -d. -f1 | sort | uniq)
    for MODULE in $MODULES; do

        TITLE="${MODULE^}" # Uppercase first letter
        TITLE=$(echo "$TITLE" | sed 's/_/ /g') # Replace underline with space
        TITLE=$(echo "$TITLE" | sed -r 's/\<./\U&/g') # Uppercase first letter after space

        # Create doc file for each module
        DOCFILE="snippets/$MODULE.md"
        echo -e "# $TITLE" > "$DOCFILE"
        echo "## [$TITLE](snippets/$MODULE.md)" >> snippets.md
        SIDEBAR_ENTRIES+="'/snippets/$MODULE.md',\n"
        
        # Get all xml ids
        XML_IDS=$(ls snippets/$MODULE.*.xml | xargs -n 1 basename | cut -d. -f2 | uniq)
        for XML_ID in $XML_IDS; do
        
            XML_ID_TITLE=$(echo "$XML_ID" | sed 's/_/ /g') # Replace underline with space
            XML_ID_TITLE=$(echo "$XML_ID_TITLE" | sed -r 's/\<./\U&/g') # Uppercase first letter after space

            echo "## $XML_ID_TITLE  " >> "$DOCFILE"

            # Process each file
            FILES="snippets/$MODULE.$XML_ID.*.xml"
            for FILE in $FILES; do

                # Get snippet params
                FILENAME=$(basename "$FILE")
                EDIT=$(echo "$FILENAME" | cut -d. -f3)

                EDIT_TITLE=$(echo "$EDIT" | sed 's/_/ /g') # Replace underline with space
                EDIT_TITLE=$(echo "$EDIT_TITLE" | sed -r 's/\<./\U&/g') # Uppercase first letter after space

                # Group by modules
                echo "### $EDIT_TITLE  " >> "$DOCFILE"
                echo "ID: \`mint_system.$MODULE.$XML_ID.$EDIT\`  " >> "$DOCFILE"
                echo -e '```xml' >> "$DOCFILE"
                cat "$FILE" >> "$DOCFILE"
                echo -e '\n```' >> "$DOCFILE"
                echo -e "Source: [$FILE]($PATH_URL/$FILE)\n" >> "$DOCFILE"
            done
        done
    done
    echo -e "export default [$SIDEBAR_ENTRIES]" > .vuepress/sidebar.js
}

function generate-revisions-doc() {

    echo "Update revisions doc file."

    rm -f "revisions.md"
    echo -e "# Odoo Revisions \n\
A Odoo revision is a snapshot of git references of the Odoo source and modules at a specific date.\n\
For each major release there are multiple revisions.\n" > "revisions.md"

    declare -A REVISIONS
    PATH_URL="https://github.com/Mint-System/Odoo-Build/tree/16.0"

    for FILE in scripts/odoo_revision_*; do
        if [[ -f "$FILE" ]]; then
            REVISION=$(basename "$FILE" | sed 's/odoo_revision_//')
            VERSION=$(echo "$REVISION" | cut -d'.' -f1-2)

            if [[ -z "${REVISIONS[$VERSION]}" ]]; then
                REVISIONS[$VERSION]="## $VERSION"
            fi

            REVISIONS[$VERSION]+=$'\n\n'
            REVISIONS[$VERSION]+="#### $REVISION"
            REVISIONS[$VERSION]+=$'\n\n```bash\n'
            REVISIONS[$VERSION]+=$(cat "$FILE")
            REVISIONS[$VERSION]+=$'\n```'
        fi
    done

    for REVISION in $(echo "${!REVISIONS[@]}" | tr ' ' '\n' | sort -V); do
        echo -e "${REVISIONS[$REVISION]}\n" >> "revisions.md"
    done
}

function generate-module-overview() {
    echo "Update module overview doc file."
    activate-venv
    ./scripts/generate_module_overview
}

function update-docs() {
    generate-module-overview
    generate-revisions-doc
    generate-snippets-doc
    generate-help-doc
}

# Module Commands

function get-modules() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    OPTION="$2"
    if [ -z "$OPTION" ]; then
        OPTION="dirname"
    fi

    if [[ "$OPTION" == "dirname" ]]; then
        MODULES=$(echo "$1" | tr "," "\n" | xargs -I {} find {} -type f -name "__manifest__.py" | xargs grep -l "version.*${GIT_BRANCH}" | xargs -r dirname | sort -u | tr "\n" "," | sed 's/,$//')
    fi
    if [[ "$OPTION" == "basename" ]]; then
        MODULES=$(echo "$1" | tr "," "\n" | xargs -I {} find {} -type f -name "__manifest__.py" | xargs grep -l "version.*${GIT_BRANCH}" | xargs -r dirname | xargs -r -I {} basename {} | sort -u | tr "\n" "," | sed 's/,$//')
    fi
    echo "$MODULES"
}

function get-module-version() {
    if test -z "$1"
    then
        echo "\$1 is empty."
    else
        # Get version of module
        VERSION=$(grep -m 1 \"version "$1/__manifest__.py" |  sed "s;';\";g"  | sed "s/,//g" | sed  's/#.*//g')
        VERSION=$(echo "{ $VERSION }" | jq .version | sed 's/"//g' | sed 's/null//g')
        
        # Set default version
        [ -z "$VERSION" ] && VERSION=0.0

        COUNT_DOTS=$(echo "$VERSION" | grep -o "\." | wc -l)

        # Check if oca version or enterprise version
        if [[ $COUNT_DOTS == 2 ]]; then
            VERSION="$GIT_BRANCH.$VERSION"
        fi
        if [[ $COUNT_DOTS == 1 ]]; then
            VERSION="$GIT_BRANCH.$VERSION"
        fi

        echo "$VERSION"
    fi
}

function list-modules() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi
    echo $(get-modules "$1" basename | tr "," "\n")
}

# Container Commands

function template-docker-compose() {
    echo "Template docker-compose.yml"

    export CONTAINER_REGISTRY
    export CONTAINER_TAG
    export POSTGRES_PORT
    export ODOO_PORT
    export MAIL_DEFAULT_FROM
    export MAIL_CATCHALL_DOMAIN
    export MAIL_CATCHALL_ALIAS
    export ODOO_MAIL_SMTP_HOST
    export ODOO_MAIL_SMTP_PORT
    export ODOO_MAIL_SMTP_ENCRYPTION
    export ODOO_MAIL_SMTP_FROM_FILTER
    export ODOO_MAIL_IMAP_HOST
    export ODOO_MAIL_IMAP_PORT
    export ODOO_MAIL_IMAP_SSL
    export ODOO_MAIL_USERNAME
    export ODOO_MAIL_PASSWORD
    export GIT_SSH_PUBLIC_KEY
    export GIT_SSH_PRIVATE_KEY
    export ADDONS_GIT_REPOS
    export ODOO_ADDONS_PATH
    export ODOO_DATABASE
    export ODOO_INIT
    export ODOO_INIT_LANG
    export ODOO_INIT_ADDONS
    export ENVIRONMENT
    export PYTHON_INSTALL
    export SERVER_WIDE_MODULES
    export SESSION_DB_URI
    export PROXY_MODE
    export LOG_LEVEL
    export LIST_DB
    export ADMIN_PASSWD
    export DBFILTER
    export WORKERS
    export LIMIT_REQUEST
    export LIMIT_TIME_CPU
    export LIMIT_TIME_REAL
    export MODULE_AUTO_INSTALL_DISABLED
    export CLICK_ODOO_UPDATE
    export PGADMIN_DEFAULT_EMAIL
    export PGADMIN_DEFAULT_PASSWORD
    export POSTGRES_IMAGE

    envsubst < "docker-compose.yml.template" > "docker-compose.yml"
}

function ps() {
    $CONTAINER_ENGINE ps
}

function build() {
    MANIFEST_FILE="image/Dockerfile"
    PLATFORM="linux/amd64" # linux/arm64
    if [ -n "$1" ]; then
        PLATFORM="$1"
    fi
    ODOO_DATE=""
    if [[ "ODOO_REVISION" != "$GIT_BRANCH" ]]; then
       ODOO_DATE=$(echo "$ODOO_REVISION" | cut -d'.' -f3-)
    fi

    echo "Remove container image with tag ${CONTAINER_REGISTRY}${CONTAINER_TAG}"
    $CONTAINER_ENGINE image rm -f "${CONTAINER_REGISTRY}${CONTAINER_TAG}"

    if [ "$CONTAINER_ENGINE" == "podman" ]; then
        echo "Run Podman build ${CONTAINER_REGISTRY}${CONTAINER_TAG} for ${PLATFORM}"
        SOURCE_DATE_EPOCH=$(git -C odoo log -1 --pretty=%ct) podman build --platform "$PLATFORM" . \
            --file "$MANIFEST_FILE" \
            --build-arg ODOO_VERSION="$GIT_BRANCH" \
            --build-arg ODOO_DATE="$ODOO_DATE" \
            --tag "${CONTAINER_REGISTRY}${CONTAINER_TAG}"
    fi

    if [ "$CONTAINER_ENGINE" == "docker" ]; then
        echo "Run Docker build ${CONTAINER_REGISTRY}${CONTAINER_TAG} for ${PLATFORM}"
        SOURCE_DATE_EPOCH=$(git -C odoo log -1 --pretty=%ct) docker buildx build --platform "$PLATFORM" . \
            --file "$MANIFEST_FILE" \
            --build-arg ODOO_VERSION="$GIT_BRANCH" \
            --build-arg ODOO_DATE="$ODOO_DATE" \
            --tag "${CONTAINER_REGISTRY}${CONTAINER_TAG}" \
            --load
    fi
}

function container-login() {
    echo "Setup container hub login credentials for $CONTAINER_REGISTRY"
    echo -n "Enter username: " 
    read CONTAINER_REGISTRY_USERNAME
    echo -n "Enter password: " 
    read -s CONTAINER_REGISTRY_PASSWORD
    if [ "$CONTAINER_ENGINE" == "podman" ]; then
        podman login --username "$CONTAINER_REGISTRY_USERNAME" --password "$CONTAINER_REGISTRY_PASSWORD" docker.io
    fi
    if [ "$CONTAINER_ENGINE" == "docker" ]; then
        docker --config "$CONTAINER_CONFIG" login --username "$CONTAINER_REGISTRY_USERNAME" --password "$CONTAINER_REGISTRY_PASSWORD"
    fi
}

function publish() {
    LATEST_TAG="odoo:$GIT_BRANCH"
    echo "Tag container image ${CONTAINER_REGISTRY}${CONTAINER_TAG} with ${CONTAINER_REGISTRY}${LATEST_TAG}"
    $CONTAINER_ENGINE tag "${CONTAINER_REGISTRY}${CONTAINER_TAG}" "${CONTAINER_REGISTRY}${LATEST_TAG}"

    if [ "$CONTAINER_ENGINE" == "docker" ]; then
        echo "Push container image to ${CONTAINER_REGISTRY}${CONTAINER_TAG}"
        docker --config "$CONTAINER_CONFIG" push "${CONTAINER_REGISTRY}${CONTAINER_TAG}"
        docker --config "$CONTAINER_CONFIG" push "${CONTAINER_REGISTRY}${LATEST_TAG}"
    fi
}

function upload-module() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi
    if test -z "$2"; then echo "\$2 is empty."; exit; fi

    # Check if path is root folder
    MODULES="$2"
    if [ ! -f "$2/__manifest__.py" ]; then
        echo "Identified as root folder"
        MODULES="$MODULES/*"
    fi

    for MODULE in $MODULES; do

        if [ -f "$MODULE/__manifest__.py" ]; then

            # Create module zip
            zip-module "$MODULE"

            # Get path to zip file and upload url
            FILE_PATH="tmp/$MODULE_NAME.zip"
            load-env "$1"
            NEXTCLOUD_UPLOAD_URL="$NEXTCLOUD_URL/remote.php/dav/files/$NEXTCLOUD_USERNAME/Odoo-Apps/"

            # Upload zip file
            curl -u "$NEXTCLOUD_USERNAME:$NEXTCLOUD_PASSWORD" -T "$FILE_PATH" "$NEXTCLOUD_UPLOAD_URL"
            echo "File $FILE_PATH uploaded to $NEXTCLOUD_UPLOAD_URL."
            
            UPLOADS+="  - name: $MODULE\n"
            UPLOADS+="    version: $VERSION\n"
        fi
    done

    echo "odoo_apps:"
    echo -e "$UPLOADS"
}

function logs() {
    $CONTAINER_ENGINE logs --follow odoo
}

# Script Commands

function install-odoo-scripts() {
    curl -L https://raw.githubusercontent.com/mint-system/ansible-build/master/roles/odoo_scripts/files/install | bash
}

function upgrade-odoo() {
    if test -z "$1"; then echo "\$1/database is empty."; exit; fi
    if test -z "$2"; then echo "\$2/version is empty."; exit; fi

    DATABASE="$1"
    ODOO_TARGET_VERSION="$2"
    MODE="test"
    if [ -n "$3" ]; then
        # Options: test, production
        MODE="$3"
    fi
    NEW_DATABASE="${DATABASE}_${ODOO_TARGET_VERSION}"

    echo "Execute Odoo upgrade script in $MODE mode for $DATABASE with version $ODOO_TARGET_VERSION."
    echo "The database will be restored as $NEW_DATABASE."
    export PGHOST=localhost
    export PGUSER=odoo
    export PGPASSWORD=odoo
    python <(curl -s https://upgrade.odoo.com/upgrade) "$MODE" -d "$DATABASE" -t "$ODOO_TARGET_VERSION" -r "$NEW_DATABASE"
    echo "Upgrade finished successfully."
}

# Install Commands

function install-native() {    
    init-venv
    activate-venv
    
    if [[ "$OS_RELEASE" =~ ^(Ubuntu|Debian|Pop!_OS)$ ]]; then

        # Source: https://gist.github.com/faniska/37f896d5e9de5fee925925d7caf3cb9e
        INSTALLED_VERSION=$(wkhtmltopdf --version 2>&1 | grep -Po '^wkhtmltopdf \K[\d.]+')
        if [ "$INSTALLED_VERSION" != "0.12.4" ]; then
            echo "Install wkhtmltopdf"
            sudo apt remove wkhtmltopdf
            wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.4/wkhtmltox-0.12.4_linux-generic-amd64.tar.xz
            tar xvf wkhtmltox*.tar.xz
            sudo mv wkhtmltox/bin/wkhtmlto* /usr/bin
            rm -rf wkhtmltox wkhtmltox-0.12.4_linux-generic-amd64.tar.*
        else
            echo "wkhtmltopdf version is already 0.12.4"
        fi

        echo "Install python-ldap and psycopg2 build dependencies"
        sudo apt-get install -y libsasl2-dev libldap2-dev libssl-dev libpq-dev python3-dev

        echo "Install xmllint and gettext"
        sudo apt install -y libxml2-utils gettext

    elif [[ "$OS_RELEASE" =~ ^(Darwin)$ ]]; then

        echo "Welcome daring Mac user. Let's try our best to get this working."
        echo "Install wkhtmltopdf and some dev libraries"
        echo "This will give a depreciation warning and you need to enter your sudo password."
        brew install gettext wkhtmltopdf libsasl2 openldap openssl libxml2
        
        echo "Install the binary version of psycopg2"
        uv pip install psycopg2-binary --force

        echo "Add LDFLAGS to .env file"
        if ! grep -qxF 'LDFLAGS=-L/opt/homebrew/lib/' .env; then
          echo '' >> .env
          echo 'LDFLAGS=-L/opt/homebrew/lib/' >> .env
        fi

    else 
        echo "The operating system $OS_RELEASE is not supported."
        exit 1
    fi

    echo "Install Odoo development tools"
    uv pip install ${PYTHON_NOTIFY}
    uv pip install -r requirements.txt

    if [ -f "odoo/requirements.txt" ]; then
        echo "Install Odoo dependencies"
        uv pip install -r odoo/requirements.txt

        echo "Configure Odoo as python package"
        uv pip install pip
        pip install -e odoo
    fi
}

# Process Commands

function open-url-with-delay(){
    if test -z "$1"; then echo "\$1 is empty."; exit; fi
    if $BROWSER_OPEN; then
        sleep 2
        $OS_OPEN "$1"
    fi
}

function start() {
    activate-venv
    set-addons-path
    template-docker-compose
    
    # Use default database if second param is not given
    DATABASE="$2"
    if [ -z "$2" ]; then
        DATABASE="$ODOO_DATABASE"
    fi

    if [ -z "$1" ] ; then
        echo "Start odoo container ${CONTAINER_REGISTRY}${CONTAINER_TAG}"
        echo "Open http://localhost:8069 url in your browser."
        $COMPOSE_COMMAND up -d
    fi

    if [[ "$1" =~ "db" ]]; then
        $COMPOSE_COMMAND up -d db
    fi

    if [[ "$1" =~ "admin" ]]; then
        echo "Open http://localhost:8000 url in your browser."
        open-url-with-delay "http://localhost:8000" & $COMPOSE_COMMAND up -d admin
    fi

    if [[ "$1" =~ "odoo" ]]; then
        echo "Start odoo container ${CONTAINER_REGISTRY}${CONTAINER_TAG}"
        echo "Open http://localhost:8069 url in your browser."
        open-url-with-delay "http://localhost:8069" & $COMPOSE_COMMAND up -d odoo
    fi

    if [[ "$1" =~ "native" ]]; then
        activate-venv
        template-odoo-rc
        PORT=8069
        while [ $PORT -le 8079 ]; do
            if ! lsof -i:$PORT >/dev/null 2>&1; then
                break
            fi
            PORT=$((PORT + 1))
        done
        export ODOO_BASE_URL="http://localhost:8069"

        echo "Open http://localhost:$PORT url in your browser."
        open-url-with-delay "http://localhost:$PORT/web?debug=1&db=$DATABASE" &
        odoo --database="$DATABASE" --config "$ODOO_RC" --xmlrpc-port="$PORT" --addons-path="$ADDONS_PATH" --dev=all --log-level="$LOG_LEVEL"
    fi

    if [[ "$1" =~ "queue" ]]; then
        activate-venv
        PORT=8069
        echo "Open http://localhost:$PORT url in your browser."
        open-url-with-delay "http://localhost:$PORT/web?debug=1&db=$DATABASE" &
        odoo --database="$DATABASE" --config "$ODOO_RC" --xmlrpc-port="$PORT" --gevent-port=8072 --load=web,queue_job --workers=4 --addons-path="$ADDONS_PATH" --dev=all --log-level="$LOG_LEVEL" --log-handler=odoo.addons.queue_job:DEBUG
    fi

    if [[ "$1" =~ "mail" ]]; then
        echo "Open http://localhost:8025 url in your browser."
        open-url-with-delay "http://localhost:8025" & $COMPOSE_COMMAND up -d mail
    fi
}


function remove() {
    activate-venv
    template-docker-compose

    if test -z "$1"; then
        $COMPOSE_COMMAND down -v
    fi

    if [[ "$1" =~ "db" ]]; then
        $COMPOSE_COMMAND rm -f -s -v db
    fi

    if [[ "$1" =~ "admin" ]]; then
        $COMPOSE_COMMAND rm -f -s -v admin
    fi
    
    if [[ "$1" =~ "odoo" ]]; then
        $COMPOSE_COMMAND rm -f -s -v odoo
    fi

    if [[ "$1" =~ "mail" ]]; then
        $COMPOSE_COMMAND rm -f -s -v mail
    fi
}

function restart() {
    activate-venv
    template-docker-compose

    if test -z "$1"; then
        $COMPOSE_COMMAND restart
    fi

    if [[ "db|mail|odoo" =~ $1 ]]; then
        $COMPOSE_COMMAND restart "$1"
    fi
}

function stop() {
    activate-venv
    template-docker-compose

    if test -z "$1"; then
        $COMPOSE_COMMAND stop
    fi

    $COMPOSE_COMMAND stop "$1"
}

function test-container() {
    activate-venv
    version
    info

    if [ -z "$GIT_SSH_PRIVATE_KEY" ]; then
        echo "Generate SSH private key."
        mkdir -p tmp
        if [ ! -f "tmp/ed25519" ]; then
            ssh-keygen -t ed25519 -C admin@example.com -f tmp/ed25519 -N ""
        fi
        GIT_SSH_PRIVATE_KEY=$(cat tmp/ed25519 | base64 -w0)
        GIT_SSH_PUBLIC_KEY=$(cat tmp/ed25519.pub)
    fi
    
    echo "Clone submodule"
    git submodule update --init oca/partner-contact

    echo "Start container environment."
    export GIT_SSH_PRIVATE_KEY
    export GIT_SSH_PUBLIC_KEY
    export ADDONS_GIT_REPOS="https://github.com/OCA/server-env.git#${GIT_BRANCH},https://github.com/OCA/server-tools.git#${GIT_BRANCH},https://github.com/Mint-System/Odoo-Apps-Server-Tools.git#${GIT_BRANCH},https://github.com/Mint-System/Odoo-Apps-Connector.git#${GIT_BRANCH}"
    export ODOO_ADDONS_PATH="/mnt/enterprise,/mnt/oca"
    export ODOO_DATABASE=test
    export ODOO_INIT=True
    export ODOO_INIT_LANG=de_CH
    export ODOO_INIT_ADDONS=server_environment_ir_config_parameter,module_auto_update,prometheus_exporter,mail_server_filter,git_base,contacts,web_enterprise
    export PYTHON_INSTALL=prometheus-client,manifestoo
    export SERVER_WIDE_MODULES=web,session_db,module_change_auto_install
    export SESSION_DB_URI=postgres://odoo:odoo@db/test
    export MODULE_AUTO_INSTALL_DISABLED=odoo_test_xmlrunner
    export CLICK_ODOO_UPDATE=True
    export ODOO_MAIL_SMTP_HOST=mail
    export ODOO_MAIL_SMTP_PORT=1025
    export ODOO_MAIL_SMTP_ENCRYPTION=none
    export MAIL_DEFAULT_FROM="test"
    export BROWSER_OPEN=false
    start db,odoo,mail
    while ! curl --fail -s http://localhost:8069; do sleep 1; done

    echo "Test auto upgrade."
    docker-odoo-init -d test -i partner_firstname
    sed -i -E 's/(firstname = fields)/secondname = fields.Char();\1/' oca/partner-contact/partner_firstname/models/res_partner.py
    restart odoo
    while ! curl --fail -s http://localhost:8069; do sleep 1; done

    echo "Check if auto upgrade was successful."
    scripts/odooctl --method "search_one" --model "ir.model.fields" --domain "[('name', '=', 'secondname')]"
    
    echo "Setup and test RPC credentials."
    export ODOO_URL="http://localhost:8069"
    export ODOO_USERNAME=admin
    export ODOO_PASSWORD=admin
    create-odoo-env test
    show-env test
    test-xmlrpc test

    echo "Send mail with message post."

    echo "Install, update, disable and remove snippet."
    install-snippet test snippets/base.view_partner_form.show_type.xml
    update-snippet test snippets/base.view_partner_form.show_type.xml
    disable-snippet test snippets/base.view_partner_form.show_type.xml
    remove-snippet test snippets/base.view_partner_form.show_type.xml

    echo "Test Odoo scripts."
    docker-odoo-backup -d test
    docker-odoo-drop -d test
    docker-odoo-restore -d test -f /var/tmp/test.zip
    change-uuid test

    echo "Cleanup test environment."
    remove-env test
    git -C oca/partner-contact checkout .
}

# Kubernetes Commands

function start-kind() {
    echo "Start kind."
    kind create cluster
}

function start-minikube() {
    echo "Start minikube."
    minikube start
}

function k8s-apply() {
    echo "Deploy Postgres:"
    kubectl apply -f k8s/postgres-cm.yaml
    kubectl apply -f k8s/postgres-pvc.yaml
    kubectl apply -f k8s/postgres-deploy.yaml
    kubectl apply -f k8s/postgres-svc.yaml

    echo -e "\nDeploy Odoo:"
    kubectl apply -f k8s/odoo-cm.yaml
    kubectl apply -f k8s/odoo16-deploy.yaml
    kubectl apply -f k8s/odoo-svc.yaml

    
    echo -e "\nWait until resources are ready."
    sleep 8

    ODOO_POD=$(kubectl get pods -o=name --all-namespaces | grep odoo)
    POSTGRES_POD=$(kubectl get pods -o=name --all-namespaces | grep postgres)

    echo -e "\nWait for $ODOO_POD and $POSTGRES_POD pods to be running:"
    kubectl wait --for=condition=Ready "$ODOO_POD" "$POSTGRES_POD" --timeout=60s
    sleep 3

    echo -e "\nInit Odoo database in $ODOO_POD pod:"
    kubectl exec "$ODOO_POD" -- env
    kubectl exec "$ODOO_POD" -- /bin/bash -c "odoo -d odoo -i web --db_host \$HOST -r\$USER -w\$PASSWORD --stop-after-init --no-http"
}

function test-k8s() {
    start-kind
    k8s-apply
}

# Interactive Shell Commands

function start-shell() {
    DATABASE="$1"
    if [ -z "$DATABASE" ]; then
        DATABASE="$ODOO_DATABASE"
    fi

    activate-venv
    set-addons-path
    odoo shell --database "$DATABASE" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --no-http
}

function start-psql() {
    DATABASE="$1"
    if [ -z "$DATABASE" ]; then
        DATABASE="$ODOO_DATABASE"
    fi

    $CONTAINER_ENGINE exec -it db psql "postgres://odoo:odoo@localhost:5432/$DATABASE"
}

# Database Commands

function init-db() {
    ODOO_INIT_ADDONS="${ODOO_INIT_ADDONS:-"web"}"
    DATABASE="$1"
    if [ -z "$DATABASE" ]; then
        DATABASE="$ODOO_DATABASE"
    fi

    activate-venv
    set-addons-path
    template-odoo-rc
    
    echo "Initialize database $DATABASE with $ODOO_INIT_ADDONS."
    if [[ -n "$ODOO_PARAM" ]]; then
        odoo -d "$DATABASE" -i "$ODOO_INIT_ADDONS" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --stop-after-init --no-http --load-language "$ODOO_LANGUAGE" "$ODOO_PARAM"
    else
        odoo -d "$DATABASE" -i "$ODOO_INIT_ADDONS" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --stop-after-init --no-http --load-language "$ODOO_LANGUAGE"
    fi
}

function import-csv() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    DATABASE="$1"
    FILE_PATH="$2"

    # Use default database if second param is not given 
    if test -z "$2"; then
        DATABASE="$ODOO_DATABASE"
        FILE_PATH="$1"
    fi

    FILE_NAME=$(basename "$FILE_PATH")
    echo "Importing $FILE_NAME to $DATABASE ..."
    $CONTAINER_ENGINE cp "$FILE_PATH" db:/tmp/
    $CONTAINER_ENGINE exec db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -c "\copy $FILE_NAME FROM '/tmp/$FILE_NAME' DELIMITER ',' CSV HEADER;"
}

function drop-db() {
    DATABASE="$1"
    if [ -z "$DATABASE" ]; then
        DATABASE="$ODOO_DATABASE"
    fi

    $CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/postgres" -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '$DATABASE';"
    $CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/postgres" -c "DROP DATABASE \"$DATABASE\";"
}

function setup-mail() {
    DATABASE="$1"
    if [ -z "$DATABASE" ]; then
        DATABASE="$ODOO_DATABASE"
    fi

    activate-venv
    set-addons-path

    PYTHON_SCRIPT=$(envsubst < scripts/setup-mail)

    echo "Setup mail server configuation for database $DATABASE."
    echo "$PYTHON_SCRIPT" | odoo shell --database "$DATABASE" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --no-http
}

function setup-mail-sql() {
    DATABASE="$1"
    if [ -z "$DATABASE" ]; then
        DATABASE="$ODOO_DATABASE"
    fi

    activate-venv
    set-addons-path

    if [ -n "$ODOO_MAIL_SMTP_HOST" ]; then
        ODOO_MAIL_SMTP_PORT=${ODOO_MAIL_SMTP_PORT:="587"}
        ODOO_MAIL_SMTP_ENCRYPTION=${ODOO_MAIL_SMTP_ENCRYPTION:="starttls"}
        ODOO_MAIL_SMTP_FROM_FILTER=${ODOO_MAIL_SMTP_FROM_FILTER:=""}

        IR_MAIL_SERVER_ID=$($CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -tAc "SELECT id FROM ir_mail_server WHERE name = '$ODOO_MAIL_SMTP_HOST' LIMIT 1")
        if [ -z "$IR_MAIL_SERVER_ID" ]; then
            echo "Setup outgoing mail server $ODOO_MAIL_SMTP_HOST for database $DATABASE."
            $CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -c "INSERT INTO ir_mail_server (active, name, smtp_host, smtp_port, smtp_user, smtp_pass, smtp_encryption, from_filter, smtp_authentication) VALUES (TRUE, '$ODOO_MAIL_SMTP_HOST', '$ODOO_MAIL_SMTP_HOST', $ODOO_MAIL_SMTP_PORT, '$ODOO_MAIL_USERNAME', '$ODOO_MAIL_PASSWORD', '$ODOO_MAIL_SMTP_ENCRYPTION', '$ODOO_MAIL_SMTP_FROM_FILTER', 'login')"
        fi
    fi

    if [ -n "$ODOO_MAIL_IMAP_HOST" ]; then
        ODOO_MAIL_IMAP_PORT=${ODOO_MAIL_IMAP_PORT:="993"}
        ODOO_MAIL_IMAP_SSL=${ODOO_MAIL_IMAP_SSL:="True"}

        FETCHMAIL_SERVER_ID=$($CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -tAc "SELECT id FROM fetchmail_server WHERE name = '$ODOO_MAIL_SMTP_HOST' LIMIT 1")
        if [ -z "$FETCHMAIL_SERVER_ID" ]; then
            echo "Setup incoming mail server $ODOO_MAIL_IMAP_HOST for database $DATABASE."
            $CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -c "INSERT INTO fetchmail_server (\"active\", \"name\", \"server\", \"port\", \"user\", \"password\", \"is_ssl\", \"server_type\", \"state\") VALUES (TRUE, '$ODOO_MAIL_SMTP_HOST', '$ODOO_MAIL_IMAP_HOST', $ODOO_MAIL_IMAP_PORT, '$ODOO_MAIL_USERNAME', '$ODOO_MAIL_PASSWORD', $ODOO_MAIL_IMAP_SSL, 'imap', 'done')"
        fi
    fi

    if [ -n "$MAIL_CATCHALL_ALIAS" ]; then
        MAIL_CATCHALL_ALIAS_VALUE=$($CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -tAc "SELECT value FROM ir_config_parameter WHERE key = 'mail.catchall.alias'")
        if [ "$MAIL_CATCHALL_ALIAS_VALUE" != "$MAIL_CATCHALL_ALIAS" ]; then
            echo "Update system parameter mail.catchall.alias with value $MAIL_CATCHALL_ALIAS."
            $CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -c "UPDATE ir_config_parameter SET value = '$MAIL_CATCHALL_ALIAS' WHERE key = 'mail.catchall.alias'"
        fi
    fi

    if [ -n "$MAIL_DEFAULT_FROM" ]; then
        MAIL_DEFAULT_FROM_VALUE=$($CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -tAc "SELECT value FROM ir_config_parameter WHERE key = 'mail.default.from'")
        if [ "$MAIL_DEFAULT_FROM_VALUE" != "$MAIL_DEFAULT_FROM" ]; then
            echo "Update system parameter mail.default.from with value $MAIL_DEFAULT_FROM."
            $CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -c "UPDATE ir_config_parameter SET value = '$MAIL_DEFAULT_FROM' WHERE key = 'mail.default.from'"
        fi
    fi

    if [ -n "$MAIL_CATCHALL_DOMAIN" ]; then
        MAIL_CATCHALL_DOMAIN_KEY=$($CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -tAc "SELECT id FROM ir_config_parameter WHERE key = 'mail.catchall.domain'")
        if [ -z "$MAIL_CATCHALL_DOMAIN_KEY" ]; then
            echo "Add system parameter mail.catchall.domain with value $MAIL_CATCHALL_DOMAIN."
            $CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -c "INSERT INTO ir_config_parameter (key, value) VALUES ('mail.catchall.domain', '$MAIL_CATCHALL_DOMAIN')"
        fi
        MAIL_CATCHALL_DOMAIN_VALUE=$($CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -tAc "SELECT value FROM ir_config_parameter WHERE key = 'mail.catchall.domain'")
        if [ "$MAIL_CATCHALL_DOMAIN_VALUE" != "$MAIL_CATCHALL_DOMAIN" ]; then
            echo "Update system parameter mail.catchall.domain with value $MAIL_CATCHALL_DOMAIN."
            $CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -c "UPDATE ir_config_parameter SET value = '$MAIL_CATCHALL_DOMAIN' WHERE key = 'mail.catchall.domain'"
        fi
    fi
}

function load-language() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    DATABASE="$1"
    LANGUAGE="$2"

    # Use default database if second param is not given 
    if test -z "$2"; then
        DATABASE="$ODOO_DATABASE"
        LANGUAGE="$1"
    fi

    activate-venv
    set-addons-path
    echo "Setup language $LANGUAGE for database $DATABASE:"
    odoo -d "$DATABASE" -u all --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --stop-after-init --no-http --load-language "$LANGUAGE" 
}

function set-admin() {
    DATABASE="$1"
    if [ -z "$DATABASE" ]; then
        DATABASE="$ODOO_DATABASE"
    fi

    $CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -c "UPDATE res_users SET active=true,password='\$pbkdf2-sha512\$25000\$JuScEwIg5JzTGqNUivFeqw\$yWTOcix2Afr3XGP2NPY7w4w49e9vpsu14NRndDYXAkbtMF4zkrmx6inVsoLl0zZY30xI/0GzhwonWsK9TUmjWA' WHERE id=2;"
    $CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost:5432/$DATABASE" -c "SELECT login, password FROM res_users WHERE id=2;"
}

function clear-assets() {
    DATABASE="$1"
    if [ -z "$DATABASE" ]; then
        DATABASE="$ODOO_DATABASE"
    fi

    echo "Delete these assets for $DATABASE:"
    $CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost/$DATABASE" -c "select id,name from ir_attachment where res_model='ir.ui.view' and name like '%assets_%';"
    $CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost/$DATABASE" -c "delete from ir_attachment where res_model='ir.ui.view' and name like '%assets_%';"
}

function clear-views() {
    DATABASE="$1"
    if [ -z "$DATABASE" ]; then
        DATABASE="$ODOO_DATABASE"
    fi

    echo "Archive views with prefix 'mint_system'."
    $CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost/$DATABASE" -c  "SELECT id,name from ir_ui_view WHERE name like '%mint_system%';"
    $CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost/$DATABASE" -c  "UPDATE ir_ui_view SET active=false WHERE name like '%mint_system%';"

    echo "Archive views with prefix 'Odoo Studio:'."
    $CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost/$DATABASE" -c  "SELECT id,name from ir_ui_view WHERE name like '%Odoo Studio:%';"
    $CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost/$DATABASE" -c  "UPDATE ir_ui_view SET active=false WHERE name like '%Odoo Studio:%';"

    echo "Delete all active views for $DATABASE in $CONTAINER :"
    $CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost/$DATABASE" -c  "DELETE FROM report_layout WHERE view_id IN (SELECT id FROM ir_ui_view WHERE active = TRUE);"
    $CONTAINER_ENGINE exec -i db psql "postgres://odoo:odoo@localhost/$DATABASE" -c  "WITH RECURSIVE views_to_delete AS (SELECT id, inherit_id FROM ir_ui_view WHERE active = TRUE AND inherit_id IS NULL UNION ALL SELECT v.id, v.inherit_id FROM ir_ui_view v JOIN views_to_delete p ON v.inherit_id = p.id) DELETE FROM ir_ui_view WHERE id IN (SELECT id FROM views_to_delete);"
}

function convert-database() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    unzip "tmp/$1.zip" -d "./tmp/$1"
    sed -i'' 's/AS integer//g' "./tmp/$1/dump.sql"
    grep -i 'as integer' "./tmp/$1/dump.sql"
    cd "tmp/$1" || exit ; zip -r "../${1}2.zip" . ; cd ../.. || exit
    rm -r "tmp/$1"
    echo "Converted database file $1 to ${1}2"
}

function clear-filestore() {
    echo "Remove directory $HOME/.local/share/Odoo/filestore/$1"
    rm -rf "$HOME/.local/share/Odoo/filestore/$1"
}

function disable-mailserver() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    activate-venv
    load-env "$1"
    scripts/odooctl --method 'write' --model 'ir.mail_server' --field 'active' --value False --domain "[]"
    scripts/odooctl --method 'write' --model 'fetchmail.server' --field 'active' --value False --domain "[]"
}

function change-uuid() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    activate-venv
    load-env "$1"
    UUID=$(uuidgen)
    echo "Set uuid $UUID for $1."
    scripts/odooctl --method 'write' --model 'ir.config_parameter' --domain "[('key', '=', 'database.uuid')]" --field	'value' --value "'$UUID'"
}

function update-app-list() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    activate-venv
    set-addons-path
    echo "env['ir.module.module'].update_list()" | odoo shell --database "$1" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --no-http
}

function patch-database() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    DATABASE="$1"
    FILENAME="$2"

    # Use default database if second param is not given 
    if test -z "$2"; then
        DATABASE="$ODOO_DATABASE"
        FILENAME="$1"
    fi

    echo "Apply patch $FILENAME to Database $DATABASE."
    cat "$FILENAME" | $CONTAINER_ENGINE exec -i db psql "postgres://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost/$DATABASE"
    echo "Patching database succeeded"
}

function save-config() {
    DATABASE="$1"
    if [ -z "$DATABASE" ]; then
        DATABASE="$ODOO_DATABASE"
    fi

    activate-venv
    set-addons-path
    odoo -d "$DATABASE" -s --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --stop-after-init --no-http
}

# Report Commands

function odoo-cloc() {
    DATABASE="$1"
    if [ -z "$DATABASE" ]; then
        DATABASE="$ODOO_DATABASE"
    fi

    activate-venv
    set-addons-path
    odoo cloc -d "$DATABASE" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --stop-after-init --no-http
}

function visualize-dependencies() {

    if test -z "$1"; then echo "\$1 is empty."; exit; fi
    
    MODULE_DIR="$1"
    OUTPUT_FILE="tmp/module_dependencies.mmd"
    mkdir -p tmp
    echo "graph TD" > "$OUTPUT_FILE"

    for MODULE_PATH in "$MODULE_DIR"/*; do
        if [[ -d "$MODULE_PATH" ]]; then
            MODULE_NAME=$(basename "$MODULE_PATH")
            MANIFEST_FILE="$MODULE_PATH/__manifest__.py"
            if [[ -f $MANIFEST_FILE ]]; then
                DEPENDENCIES=$(grep -Po '(?<="depends": \[)[^\]]*' "$MANIFEST_FILE" | tr -d '"[] ')
                if [[ -n "$DEPENDENCIES" ]]; then
                    for DEPENDENCY in $(echo "$DEPENDENCIES" | tr ',' '\n'); do
                        echo "  $MODULE_NAME --> $DEPENDENCY" >> "$OUTPUT_FILE"
                    done
                fi
            fi
        fi
    done

    echo "Mermaid output generated: $OUTPUT_FILE"
    echo "Run mermaid-cli with npx and open png file ..."

    npx @mermaid-js/mermaid-cli -i $OUTPUT_FILE -o tmp/module_dependencies.png --scale 10
    $OS_OPEN tmp/module_dependencies.png
}

# Module Development Commands

function install-requirements() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    DATABASE="$1"
    FILE_PATH="$2"

    # Use default database if second param is not given 
    if test -z "$2"; then
        DATABASE="$ODOO_DATABASE"
        FILE_PATH="$1"
    fi

    FILE_NAME=$(basename "$FILE_PATH")
    if [[ "$FILE_NAME" != "requirements.txt" ]]; then echo "\$1 must point to requirements.txt file."; exit; fi

    CONTAINER_RUNNING=$($CONTAINER_ENGINE container inspect -f '{{.State.Running}}' odoo)
    if [ "$CONTAINER_RUNNING" == "true" ]; then
        echo "Installing python packages in container ..."
        $CONTAINER_ENGINE exec -u root odoo python -m pip install -r "/mnt/$FILE_PATH"
    else
        activate-venv
        echo "Installing python packages in virutal env ..."
        uv pip install -r "$FILE_PATH"
    fi
}

function init-module() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    DATABASE="$1"
    MODULE_PATH="$2"

    # Use default database if second param is not given 
    if test -z "$2"; then
        DATABASE="$ODOO_DATABASE"
        MODULE_PATH="$1"
    fi

    # Check if module path is a module repo
    if [ -f "$MODULE_PATH/README.md" ]; then
        
        # Look for manifest files in repo folder
        # Get parent folder name of manifest files
        # Create a comma separated string of folder names
        MODULES=$(get-modules "$MODULE_PATH" basename)
    else
        MODULES=$(basename "$MODULE_PATH")
    fi

    activate-venv
    set-addons-path
    echo "Initialize module $MODULES on $DATABASE ..."
    odoo -d "$DATABASE" -i "$MODULES" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --stop-after-init --no-http
}

function upgrade-module() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi
    if test -z "$2"; then echo "\$2 is empty."; exit; fi

    activate-venv
    echo "Upgrade code of module $1 from $2 ..."
    odoo upgrade_code --addons-path "$1" --from "$2"
}

function update-module() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    DATABASE="$1"
    MODULE_NAME=$(basename "$2")

    # Use default database if second param is not given 
    if test -z "$2"; then
        DATABASE="$ODOO_DATABASE"
        MODULE_NAME=$(basename "$1")
    fi

    activate-venv
    set-addons-path
    echo "Updating module $MODULE_NAME on $DATABASE ..."
    if [[ -n "$ODOO_PARAM" ]] ; then
        odoo --database "$DATABASE" --update "$MODULE_NAME" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --stop-after-init --no-http "$ODOO_PARAM"
    else
        odoo --database "$DATABASE" --update "$MODULE_NAME" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --stop-after-init --no-http
    fi
}

function translate-module() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    DATABASE="$1"
    MODULE_PATH="$2"
    MODULE_NAME=$(basename "$2")
    LANGUAGE="$3"    

    if test -z "$2"; then
        DATABASE="$ODOO_DATABASE"
        MODULE_PATH="$1"
        MODULE_NAME=$(basename "$1")
    fi

    if test -z "$3"; then
        LANGUAGE="$ODOO_LANGUAGE"
    fi

    activate-venv
    set-addons-path
    echo "Generate $LANGUAGE tranlsation file for $MODULE_NAME on $DATABASE ..."
    mkdir -p "$MODULE_PATH/i18n/"
    odoo -d "$DATABASE" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --modules "$MODULE_NAME" -l "$LANGUAGE" --i18n-export "$MODULE_PATH/i18n/$LANGUAGE.po"
    # if lang is de_CH then rename the file to de.po.
    if [[ "$LANGUAGE" == "de_CH" ]]; then
        mv "$MODULE_PATH/i18n/$LANGUAGE.po" "$MODULE_PATH/i18n/de.po"
    fi
}

function lint-module() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi
    activate-venv
    
    echo "Set file and folder permissions on $1"
    find "$1" -type d -exec chmod u=rwx,go=rx {} \;
    find "$1" -type f -exec chmod u=rw,go=r {} \;

    echo "Update index.html"
    rst2html5 "$1/README.rst"  "$1/static/description/index.html"

    pushd . 
    cd "$1"

    echo "Run pre-commit in $PWD"
    pre-commit run --all-files # --show-diff-on-failure --color=always

    echo "Stage changes"
    git  add .

    popd
}

function lint-module-repo() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    MODULE_PATHS=$(get-modules "$MODULE_PATH")

    for MODULE_PATH in ${MODULE_PATHS//,/ }; do 
        lint-module "$MODULE_PATH"
    done
}

function test-module() {
    DATABASE="$1"
    MODULE_NAME=$(basename "$2")

    # Use default database if second param is not given 
    if test -z "$2"; then
        DATABASE="$ODOO_DATABASE"
        MODULE_NAME=$(basename "$1")
    fi

    activate-venv
    set-addons-path
    echo "Testing module $MODULE_NAME on $DATABASE ..."
    odoo -d "$DATABASE" -i "$MODULE_NAME" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --stop-after-init --no-http --test-tags /"$MODULE_NAME"
}

function test-module-repo() {
    DATABASE="$1"
    MODULE_PATH="$2"

    # Use default database if second param is not given 
    if test -z "$2"; then
        DATABASE="$ODOO_DATABASE"
        MODULE_PATH="$1"
    fi

    MODULES=$(get-modules "$MODULE_PATH" basename)

    for MODULE in ${MODULES//,/ }; do 
        echo "Testing module $MODULE ..."
        test-module "$DATABASE" "$MODULE"
    done
}

function pytest-module() {
    DATABASE="$1"
    MODULE_PATH="$2"

    # Use default database if second param is not given 
    if test -z "$2"; then
        DATABASE="$ODOO_DATABASE"
        MODULE_PATH="$1"
    fi

    activate-venv
    set-addons-path

    ODOO_CONFIG="tmp/odoo.conf"
    echo "Write $ODOO_CONFIG"

    echo "[options]" > "$ODOO_CONFIG"
    echo "addons_path=$ADDONS_PATH" >> "$ODOO_CONFIG"
    echo "db_host = localhost" >> "$ODOO_CONFIG"
    echo "db_password = odoo" >> "$ODOO_CONFIG"
    echo "db_user = odoo" >> "$ODOO_CONFIG"
    
    pytest -s --odoo-http --odoo-config="$ODOO_CONFIG" --odoo-database="$DATABASE" "$MODULE_PATH"
}

function remove-module() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    DATABASE="$1"
    MODULE_NAME=$(basename "$2")

    # Use default database if second param is not given 
    if test -z "$2"; then
        DATABASE="$ODOO_DATABASE"
        MODULE_NAME=$(basename "$1")
    fi

    activate-venv
    set-addons-path
    echo "Remove module $MODULE_NAME"
    echo "self.env['ir.module.module'].search([('name', '=', '$MODULE_NAME')]).button_immediate_uninstall()" |
    odoo shell --database "$DATABASE" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --no-http
}

function create-module() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    MODULE_NAME=$(basename "$1")
    PARENT_DIR=$(dirname "$1")

    activate-venv
    echo "Scaffolding module $MODULE_NAME in $PARENT_DIR ..."
    odoo scaffold "$MODULE_NAME" "$PARENT_DIR" -t templates/module
}

function create-module-repo() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    REPO_PATH="$1"
    REPO_NAME=$(basename "$REPO_PATH")

    # If repo already exists, create new branch
    if [ -d "$REPO_PATH/.git" ]; then
        echo "Create new branch $REPO_NAME in $REPO_PATH"
        cd "$REPO_PATH" || exit
        git switch --orphan -c "$GIT_BRANCH"

        echo "Remove all files from $REPO_PATH"
        rm -rf "$REPO_PATH/*"
    fi

    echo "Copy template files from templates/GIT_BRANCH to $REPO_PATH"
    cp templates/GIT_BRANCH/* "$REPO_PATH"
}

function generate-module-security() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi
    if test -z "$2"; then echo "\$2 is empty."; exit; fi

    MODULE_NAME=$(basename "$1")
    PARENT_DIR=$(dirname "$1")
    MODEL_DOT_NAME="$2"
    MODEL_NAME=$(echo "$MODEL_DOT_NAME" | tr '.' '_')

    ACCESS_FILE="$PARENT_DIR/$MODULE_NAME/security/ir.model.access.csv"
    mkdir -p "$PARENT_DIR/$MODULE_NAME/security"

    if [ ! -f "$ACCESS_FILE" ]; then
        echo "Init security file: $ACCESS_FILE"
        echo "id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink" > "$ACCESS_FILE"
    fi

    # id
    # name
    # model_id:id
    # group_id:id
    # perm_read
    # perm_write
    # perm_create
    # perm_unlink

    echo "Add model access to $ACCESS_FILE"
    echo "access_${MODEL_NAME}_user,access.$MODEL_DOT_NAME.user,model_${MODEL_NAME},base.group_user,1,0,0,0" >> "$ACCESS_FILE"
    echo "access_${MODEL_NAME}_manager,access.$MODEL_DOT_NAME.manager,model_${MODEL_NAME},base.group_erp_manager,1,1,1,1" >> "$ACCESS_FILE"
}

function generate-module-model() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi
    if test -z "$2"; then echo "\$2 is empty."; exit; fi

    MODULE_PATH="$1"
    MODULE_NAME=$(basename "$1")

    # Generate template values
    MODEL_DOT_NAME="$2" # res.partner
    MODEL_NAME=$(echo "$MODEL_DOT_NAME" | tr '.' '_') # res_partner
    NAME=$(echo "$MODEL_DOT_NAME" | cut -d"." -f2  | sed 's/[^_]\+/\L\u&/g') # Partners
    MODEL_DESCRIPTION=$(echo "$MODEL_NAME" | sed 's/[^_]\+/\L\u&/g' | sed 's/_/ /g') # Res Partner
    MODEL_CAMEL_NAME=$(echo "$MODEL_DESCRIPTION" | sed 's/ //g') # ResPartner
    export NAME MODULE_NAME MODEL_DOT_NAME MODEL_NAME MODEL_DESCRIPTION MODEL_CAMEL_NAME
    
    echo "Substitute model template"
    envsubst '$NAME $MODULE_NAME $MODEL_DOT_NAME $MODEL_NAME $MODEL_DESCRIPTION $MODEL_CAMEL_NAME' < templates/model.py > "$MODULE_PATH/models/$MODEL_NAME.py"
    echo "from . import $MODEL_NAME" >> "$MODULE_PATH/models/__init__.py"

    echo "Substitute view template"
    mkdir -p "$MODULE_PATH/views"
    envsubst '$NAME $MODULE_NAME $MODEL_DOT_NAME $MODEL_NAME $MODEL_DESCRIPTION $MODEL_CAMEL_NAME' < templates/model_views.xml > "$MODULE_PATH/views/${MODEL_NAME}_views.xml"
    echo "Update file $MODULE_NAME/__manifest__.py with:"
    echo -e "\t\"views/${MODEL_NAME}_views.xml\","
}

function generate-module-snippet() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi
    if test -z "$2"; then echo "\$2 is empty."; exit; fi

    MODULE_PATH="$1"
    VIEW_REF="$2"

    # Generate template values
    MODEL_NAME="crm_lead"
    MODEL_DOT_NAME="crm.lead"
    MODULE_NAME=$(basename "$1")
    SRC_MODULE_NAME=$(echo "$VIEW_REF" | cut -d"." -f1) 
    XML_ID=$(echo "$VIEW_REF" | cut -d"." -f1) 
    export MODULE_NAME MODEL_DOT_NAME SRC_MODULE_NAME XML_ID

    echo "Substitute snippet template"
    envsubst '$MODULE_NAME $MODEL_DOT_NAME $SRC_MODULE_NAME $XML_ID' < templates/model_snippet.xml > "$MODULE_PATH/views/$MODEL_NAME_views.xml"
    echo "Update file $MODULE_NAME/__manifest__.py with:"
    echo -e "\t, \"views/${MODEL_NAME}_views.xml\""
}

function release-module() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    VERSION=$(get-module-version "$1")
    cd "$1" || exit
    LAST_TAG=$(git describe --tags)
    RELEASE_NOTES=$(git log "$LAST_TAG"..HEAD --oneline)

    echo "Tag with v$VERSION ..."
    git tag -a "v$VERSION" -m "v$VERSION"

    echo "Release notes:"
    echo "$RELEASE_NOTES"
}

function zip-module() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    # Get version and module name
    VERSION=$(get-module-version "$1")
    MODULE=$(basename "$1")

    # Copy module to tmp folder
    echo "Copy module $MODULE version $VERSION to tmp folder"
    MODULE_NAME="$MODULE-$VERSION"
    MODULE_PATH="tmp/$MODULE_NAME"
    rm -rf "$MODULE_PATH"
    mkdir -p "$MODULE_PATH"
    cp -r "$1/." "$MODULE_PATH"
    find "$MODULE_PATH" -type d -exec chmod u=rwx,go=rx {} \;
    find "$MODULE_PATH" -type f -exec chmod u=rw,go=r {} \;

    # Configure and zip module
    echo "Remove auto install option"
    sed -i'' -e "s/'auto_install': True,/'auto_install': False,/" "$MODULE_PATH/__manifest__.py"
    echo "Remove pycache and hidden folders"
    find "$MODULE_PATH" | grep -E "(\.git|__pycache__|\.pyc|\.pyo$)" | xargs rm -rf
    echo "Zip module $MODULE"
    cd tmp || exit
    rm -f "$MODULE_NAME".zip
    zip -q -r "$MODULE_NAME".zip "$MODULE_NAME"
    cd .. || exit
}

# Snippet Commands

function reset-views() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    DATABASE="$1"
    KEY=$(basename "$2")

    # Use default database if second param is not given 
    if test -z "$2"; then
        DATABASE="$ODOO_DATABASE"
        KEY=$(basename "$1")
    fi

    activate-venv
    set-addons-path
    echo "Reset views for key $KEY"
    echo "self.env['ir.ui.view'].search([('key', 'ilike', '$KEY')]).reset_arch(mode='hard')" |
    odoo shell --database "$DATABASE" --config "$ODOO_RC" --addons-path="$ADDONS_PATH" --no-http
}

function create-snippet() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    export INHERIT_ID=$(echo "$1" | cut -d. -f1-2)
    FILE="snippets/$1.xml"

    echo "Create snippet from template: $FILE"
    envsubst '$INHERIT_ID' < templates/snippet.xml > "$FILE"
}

function install-snippet() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi
    if test -z "$2"; then echo "\$2 is empty."; exit; fi

    # Generate view name from filename
    FILE=$(basename "$2")
    NAME="mint_system.${FILE%.xml}"
    INHERIT_ID=$(echo 'cat //data/@inherit_id' | xmllint --shell "$2" | awk -F'[="]' '!/>/{print $(NF-1)}')
    TYPE=$(echo 'cat //data/@type' | xmllint --shell "$2" | awk -F'[="]' '!/>/{print $(NF-1)}')
    MODEL=$(echo 'cat //data/@model' | xmllint --shell "$2" | awk -F'[="]' '!/>/{print $(NF-1)}')
    PRIORITY=$(echo 'cat //data/@priority' | xmllint --shell "$2" | awk -F'[="]' '!/>/{print $(NF-1)}')
    MODULE_NAME=$(echo "$INHERIT_ID" | cut -d. -f 1 )
    XML_ID=$(echo "$INHERIT_ID" | cut -d. -f 2 )

    # Set default values
    : ${TYPE:='qweb'}

    activate-venv
    load-env "$1"
    echo "Search for view with name $MODULE_NAME.$XML_ID"
    INHERIT_ID=$(scripts/odooctl --method "read" --model "ir.model.data" --field "res_id" --domain "[('name', '=', '$XML_ID'), ('module', '=', '$MODULE_NAME')]")
    echo "Found view id $INHERIT_ID"
    
    echo "Apply view $NAME"
    scripts/odooctl --method 'create' --model 'ir.ui.view' --value "{ 
        'name': '$NAME',
        'type': '$TYPE',
        'model': '$MODEL',
        'mode': 'extension',
        'priority': $PRIORITY, 
        'inherit_id': $INHERIT_ID, 
        'arch_base': '''$(cat "$2")'''
    }"
}

function update-snippet() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi
    if test -z "$2"; then echo "\$2 is empty."; exit; fi

    # Generate view name from filename
    FILE=$(basename "$2")
    NAME="mint_system.${FILE%.xml}"

    activate-venv
    load-env "$1"
    echo "Update view with name $NAME"
    scripts/odooctl --method 'write' --model 'ir.ui.view' --domain "[('name', '=', '$NAME')]" --field 'arch_base' --value "'''$(cat "$2")'''"
}

function disable-snippet() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi
    if test -z "$2"; then echo "\$2 is empty."; exit; fi

    # Generate view name from filename
    FILE=$(basename "$2")
    NAME="mint_system.${FILE%.xml}"

    activate-venv
    load-env "$1"
    echo "Disable view with name $NAME"
    scripts/odooctl --method 'write' --model "ir.ui.view" --domain "[('name', '=', '$NAME')]" --field "active" --value "False"
}

function remove-snippet() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi
    if test -z "$2"; then echo "\$2 is empty."; exit; fi

    # Generate view name from filename
    FILE=$(basename "$2")
    NAME="mint_system.${FILE%.xml}"

    activate-venv
    load-env "$1"
    echo "Remove view with name $NAME"
    scripts/odooctl --method "unlink" --model "ir.ui.view" --domain "[('name', '=', '$NAME')]"
}

function lint-snippets() {

    echo "Lint snippets files ..."

    FILES="snippets/*.xml"

    for FILE in $FILES; do

        # Access various snippet parameters
        FILENAME=$(basename "$FILE")
        SNIPPET_MODULE=$(echo "$FILENAME" | cut -d. -f1)
        REPORT=$(echo "$FILENAME" | cut -d. -f2)
        EDIT=$(echo "$FILENAME" | cut -d. -f3)
        INHERIT_ID=$(echo 'cat //data/@inherit_id' | xmllint --shell "$FILE" | awk -F'[="]' '!/>/{print $(NF-1)}')
        TYPE=$(echo 'cat //data/@type' | xmllint --shell "$FILE" | awk -F'[="]' '!/>/{print $(NF-1)}')
        MODEL=$(echo 'cat //data/@model' | xmllint --shell "$FILE" | awk -F'[="]' '!/>/{print $(NF-1)}')
        PRIORITY=$(echo 'cat //data/@priority' | xmllint --shell "$FILE" | awk -F'[="]' '!/>/{print $(NF-1)}')
        MODULE_NAME=$(echo "$INHERIT_ID" | cut -d. -f 1 )
        XML_ID=$(echo "$INHERIT_ID" | cut -d. -f 2 )

        # Check filename 
        COUNT_DOTS=$(echo "$FILENAME" | grep -o "\." | wc -l)
        if [ "$COUNT_DOTS" -ge 4 ]; then
            echo "Linting failed for $FILE"
            echo "Dots count: $COUNT_DOTS"
            echo "  Filename: $SNIPPET_MODULE.$REPORT"
            exit 1
        fi

        # Check if inherit id matches the filename
        if [ -n "$INHERIT_ID" ]; then
            if [[ "$INHERIT_ID" != "$SNIPPET_MODULE.$REPORT" ]]; then
                echo "Linting failed for $FILE"
                echo " Inherit: $INHERIT_ID"
                echo "Filename: $SNIPPET_MODULE.$REPORT"
                exit 1
            fi
        fi

        # Check if priority is set
        if [ -z "$PRIORITY" ] && [ -n "$INHERIT_ID" ]; then
            echo "Linting failed for $FILE"
            echo "No priority is set."
            exit 1
        fi
    done
    echo "No problems with snippets found."
}

# Git Commands

function git-fetch() {
    git fetch origin 13.0
    git fetch origin 14.0
    git fetch origin 15.0
    git fetch origin 16.0
    git fetch origin 17.0
    git fetch origin 18.0
}

function git-submodule-add() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi
    if test -z "$2"; then echo "\$2 is empty."; exit; fi

    git submodule add -f -b "$GIT_BRANCH" "$1" "$2"
}

function git-submodule-ls() {
    echo $(git config --file .gitmodules --get-regexp url | sed -e 's/submodule.//g' -e 's/.url.*//g')
}

function git-submodule-list() {
    # git submodule foreach --quiet 'printf "%-30s %-20s\n" "$name" "$(git rev-parse --abbrev-ref HEAD)"'
    git config --file .gitmodules --get-regexp url | sed -e 's/submodule.//g' -e 's/.url//g' | awk '{ print $1 "," $2}'
}

function git-submodule-delete() {
    echo "Delete git submodules."

    # Using "git submodule update --init --recursive" is not possible as modules are registered from different branches
    SUBMODULES=$(git-submodule-ls)
    for SUBMODULE in $SUBMODULES; do
        echo "Delete submodule: $SUBMODULE"
        rm -rf "$SUBMODULE"
    done
}

function git-submodule-remove() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    echo "Deinit submodule"
    git submodule deinit -f "$1"
    
    echo "Move submodule to tmp folder"
    mkdir -p tmp/"$1"
    mv "$1" tmp/"$1"

    echo "Remove submodule from work tree"
    git rm -f "$1"

    echo "Remove submodule from .git folder"
    rm -rf .git/modules/"$1"
}

function git-submodule-init() {
    echo "Init git submodules."

    # Using "git submodule update --init --recursive" is not possible as modules are registered from different branches
    SUBMODULES=$(git-submodule-ls)
    for SUBMODULE in $SUBMODULES; do
        SHALLOW=$(git config --file .gitmodules --get-regexp submodule."$SUBMODULE".shallow | awk '{ print $2 }')
        if [ "$SHALLOW" = "true" ]; then
            echo "Initializing submodule: $SUBMODULE (shallow)"
            git submodule update --init --depth 1 "$SUBMODULE"
        else
            echo "Initializing submodule: $SUBMODULE"
            git submodule update --init "$SUBMODULE"
        fi
    done
}

function git-submodule-pull() {
    echo "Pull git submodules"
    SUBMODULES=$(git-submodule-ls)
    for SUBMODULE in $SUBMODULES; do
        echo "Pull git submodule: $SUBMODULE"
        git -C "$SUBMODULE" stash
        UPDATE=$(git config submodule."$SUBMODULE".update)
        if [ -z "$UPDATE" ]; then
            git -C "$SUBMODULE" pull origin "$GIT_BRANCH"
        fi;
    done
}

function git-submodule-checkout() {
    echo "Checkout submodule commits."
    SUBMODULES=$(git-submodule-ls)
    for SUBMODULE in $SUBMODULES; do
        SHALLOW=$(git config --file .gitmodules --get-regexp submodule."$SUBMODULE".shallow | awk '{ print $2 }')
        COMMIT_HASH=$(git ls-tree HEAD "$SUBMODULE" | awk '{print $3}')
        if [ "$SHALLOW" = "true" ]; then
            echo "Update git submodule: $SUBMODULE (shallow)"
            git -C "$SUBMODULE" stash
            git -C "$SUBMODULE" fetch origin "$COMMIT_HASH"
            git -C "$SUBMODULE" checkout "$COMMIT_HASH"
        else
            echo "Update git submodule: $SUBMODULE"
            git -C "$SUBMODULE" stash
            git -C "$SUBMODULE" checkout "$COMMIT_HASH"
        fi
    done
}

function git-submodule-switch() {
    if [ -n "$1" ]; then
        GIT_BRANCH="$1"
    fi

    echo "Switch branch on git submodules."
    SUBMODULES=$(git-submodule-ls)
    for SUBMODULE in $SUBMODULES; do
        echo "Switch git submodule branch to $GIT_BRANCH: $SUBMODULE"
        git -C "$SUBMODULE" stash
        git -C "$SUBMODULE" switch "$GIT_BRANCH"
    done
}

function git-submodule-sync() {
    echo "Switch and pull submodules."
    git-submodule-switch
    git-submodule-pull
}

function git-feature-branch(){
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    MODULE_NAME=$(basename "$1")
    MODULE_PATH=$(dirname "$1")

    echo "Create feature branch for $MODULE_NAME in $MODULE_PATH ..."
    cd ./"$MODULE_PATH" || exit
    pwd
    git switch -c "feature-$MODULE_NAME"
}

function git-mig-branch(){
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    MODULE_NAME=$(basename "$1")
    MODULE_PATH=$(dirname "$1")

    echo "Create mig branch for $MODULE_NAME in $MODULE_PATH ..."
    cd ./"$MODULE_PATH" || exit
    pwd
    git switch -c "$GIT_BRANCH-mig-$MODULE_NAME"
}

function checkout-config-files() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    echo "Checkout config files $1 branch."
    git checkout "$1" .git-checkout-files .git-reset-files

    echo "Remove reset files."
    git rm -r $(tr '\n' ' ' < ./.git-reset-files) >/dev/null 2>&1

    echo "Sync checkout files from $1 branch."
    git checkout "$1" $(tr '\n' ' ' < ./.git-checkout-files)
}

function checkout() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi
    GIT_BRANCH="$1"

    echo "Switch current branch to $GIT_BRANCH."
    git switch "$GIT_BRANCH"
    git pull

    git-submodule-init

    git-submodule-switch
}

# Revision Commands

function list-revision() {
    ls scripts/odoo_revision_* | sed 's/scripts\/odoo_revision_//g'
}

function show-revision() {
    if [ -n "$1" ]; then
        ODOO_REVISION="$1"
    fi
    ODOO_VERSION=$(echo "$ODOO_REVISION" | cut -d'.' -f1-2)

    echo "Load refs for revision: $ODOO_REVISION"
    source "scripts/odoo_revision_$ODOO_REVISION"

    echo "Odoo Ref: $ODOO_REF"
    echo "Odoo Enterprise Ref: $ODOO_ENTERPRISE_REF"
    echo "Odoo Themes Ref: $ODOO_THEME_REF"
    echo "Odoo Image Ref: $ODOO_IMAGE_REF"
}

function checkout-revision() {
    if [ -n "$1" ]; then
        ODOO_REVISION="$1"
    fi
    ODOO_VERSION=$(echo "$ODOO_REVISION" | cut -d'.' -f1-2)

    echo "Update revision var in .env file."
    if grep -q "ODOO_REVISION" .env; then
        sed -i -e "s/^ODOO_REVISION=.*/ODOO_REVISION=${ODOO_REVISION}/" .env
    else
        echo "ODOO_REVISION=${ODOO_REVISION}" >> .env
    fi

    echo "Load refs for revision: $ODOO_REVISION"
    export $(cat "scripts/odoo_revision_$ODOO_REVISION" | sed 's/#.*//g' | xargs)

    echo "Checkout and tag git repos ..."
    git -C odoo checkout $ODOO_REF
    git -C odoo tag -a $ODOO_REVISION -m "$ODOO_REVISION"
    git -C enterprise checkout $ODOO_ENTERPRISE_REF
    git -C enterprise tag -a $ODOO_REVISION -m "$ODOO_REVISION"
    git -C themes checkout $ODOO_THEME_REF
    git -C themes tag -a $ODOO_REVISION -m "$ODOO_REVISION"


    if $ODOO_REVISION_CONTAINER_PULL; then

        echo "Pull container image ..."
        $CONTAINER_ENGINE pull "$ODOO_IMAGE_REF"
        IMAGE_ID=$($CONTAINER_ENGINE image inspect "$ODOO_IMAGE_REF" --format "{{ .ID }}")

        echo "Tag container image with odoo:$ODOO_REVISION"
        $CONTAINER_ENGINE tag "$IMAGE_ID" odoo:$ODOO_REVISION
    fi
}

function create-revision() {
    if test -z "$1"; then echo "\$1 is empty."; exit; fi

    REVISION="$1" # 16.0.20241029
    ODOO_VERSION=$(echo "$REVISION" | cut -d'.' -f1-2)
    ODOO_DATE=$(echo "$REVISION" | cut -d'.' -f3-)
    BEFORE_DATE=$(date -d "$ODOO_DATE -1 day" +"%Y-%m-%d")
    
    # Pull container image with revision
    IMAGE=odoo:"$ODOO_VERSION-$ODOO_DATE"
    $CONTAINER_ENGINE pull "$IMAGE"
    CONTAINER_REF=$($CONTAINER_ENGINE inspect --format='{{index .RepoDigests 0}}' "$IMAGE")

    # Get git commit by date
    cd odoo
    REF=$(git rev-list -n 1 --before="$BEFORE_DATE" origin/$ODOO_VERSION)
    git checkout "$REF"
    cd ..
    cd enterprise
    ENTERPRISE_REF=$(git rev-list -n 1 --before="$BEFORE_DATE" origin/$ODOO_VERSION)
    git checkout "$ENTERPRISE_REF"
    cd ..
    cd themes
    THEME_REF=$(git rev-list -n 1 --before="$BEFORE_DATE" origin/$ODOO_VERSION)
    git checkout "$THEME_REF"
    cd ..

    echo "Create revision: $REVISION"
    export REVISION REF ENTERPRISE_REF THEME_REF CONTAINER_REF
    envsubst '$REVISION $REF $ENTERPRISE_REF $THEME_REF $CONTAINER_REF' < templates/odoo_revision > scripts/odoo_revision_"$REVISION"
    chmod +x scripts/odoo_revision_"$REVISION"

    echo "Checkout revision: $REVISION"
    checkout-revision "$REVISION"
}

# RPC Commands

function test-xmlrpc() {
    if test -z "$1"; then echo "\$1 is empty."; exit 1; fi

    activate-venv
    load-env "$1"

    echo "Connect to database and count res.partner records: $(scripts/odooctl --model "res.partner" --method "search_count" --domain '[]')"
}

# Pass Commands

function pass-store-dotenv() {
    if [ -f .env ]; then
        echo "Store .env file in pass: $PASS_ENTRY"
        cat .env | pass insert -m -f "$PASS_ENTRY"
    else
        echo "No .env file found."
    fi
}

function pass-restore-dotenv() {
    if pass find "$PASS_ENTRY" >/dev/null; then
        echo "Restore .env file from pass: $PASS_ENTRY"
        pass show "$PASS_ENTRY" > .env
    else
        echo "Pass entry not found."
    fi
}

# LLM Commands

function llm-update() {
    if test -z "$1"; then 
        echo "\$1 is empty."; 
        exit 1; 
    fi

    # Get list of files
    FILES=$(find "$1" -type f \( -name "*.py" -o -name "*.xml" \))

    echo -e "Loaded these files into prompt:\n\n$FILES\n"

    # Get task description
    read -p "Enter the task description: " TASK_DESCRIPTION

    # Prepare the files content for prompt
    FILE_CONTENTS=""
    for file in $FILES; do
        FILE_CONTENTS+="<<< $file >>>
$(cat "$file")

"
    done

    # Define the prompt
    PROMPT="EOF
Look at the code files below and do the following:

$TASK_DESCRIPTION

Output your response in the format of a git patch file. The patch should include only the changes to the files, and it should be applicable with 'git apply'. Do not include any explanations or extra information outside of the patch format.

Here are the files:

$FILE_CONTENTS
EOF"

    # Run the llm command with the prompt
    echo -e "\nWait for the response of the $LLM_MODEL llm."
    RESULT=$(llm -m "$LLM_MODEL" "$PROMPT")

    # Check if the result is empty
    if test -z "$RESULT"; then
        echo "No response from the model. Exiting."
        exit 1
    fi

    # Save the patch to a file
    PATCH_FILE="tmp/llm_changes.patch"
    echo "$RESULT" > "$PATCH_FILE"
    echo -e "Saved patch to $PATCH_FILE.\n"

    # Preview patch file and ask to apply
    git apply --check "$PATCH_FILE"
    less "$PATCH_FILE"
    read -p "Do you want to apply this patch? (y/n): " CONFIRM
    if [[ "$CONFIRM" =~ ^[Yy]$ ]]; then
        git apply "$PATCH_FILE"
        echo "Applied patch file."
    fi
}

if declare -f "$1" > /dev/null; then
    "$1" "${@:2}"
else
    case "$1" in
        help)
            help task
            exit 1
            ;;
        node-install)
            npm install
            ;;
        node-dev)
            npm run dev
            ;;
        node-build)
            npm run build
            ;;
        node-serve-build)
            cd .vuepress/dist
            npx serve
            ;;
        source)
            activate-venv
            ;;
        *)
            echo "Unknown command: $1"
            help task
            exit 1
            ;;
    esac
fi
