#!/usr/bin/env bash
# Author: Lucas Frérot
# Affiliation:
#     Sorbonne Université, CNRS, Institut Jean Le Rond d’Alembert,
#     F-75005 Paris, France
#
# Copyright © 2024  Lucas Frérot
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

# Sane bash options
set -o errexit
set -o nounset
set -o pipefail

# Colors
readonly RED='\033[0;31m'
readonly ORANGE='\033[0;33m'
readonly GREEN='\033[0;32m'
readonly BLUE='\033[0;34m'
readonly CYAN='\033[0;36m'
readonly NC='\033[0m'

# Gitea
readonly ENDPOINT="https://git.dalembert.upmc.fr/api/v1"

# Lab info
readonly AFFILIATION="Sorbonne Université, CNRS, Institut Jean Le Rond d’Alembert, F-75005 Paris, France"

# ----------------- Logging commands -----------------------

# Print error and exit
error() {
    printf "${RED}error${NC}: %s\\n" "$@" 1>&2
    exit 1
}

# Print warning
warning() {
    printf "${ORANGE}warning${NC}: %s\\n" "$@" 1>&2
}

# Print info
info() {
    printf "${GREEN}info${NC}: %b\\n" "$@" 1>&2
}

# Enter value
enter() {
    printf "${BLUE}input${NC}: %b" "$@" 1>&2
    local input_var=''
    read input_var
    printf "${input_var}"
}

# Test if a variable name is set
is_set() {
    local var_name="$1"
    eval "! [[ -z \"\${${var_name}+x}\" ]]"
    return $?
}

# Set var to first value if unset
alt_var() {
    local value_if_unset="$1"
    local variable="$2"
    if is_set "${variable}"; then
        printf "%s" "$(eval "printf \"%s\" \"\${${variable}}\"")"
    else
        printf "%s" "$value_if_unset"
    fi
}

# Check that command exists
has_command() {
    command -v "$1" >/dev/null 2>&1
}

# Check curl and jq to process API calls to gitea
check_api_prerequisites() {
    if ! has_command curl; then
        error "curl not found, please install"
    fi

    if ! has_command jq; then
        error "jq not found, please install"
    fi
}

# ----------------- Gitea API commands -----------------------
get_gitea_token(){
    if [[ -f token ]]; then
        read TOKEN < token
    else
        TOKEN="$(enter "gitea token: ")"
    fi
    readonly TOKEN
}

gitea() {
    check_api_prerequisites
    readonly TOKEN

    if ! is_set TOKEN; then
        get_gitea_token
    fi

    local method="$1"
    local request="$2"
    \curl -X "${request}" \
          -H "Content-Type: application/json" \
          -H "Authorization: token ${TOKEN}" "${ENDPOINT}/${method}"
}

# ----------------- Git commands -----------------------

# Set value of git config parameter
set_git_config() {
    local param="$1"
    local value=''
    while ! [[ -n "${value}" ]]; do
        value="$(enter "new value for ${param}: ")"
    done
    \git config --global "${param}" "${value}"
    info "setting new value for ${param}: '$(git config "${param}")'"
    printf "${value}"
}

# Get value of git config parameter, set if unset
get_git_config() {
    local param="$1"
    local value="$(git config "${param}")"
    if ! [[ -n "${value}" ]]; then
        warning "git ${param} is unset"
        value="$(set_git_config "${param}")"
    fi
    printf "${value}"
}

# Check git configuration and correct if necessary
check_git_config() {
    if ! has_command git; then
        error "git not found, please install"
    fi

    readonly USER="$(alt_var "$(get_git_config user.name)" USER)"
    readonly EMAIL="$(alt_var "$(get_git_config user.email)" EMAIL)"
    info "found git credentials:\\n  - user.name: '${USER}'\\n  - user.email: '${EMAIL}'"
}

# Initialize git repository
init_repo() {
    check_git_config
    \git init
}

# Make bash script stub
script_stub() {
    local script_name="$1"
    local start_phrase="$2"

    if ! [[ -f "${script_name}" ]]; then
        mkdir -p "$(dirname "${script_name}")"
        cat << STUB > "${script_name}"
#!/usr/bin/env bash
set -euo pipefail

main() {
    printf "${start_phrase}\\n" 1>&2
    # put code here
}

main "\$@"
STUB
        chmod +x "${script_name}"
    fi
}

# Fetch licence
fetch_licence() {
    local licence="COPYING"

    if ! [[ -f "${licence}" ]]; then
        if has_command curl; then
            info "setting licence to GPL by default, see https://www.gnu.org/licenses for more options"
            \curl "https://www.gnu.org/licenses/gpl-3.0.txt" > "${licence}"
        else
            warning "please choose a free software licence, see https://www.gnu.org/licenses"
        fi
    fi
}

# Create README
create_readme() {
    local readme="README.md~"

    if ! [[ -f "${readme}" ]]; then
        local project_name="$(enter "project name: ")"
        local project_desc="$(enter "project short description: ")"

        cat << READMEMSG > "${readme}"
# ${project_name}

${project_desc}

## Dependencies

Here are the dependencies to build and run the code:

- <dependencies_list>

## Running the code

Here is how to run the code:

\`\`\`
./make_all_figures
\`\`\`

## Tests

Here is how to run the tests:

\`\`\`
./tests/run_all_tests
\`\`\`
READMEMSG

        info "wrote '${readme}'"
    fi
}

create_authors_file() {
    if ! [[ -f AUTHORS ]]; then
        printf "%s\\n" "${USER} <${EMAIL}> ${AFFILIATION}" > AUTHORS
    fi
}

# Create required files
create_tenet_file_tree() {
    create_readme
    create_authors_file
    fetch_licence
    script_stub tests/run_all_tests "Running all tests..."
    script_stub make_all_figures "Generating figures..."
}

# Create git repository
create_repo() {
    local repo_name="$1"
    info "recursively creating directory '${repo_name}'"
    mkdir -p "${repo_name}"
    (
        info "initializing repository '${repo_name}'"
        cd "${repo_name}"
        init_repo
        create_tenet_file_tree
    )
}

# Print usage and exit
usage() {
    true
}

main() {
    check_git_config
    create_tenet_file_tree

    gitea /user GET
}

main "$@"