#! /usr/bin/env bash

# [LICENSE: GPL3](https://www.gnu.org/licenses/gpl-3.0.en.html)
# Author: [Lockszmith](https://stackexchange.com/users/421248/lockszmith) 2023-10(Oct)-08

set -e
eval "$SETX"

ZELLIJ_PATH="${ZELLIJ_PATH:-$(which zellij)}" || true

NOZELLIJ=${NOZELLIJ:-$NOWATCH}
NOWATCH=${NOWATCH:-$NOZELLIJ}

main() {
    if [[ -n "${ZELLIJ_PATH}" && -x "${ZELLIJ_PATH}" && -z "$NOZELLIJ" ]]; then
        printf "Starting zellij layout..." >&2
        $ZELLIJ_PATH ${INTAB:+action new-tab} --layout <(
            get_zellij_layout
#           ZELLIJ_PATH="$ZELLIJ_PATH" APP="$APP" NS="$NS" TAIL="$TAIL" \
#           envsubst < ~/watch-k3s-app.kdl
        )
    else
        unset ZELLIJ_PATH 
        export NOZELLIJ=1 APP="$APP"
        $0 -- "charts"
        $0 -- "pvc"
        $0 -- "apps"
        $0 -- "services"
        $0 -- "events"
        $0 -- "pods"
        $0 -- "cnpg"
        $0 -- "logs"
    fi
}

get_zellij_layout() {
    cat - <<ZELLIJ_LAYOUT
layout {
    pane_template name="watch_k3s_app" {
        command "$HOME/bin/watch-k3s-app"
    }
    pane_template name="charts" {
        watch_k3s_app name="CHARTS" size=5 {
            args "--" "charts" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}"
        }
    }
    pane_template name="pvc" {
        watch_k3s_app name="PERSISTENT VOLUME CLAIMS (PVC)" size=9 {
            args "--" "pvc" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}"
        }
    }

    pane_template name="apps" {
        watch_k3s_app name="DEPLOYMENT.APPS" {
            args "--" "apps" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}"
        }
    }
    pane_template name="services" {
        watch_k3s_app name="SERVICES" size=9 {
            args "--" "services" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}"
        }
    }
    pane_template name="services_and_apps" {
        pane split_direction="vertical" {
            apps size="35%"
            services
        }
    }
    pane_template name="events" {
        watch_k3s_app name="EVENTS" size=9 {
            args "--" "events" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}"
        }
    }
    pane_template name="pods" {
        watch_k3s_app name="PODS" {
            args "--" "pods" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}"
        }
    }
    pane_template name="pods_and_events" {
        pane split_direction="vertical" {
            pods size="40%"
            events
        }
    }

    pane_template name="logs" {
        watch_k3s_app name="LOGS ${APP}" {
            args "--" "logs" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}"
        }
    }
    pane_template name="cnpg" {
        watch_k3s_app name="CLOUDNATIVE POSTGRESQL" size=9 {
            args "--" "cnpg" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}"
        }
    }
    pane_template name="logs_and_cnpg" {
        pane split_direction="vertical" {
            logs size="65%"
            cnpg
        }
    }

    pane split_direction="horizontal" {
        pane size=1 command="printf" borderless=true {
            args "### Watching kubernetes environment ${NS} --- [Ctrl+x] to close | [mouse-click]+[F11] Expand Pane | [Ctrl-C]+[Enter] to refersh"
        }
        // pane stacked=true {
        charts
        pvc
        // }

        services_and_apps
        pods_and_events
        logs_and_cnpg
    }
}

keybinds {
    shared {
        bind "Ctrl x" { CloseTab; }
        bind "F11" { ToggleFocusFullscreen; }
    }
}

pane_frames true

ZELLIJ_LAYOUT
}

repeat_out() {
    dd if=/dev/zero bs=${2:-10} count=1 2>/dev/null | tr '\0' "${1:?Repeat character missing}"
}
visual_sleep() {
    local SLEEP=$(( 0 + ${1:-2} )) MSG="${MSG:-Restarting in %s %s}"
    tput sc;
    while (( SLEEP > 0 )); do
        tput el; printf "$MSG" "${SLEEP}s" "$(repeat_out . ${SLEEP})"
        sleep 1s
        tput rc 1; tput el; 
        (( SLEEP-=1 )) || true
    done
}

[[ "$1" == "--" ]] || APP=${APP:-${1}}
NS=${APP:+--namespace=ix-}${APP:---all-namespaces}

case $1 in
    "--help")
        cat - <<USAGE
Watch k3s apps (with zellij support) for TrueChart Apps on TrueNAS SCALE

