#!/usr/bin/env bash
#
# This file is part of REANA.
# Copyright (C) 2017, 2018, 2019, 2020, 2022, 2024, 2025 CERN.
#
# REANA is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.

set -o errexit
set -o nounset

docker_build() {
    docker build -t docker.io/reanahub/reana-client .
}

docker_run() {
    docker run --rm -v "$PWD"/tests:/home/reana/tests --entrypoint /bin/bash docker.io/reanahub/reana-client -c 'pytest tests'
}

docs_cli_api() {
    cli_docs_url=https://raw.githubusercontent.com/reanahub/docs.reana.io/master/docs/reference/reana-client-cli-api/index.md
    docs_differ_error_msg='Current reana-client differs with the documentation. Please update http://docs.reana.io/reference/reana-client-cli-api/.'
    python scripts/generate_cli_api.py >cli_api.md
    (diff -q -w cli_api.md <(curl -s $cli_docs_url) || (echo "$docs_differ_error_msg" && exit 1))
    rm cli_api.md
}

docs_cli_commands() {
    reana-client --help >cmd_list.txt
    diff -q -w docs/cmd_list.txt cmd_list.txt
    rm cmd_list.txt
}

docs_sphinx() {
    sphinx-build -qnNW docs docs/_build/html
    sphinx-build -qnNW -b doctest docs docs/_build/doctest
}

format_black() {
    black --check .
}

format_prettier() {
    prettier -c .
}

format_shfmt() {
    shfmt -d .
}

lint_commitlint() {
    from=${2:-master}
    to=${3:-HEAD}
    pr=${4:-[0-9]+}
    if command -v commitlint >/dev/null 2>&1; then
        commitlint --from="$from" --to="$to"
    else
        npx commitlint --from="$from" --to="$to"
    fi
    found=0
    while IFS= read -r line; do
        commit_hash=$(echo "$line" | cut -d ' ' -f 1)
        commit_title=$(echo "$line" | cut -d ' ' -f 2-)
        commit_number_of_parents=$(git rev-list --parents "$commit_hash" -n1 | awk '{print NF-1}')
        # (i) skip checking release commits generated by Release Please
        if [ "$commit_number_of_parents" -le 1 ] && echo "$commit_title" | grep -qE "^chore\(.*\): release"; then
            continue
        fi
        # (ii) check presence of PR number
        if ! echo "$commit_title" | grep -qE "\(#$pr\)$"; then
            echo "✖   Headline does not end by '(#$pr)' PR number: $commit_title"
            found=1
        fi
        # (iii) check absence of merge commits in feature branches
        if [ "$commit_number_of_parents" -gt 1 ]; then
            if echo "$commit_title" | grep -qE "^chore\(.*\): merge "; then
                break # skip checking maint-to-master merge commits
            else
                echo "✖   Merge commits are not allowed in feature branches: $commit_title"
                found=1
            fi
        fi
    done < <(git log "$from..$to" --format="%H %s")
    if [ $found -gt 0 ]; then
        exit 1
    fi
}

lint_flake8() {
    flake8 .
}

lint_hadolint() {
    docker run -i --rm docker.io/hadolint/hadolint:v2.12.0 <Dockerfile
}

lint_jsonlint() {
    find . -name "*.json" -exec jsonlint -q {} \+
}

lint_manifest() {
    check-manifest
}

lint_markdownlint() {
    markdownlint-cli2 "**/*.md"
}

lint_pydocstyle() {
    pydocstyle reana_client
}

lint_shellcheck() {
    find . -name "*.sh" -exec shellcheck {} \+
}

lint_yamllint() {
    yamllint .
}

python_tests() {
    pytest
}

all() {
    docker_build
    docker_run
    docs_cli_api
    docs_cli_commands
    docs_sphinx
    format_black
    format_prettier
    format_shfmt
    lint_commitlint
    lint_flake8
    lint_hadolint
    lint_jsonlint
    lint_manifest
    lint_markdownlint
    lint_pydocstyle
    lint_shellcheck
    lint_yamllint
    python_tests
}

help() {
    echo "Usage: $0 [options]"
    echo "Options:"
    echo "  --all                  Perform all checks [default]"
    echo "  --docker-build         Check Docker build"
    echo "  --docker-run           Check Docker run"
    echo "  --docs-cli-api         Check CLI API docs"
    echo "  --docs-cli-commands    Check CLI commands list"
    echo "  --docs-sphinx          Check Sphinx docs build"
    echo "  --format-black         Check formatting of Python code"
    echo "  --format-prettier      Check formatting of Markdown etc files"
    echo "  --format-shfmt         Check formatting of shell scripts"
    echo "  --help                 Display this help message"
    echo "  --lint-commitlint      Check linting of commit messages"
    echo "  --lint-flake8          Check linting of Python code"
    echo "  --lint-hadolint        Check linting of Dockerfiles"
    echo "  --lint-jsonlint        Check linting of JSON files"
    echo "  --lint-manifest        Check linting of Python manifest"
    echo "  --lint-markdownlint    Check linting of Markdown files"
    echo "  --lint-pydocstyle      Check linting of Python docstrings"
    echo "  --lint-shellcheck      Check linting of shell scripts"
    echo "  --lint-yamllint        Check linting of YAML files"
    echo "  --python-tests         Check Python test suite"
}

if [ $# -eq 0 ]; then
    all
    exit 0
fi

arg="$1"
case $arg in
--all) all ;;
--help) help ;;
--docker-build) docker_build ;;
--docker-run) docker_run ;;
--docs-cli-api) docs_cli_api ;;
--docs-cli-commands) docs_cli_commands ;;
--docs-sphinx) docs_sphinx ;;
--format-black) format_black ;;
--format-prettier) format_prettier ;;
--format-shfmt) format_shfmt ;;
--lint-commitlint) lint_commitlint "$@" ;;
--lint-flake8) lint_flake8 ;;
--lint-hadolint) lint_hadolint ;;
--lint-jsonlint) lint_jsonlint ;;
--lint-manifest) lint_manifest ;;
--lint-markdownlint) lint_markdownlint ;;
--lint-pydocstyle) lint_pydocstyle ;;
--lint-shellcheck) lint_shellcheck ;;
--lint-yamllint) lint_yamllint ;;
--python-tests) python_tests ;;
*) echo "[ERROR] Invalid argument '$arg'. Exiting." && help && exit 1 ;;
esac
