#!/usr/bin/env bash
set -euo pipefail

ENV_FILE="/etc/niceos/kubernetes/addons/flannel.env"
TEMPLATE="/usr/share/niceos/kubernetes/addons/flannel/kube-flannel.yaml.in"

COMMAND="render"

NICEOS_FLANNEL_NAMESPACE="${NICEOS_FLANNEL_NAMESPACE:-kube-flannel}"
NICEOS_FLANNEL_NETWORK="${NICEOS_FLANNEL_NETWORK:-10.244.0.0/16}"
NICEOS_FLANNEL_BACKEND="${NICEOS_FLANNEL_BACKEND:-vxlan}"
NICEOS_FLANNEL_IMAGE="${NICEOS_FLANNEL_IMAGE:-registry.niceos.ru/mirror/ghcr.io/flannel-io/flannel:v0.28.4}"
NICEOS_FLANNEL_CNI_PLUGIN_IMAGE="${NICEOS_FLANNEL_CNI_PLUGIN_IMAGE:-registry.niceos.ru/mirror/ghcr.io/flannel-io/flannel-cni-plugin:v1.9.1-flannel1}"
NICEOS_FLANNEL_MANIFEST="${NICEOS_FLANNEL_MANIFEST:-/etc/kubernetes/addons/kube-flannel.yaml}"
NICEOS_FLANNEL_KUBECONFIG="${NICEOS_FLANNEL_KUBECONFIG:-}"

usage() {
    cat <<'USAGE'
Usage:
  niceos-flannel-addon render [options]
  niceos-flannel-addon apply [options]
  niceos-flannel-addon delete [options]
  niceos-flannel-addon status
  niceos-flannel-addon wait
  niceos-flannel-addon images
  niceos-flannel-addon help

Commands:
  render    Render NiceOS Flannel manifest.
  apply     Render and apply NiceOS Flannel manifest.
  delete    Delete Flannel resources from rendered manifest.
  status    Show Flannel status.
  wait      Wait for Flannel DaemonSet rollout.
  images    Print required Flannel images.
  help      Show this help.

Options:
  --namespace NAME             Flannel namespace.
  --network CIDR               Flannel pod network, default 10.244.0.0/16.
  --backend TYPE               Flannel backend, default vxlan.
  --flannel-image IMAGE        Flannel image.
  --cni-plugin-image IMAGE     Flannel CNI plugin image.
  --manifest PATH              Rendered manifest output path.
  --kubeconfig PATH            kubeconfig path.
  -h, --help                   Show this help.

Examples:
  niceos-flannel-addon render
  niceos-flannel-addon apply
  niceos-flannel-addon status
  niceos-flannel-addon wait
  niceos-flannel-addon images
USAGE
}

log() {
    printf '[INFO] %s\n' "$*" >&2
}

die() {
    printf '[ERROR] %s\n' "$*" >&2
    exit 1
}

sed_escape() {
    printf '%s' "$1" | sed -e 's/[\/&]/\\&/g'
}

load_env() {
    if [ -f "$ENV_FILE" ]; then
        # shellcheck disable=SC1090
        . "$ENV_FILE"
    fi

    NICEOS_FLANNEL_NAMESPACE="${NICEOS_FLANNEL_NAMESPACE:-kube-flannel}"
    NICEOS_FLANNEL_NETWORK="${NICEOS_FLANNEL_NETWORK:-10.244.0.0/16}"
    NICEOS_FLANNEL_BACKEND="${NICEOS_FLANNEL_BACKEND:-vxlan}"
    NICEOS_FLANNEL_IMAGE="${NICEOS_FLANNEL_IMAGE:-registry.niceos.ru/mirror/ghcr.io/flannel-io/flannel:v0.28.4}"
    NICEOS_FLANNEL_CNI_PLUGIN_IMAGE="${NICEOS_FLANNEL_CNI_PLUGIN_IMAGE:-registry.niceos.ru/mirror/ghcr.io/flannel-io/flannel-cni-plugin:v1.9.1-flannel1}"
    NICEOS_FLANNEL_MANIFEST="${NICEOS_FLANNEL_MANIFEST:-/etc/kubernetes/addons/kube-flannel.yaml}"
    NICEOS_FLANNEL_KUBECONFIG="${NICEOS_FLANNEL_KUBECONFIG:-}"
}

parse_args() {
    if [ $# -gt 0 ]; then
        case "$1" in
            render|apply|delete|status|wait|images|help)
                COMMAND="$1"
                shift
                ;;
        esac
    fi

    while [ $# -gt 0 ]; do
        case "$1" in
            --namespace)
                NICEOS_FLANNEL_NAMESPACE="${2:-}"
                shift 2
                ;;
            --network)
                NICEOS_FLANNEL_NETWORK="${2:-}"
                shift 2
                ;;
            --backend)
                NICEOS_FLANNEL_BACKEND="${2:-}"
                shift 2
                ;;
            --flannel-image)
                NICEOS_FLANNEL_IMAGE="${2:-}"
                shift 2
                ;;
            --cni-plugin-image)
                NICEOS_FLANNEL_CNI_PLUGIN_IMAGE="${2:-}"
                shift 2
                ;;
            --manifest)
                NICEOS_FLANNEL_MANIFEST="${2:-}"
                shift 2
                ;;
            --kubeconfig)
                NICEOS_FLANNEL_KUBECONFIG="${2:-}"
                shift 2
                ;;
            -h|--help)
                COMMAND="help"
                shift
                ;;
            *)
                die "Unknown option: $1"
                ;;
        esac
    done
}