Usage:
    $(basename $0) [Installed App Name]
    $(basename $0) -- <output type> [<Set Expression1> [<Set Expression...>]]

Invokation modifiers (environment variable):
    [NOREPEAT=1] [NOWATCH=1] [SLEEP=3] $(basename $0) ...

Description:
    This script will pull from k3s the follwing:
        charts (helm charts)
        pvc
        apps (deployment.apps)
        services
        events
        pods
        cnpg status (applicable for APP only)
        contianer-logs (applicable for APP only)

    By default, if zellij exists, it will WATCH all of these for
    changes in parallel.
    If zellij doesn't exist, it will list all, SLEEP for a few seconds,
    then REPEAT.
    
    To produce output to share in bug reports, calling with
        NOREPEAT=1 NOWATCH=1 ...
    will output all the details and exit.

    If an APP is specified, output is confined to the specific
    namespace and service. Otherwise, it will output information about
    k3s all-namespaces.

    * For cnpg status, the cnpg plugin needs to be installed.
      On TrueNAS SCALE, this install might be required after a reboot.

Zellij specific support
    When zellij exists and running, zellij will create a set of panes
    with the above list of views watching for changes in parallel.

    It maps <Ctrl>-<X> as the exit key.
    and it maps <F11> as a Full-Screen toggle, to use it you need to
    select inside a pane with a mouse, and then click the key.


USAGE
        ;;
    "--")
        eval "${*:3}"
        export KUBECONFIG
        K_WATCH="${ZELLIJ_PATH:+--watch-only --no-headers}"
        C_WATCH="watch -tcn4"
        [[ -z "$NOZELLIJ" && -z "$NOWATCH" ]] || { K_WATCH=''; C_WATCH='eval'; }


        case "$2" in
            "charts")
                ${C_WATCH} "helm list ${NS} | sort"
                ;;
            "pvc")
                k3s kubectl get pvc ${NS} --sort-by='.metadata.creationTimestamp'
                [[ -z "${K_WATCH}" ]] || k3s kubectl get pvc ${NS} ${K_WATCH}
                ;;
            "apps")
                k3s kubectl get deployment.apps ${NS} --sort-by='.metadata.creationTimestamp'
                [[ -z "${K_WATCH}" ]] || k3s kubectl get deployment.apps ${NS} ${K_WATCH}
                ;;
            "services")
                k3s kubectl get services ${NS} --sort-by='.metadata.creationTimestamp'
                [[ -z "${K_WATCH}" ]] || k3s kubectl get services ${NS} ${K_WATCH}
                ;;
            "events")
                k3s kubectl get events ${NS} --sort-by='.metadata.creationTimestamp'
                [[ -z "${K_WATCH}" ]] || k3s kubectl get events ${NS} ${K_WATCH} \
                ;;
            "pods")
                k3s kubectl get pods ${NS} --sort-by='.metadata.creationTimestamp'
                [[ -z "${K_WATCH}" ]] || k3s kubectl get pods ${NS} \
                    ${K_WATCH};
                ;;
            "cnpg")
                sleep 0.4s;
                [[ -n "${APP}" ]] \
                && ${C_WATCH} "k3s kubectl cnpg status ${NS} ${APP}-cnpg-main" \
                || k3s kubectl get clusters.postgresql.cnpg.io ${NS} ${K_WATCH}
                ;;
            "logs")
                MSG='N/A with --all-namespaces'
                if [[ -n "${APP}" ]]; then
                    MSG="no pods active for $APP"
                    APP=($(k3s kubectl get pods ${NS} --output name | grep -E "^pod/$APP(-[^-]+){2}$"))
                    
                    FOLLOW='--follow'
                    [[ -z "$NOWATCH" ]] || { FOLLOW=''; TAIL=${TAIL:-40}; }

                    while ! k3s kubectl logs ${NS} ${FOLLOW} ${TAIL:+--tail=${TAIL}} \
                        "${APP}"; do
                        printf 'could not load logs, checking for previous logs...\n'
                        k3s kubectl logs ${NS} -p ${TAIL:+--tail=${TAIL}} "${APP}" \
                        || printf "${MSG}"

                        [[ -z "$NOWATCH" ]] || break;
                        visual_sleep ${SLEEP:-3}
                    done
                fi
                ;;
            *)
                printf "Don't know how to handle $2\n" 1>&2;
                false;
                ;;
        esac
        ;;
    *)
        while main "$1" && [[ -z "$NOREPEAT" ]]; do
            tput cuu1;
            visual_sleep ${SLEEP:-3}
        done
esac