#!/usr/bin/bash
#shellcheck disable=SC1090

. "$(sfpath)" || exit 3

shellfu import pretty

shellfu import saturnin

usage() {
    mkusage "$@"                                                                \
            "[options] TEMPLATE [ARGS..]"                                       \
            "-l"                                                                \
        --                                                                      \
            "Print path to new file (or old, if already exists) created using"  \
            "template TEMPLATE.  File path and name is generated using template"\
            "properties stored with template in config file and optionally the" \
            "arguments ARGS.."                                                  \
        -o                                                                      \
            "-o|--override K=V  Override data value K with value V (see"        \
            "               bmo-mka.md for details)"                            \
            "-f|--force     Force overwrite of an old file."                    \
            "-l|--list      Don't write anything; just list available templates"\
            "               and exit"                                           \
        --                                                                      \
            "For instructions on how to create template, see bmo-mka.md"        \
            "distributed along with bmo."
}

render_with_jinja() {
    #
    # Render template $1 with Jinja2
    #
    # Also adds functions 'file' and 'env' that can be used to conveniently
    # read file or environment variable inside the template code, and 'data'
    # dictionary containing data assigned in config or passed with --data
    # parameter.
    #
    local tpath=$1
    local key
    {
        echo '# -*- coding: utf-8 -*-'
        echo 'import datetime'
        echo 'import os'
        echo 'import sys'
        echo 'from jinja2 import Template'
        echo 'from pathlib import Path'
        echo ''
        echo 'def read_file(fpath):'
        echo '    try:'
        echo '        return Path(fpath).expanduser().read_text()'
        echo '    except IOError:'
        echo '        return ""'
        echo ''
        echo 'def read_env(vname):'
        echo '    return os.environ.get(vname, "")'
        echo ''
        echo 'data = {'
        for key in "${!Data[@]}"
        do
            echo "    '${key}': '${Data[$key]}',"
        done
        echo '}'
        echo ''
        echo 'meta = {'
        echo "    'host': '$(hostname)',"
        echo "    'date': '$(date -Iseconds)',"
        echo "    'version': '$(saturnin__get app-version)',"
        echo "    'url': '$(saturnin__get app-url)',"
        echo '}'
        echo ''
        echo 'days = {'
        echo '    "yesterday": datetime.datetime.today() + datetime.timedelta(days=-1),'
        echo '    "today": datetime.datetime.today(),'
        echo '    "tomorrow": datetime.datetime.today() + datetime.timedelta(days=1),'
        echo '}'
        echo ''
        echo "t = Template(read_file('$tpath'))"
        echo 'sys.stdout.write(t.render('
        echo '    file=read_file,'
        echo '    env=read_env,'
        echo '    data=data,'
        echo '    meta=meta,'
        echo '    days=days,'
        echo '))'
    } | python3
}

merge_data() {
    #
    # Merge template data from config and overrides $@ into $Data
    #
    local key
    local value
    for key in $(saturnin__conf -j -K "mka.template.$Template.data")
    do
        value=$(saturnin__conf -j -1 "mka.template.$Template.data.$key")
        Data[$key]=$value
    done
    for item in "$@";
    do
        key=${item%%=*}
        value=${item#"$key="}
        Data[$key]=$value
    done
}

template_prop() {
    #
    # Load property $1 of template $Template or default
    #
    local key=$1
    saturnin__conf -j -1 "mka.template.$Template.$key" \
      || saturnin__conf -j -1 "mka.default.$key"
}

render_template() {
    #
    # Find and print template from $Template using $@ as data for filename
    #
    local tfile         # template filename
    local tpath         # template full path
    tfile=$(template_prop "file")
    debug -v tfile
    tpath=$(
        saturnin__conf_find "mka/templates/$tfile" \
          | grep -m 1 .
    ) || {
        warn "template file not found (using /dev/null): $tfile"
        tpath="/dev/null"
    }
    debug -v tpath
    render_with_jinja "$tpath" || {
        warn "rendering failed"
        return 2
    }
}

outfile() {
    #
    # Decide output file path
    #
    local tformat       # template's output file naming format
    local destdir       # template's destination directory
    tformat=$(template_prop "format")
    destdir="$(saturnin__get data-home)/mka/out/$Template"
    debug -v tformat tdestdir
    #shellcheck disable=SC2059
    printf "$destdir/$tformat" "$@"
}

lstemplates() {
    #
    # List available templates
    #
    saturnin__conf -j -S mka.ini \
      | grep '^mka\.template\.' \
      | cut -d. -f3 \
      | sort \
      | uniq
}

main() {
    local Template      # template to use
    declare -A Data     # template data (k=v pairs)
    local overrides=()  # template data overrides
    local tmp           # temp to keep rendered file
    local es=0          # exit status
    local keep=true     # keep old file?
    local outfile       # output file path
    while true; do case "$1" in
        -o|--override)  overrides+=("$2");  shift 2 || usage -w "missing value to: $1" ;;
        -f|--force)     keep=false;         shift   ;;
        -l|--list)      lstemplates;        exit $? ;;
        --) shift; break ;;
        -*) usage -w "unknown argument: $1" ;;
        *)  break ;;
    esac done
    Template=$1; shift
    test -n "$Template" || usage -w "no TEMPLATE?"
    lstemplates | grep -qxFe "$Template" \
     || die "no such template: $Template"
    debug -v Template
    merge_data "${overrides[@]}"
    debug -v Data
    outfile=$(outfile "$@")
    test -f "$outfile" && $keep && {
        echos "$outfile"
        return 0
    }
    tmp=$(mktemp -t "bmo-mka.main.tmp.XXXXXXXX")
    render_template > "$tmp"; es=$?
    if test $es -eq 0;
    then
        mkdir -p "$(dirname "$outfile")" \
         || die "could not create output dir: $(dirname "$outfile")"
        mv "$tmp" "$outfile"
        echos "$outfile"
    fi
    return $es
}

main "$@"