validate_values() {
    [ -n "$NICEOS_FLANNEL_NAMESPACE" ] || die "Flannel namespace is empty."
    [ -n "$NICEOS_FLANNEL_NETWORK" ] || die "Flannel network is empty."
    [ -n "$NICEOS_FLANNEL_BACKEND" ] || die "Flannel backend is empty."
    [ -n "$NICEOS_FLANNEL_IMAGE" ] || die "Flannel image is empty."
    [ -n "$NICEOS_FLANNEL_CNI_PLUGIN_IMAGE" ] || die "Flannel CNI plugin image is empty."
    [ -n "$NICEOS_FLANNEL_MANIFEST" ] || die "Flannel manifest path is empty."
}

setup_kubeconfig() {
    if [ -n "$NICEOS_FLANNEL_KUBECONFIG" ]; then
        export KUBECONFIG="$NICEOS_FLANNEL_KUBECONFIG"
        return 0
    fi

    if [ -n "${KUBECONFIG:-}" ]; then
        return 0
    fi

    if [ -f /etc/kubernetes/admin.conf ]; then
        export KUBECONFIG=/etc/kubernetes/admin.conf
        return 0
    fi

    die "KUBECONFIG is not set and /etc/kubernetes/admin.conf was not found."
}

render_manifest() {
    [ -f "$TEMPLATE" ] || die "Template not found: $TEMPLATE"

    mkdir -p "$(dirname "$NICEOS_FLANNEL_MANIFEST")"

    sed \
        -e "s|__FLANNEL_NAMESPACE__|$(sed_escape "$NICEOS_FLANNEL_NAMESPACE")|g" \
        -e "s|__FLANNEL_NETWORK__|$(sed_escape "$NICEOS_FLANNEL_NETWORK")|g" \
        -e "s|__FLANNEL_BACKEND__|$(sed_escape "$NICEOS_FLANNEL_BACKEND")|g" \
        -e "s|__FLANNEL_IMAGE__|$(sed_escape "$NICEOS_FLANNEL_IMAGE")|g" \
        -e "s|__FLANNEL_CNI_PLUGIN_IMAGE__|$(sed_escape "$NICEOS_FLANNEL_CNI_PLUGIN_IMAGE")|g" \
        "$TEMPLATE" > "$NICEOS_FLANNEL_MANIFEST"

    chmod 0644 "$NICEOS_FLANNEL_MANIFEST"

    log "Rendered Flannel manifest: $NICEOS_FLANNEL_MANIFEST"
    log "Namespace: $NICEOS_FLANNEL_NAMESPACE"
    log "Network: $NICEOS_FLANNEL_NETWORK"
    log "Backend: $NICEOS_FLANNEL_BACKEND"
    log "Flannel image: $NICEOS_FLANNEL_IMAGE"
    log "CNI plugin image: $NICEOS_FLANNEL_CNI_PLUGIN_IMAGE"
}

cmd_images() {
    printf '%s\n' "$NICEOS_FLANNEL_IMAGE"
    printf '%s\n' "$NICEOS_FLANNEL_CNI_PLUGIN_IMAGE"
}

cmd_apply() {
    setup_kubeconfig
    render_manifest
    kubectl apply -f "$NICEOS_FLANNEL_MANIFEST"
}

cmd_delete() {
    setup_kubeconfig
    render_manifest
    kubectl delete -f "$NICEOS_FLANNEL_MANIFEST" --ignore-not-found=true
}

cmd_status() {
    setup_kubeconfig

    echo "=== Flannel namespace ==="
    kubectl get ns "$NICEOS_FLANNEL_NAMESPACE" -o wide || true
    echo

    echo "=== Flannel DaemonSet ==="
    kubectl -n "$NICEOS_FLANNEL_NAMESPACE" get ds kube-flannel-ds -o wide || true
    echo

    echo "=== Flannel pods ==="
    kubectl -n "$NICEOS_FLANNEL_NAMESPACE" get pods -l app=flannel -o wide || true
    echo

    echo "=== Flannel ConfigMap ==="
    kubectl -n "$NICEOS_FLANNEL_NAMESPACE" get cm kube-flannel-cfg -o yaml || true
}

cmd_wait() {
    setup_kubeconfig
    kubectl -n "$NICEOS_FLANNEL_NAMESPACE" rollout status daemonset/kube-flannel-ds --timeout=180s
}

main() {
    load_env
    parse_args "$@"
    validate_values

    case "$COMMAND" in
        render)
            render_manifest
            ;;
        apply)
            cmd_apply
            ;;
        delete)
            cmd_delete
            ;;
        status)
            cmd_status
            ;;
        wait)
            cmd_wait
            ;;
        images)
            cmd_images
            ;;
        help)
            usage
            ;;
        *)
            die "Unsupported command: $COMMAND"
            ;;
    esac
}

main "$@"
