#!/usr/bin/env bash
# ssr-mackup — Manage auto-generated Mackup app definitions for dot-dirs.
#
# Subcommands:
#   scan   Dry-run: show which ssr-*.cfg files would be created / updated,
#          then ask for confirmation before writing anything.
#   list   List existing ~/.mackup/ssr-*.cfg files with the path they cover.
#   clean  Remove all generated ssr-*.cfg files (prompts first).

set -euo pipefail
SSR_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# shellcheck source=../lib/common.sh
source "$SSR_ROOT/lib/common.sh"
# shellcheck source=../lib/cloud.sh
source "$SSR_ROOT/lib/cloud.sh"
# shellcheck source=../lib/mackup.sh
source "$SSR_ROOT/lib/mackup.sh"

ssr::require_macos
ssr::load_config

usage() {
    cat <<EOF
Usage: ssr mackup <subcommand>

Manage auto-generated Mackup app definitions for dot-dirs not covered
by Mackup's built-in app definitions.

Subcommands:
  scan    Show suggested ~/.mackup/ssr-*.cfg files and confirm before writing.
  list    List existing generated files.
  clean   Remove all generated ssr-*.cfg files.

Run 'ssr mackup scan' once after install (or whenever new dot-dirs appear)
and commit the generated files alongside your dotfiles.
EOF
}

# ---------------------------------------------------------------------------
# scan — dry-run then confirm
# ---------------------------------------------------------------------------
cmd_scan() {
    local mackup_dir
    mackup_dir="$(ssr::cloud::mackup_dir 2>/dev/null)" \
        || mackup_dir=""   # allow offline use; _in_backup will just never match

    local cfg_dir="$HOME/.mackup"
    mkdir -p "$cfg_dir"

    local skip_set=" ${_SSR_MACKUP_SKIP[*]} "

    _in_backup()    { [[ -n "$mackup_dir" && -e "$mackup_dir/$1" ]]; }
    _is_declared()  { printf '%s\n' "$declared" | grep -qxF "$1"; }

    local declared
    declared="$(_ssr_mackup_declared_paths)"

    # Collect candidate items (same logic as generate_custom_cfg).
    local -a items=()
    local item
    for item in "${_SSR_MACKUP_CURATED[@]}" ${SSR_MACKUP_EXTRA_PATHS:-}; do
        [[ -e "$HOME/$item" ]] || continue
        _is_declared "$item"   && continue
        _in_backup "$item"     && continue
        items+=("$item")
    done
    local name
    while IFS= read -r dotdir; do
        name="${dotdir##*/}"
        [[ "$skip_set" == *" $name "* ]] && continue
        _is_declared "$name"   && continue
        _in_backup "$name"     && continue
        local dup=false
        for item in "${items[@]:-}"; do [[ "$item" == "$name" ]] && dup=true && break; done
        $dup && continue
        items+=("$name")
    done < <(find "$HOME" -maxdepth 1 -mindepth 1 -name '.*' -type d 2>/dev/null | sort)

    # Check existing stale duplicates.
    local -a to_remove=()
    local stale_cfg stale_path
    for stale_cfg in "$cfg_dir"/ssr-*.cfg; do
        [[ -f "$stale_cfg" ]] || continue
        stale_path="$(awk '/^\[configuration_files\]/{f=1;next}/^\[/{f=0}f&&/^[^#[:space:]]/{print $1;exit}' "$stale_cfg")"
        _is_declared "$stale_path" && to_remove+=("$stale_cfg")
    done

    # Classify each candidate: NEW or UPD (content differs from existing).
    local -a to_write=()
    local -a labels=()
    local -a cfg_paths=()

    local it app_name desired existing cfg_file paths_block
    for it in "${items[@]:-}"; do
        app_name="$(_ssr_mackup_cfg_name "$it")"
        cfg_file="$cfg_dir/${app_name}.cfg"
        paths_block="$(_ssr_mackup_resolve_paths "$it")"
        desired="$(printf '[application]\nname = %s\n\n[configuration_files]\n%s\n' "$app_name" "$paths_block")"
        if [[ -f "$cfg_file" ]]; then
            existing="$(cat "$cfg_file")"
            if [[ "$existing" == "$desired" ]]; then
                continue   # already up-to-date, skip
            fi
            labels+=("UPD")
        else
            labels+=("NEW")
        fi
        to_write+=("$it")
        cfg_paths+=("$cfg_file")
    done

    # Nothing to do?
    if [[ ${#to_write[@]} -eq 0 && ${#to_remove[@]} -eq 0 ]]; then
        ssr::ok "All ~/.mackup/ssr-*.cfg files are up-to-date — nothing to do."
        return 0
    fi

    # Show plan.
    if [[ ${#to_write[@]} -gt 0 ]]; then
        printf '\nSuggested Mackup app definitions:\n'
        local i
        for i in "${!to_write[@]}"; do
            local label="${labels[$i]}"
            local path="${cfg_paths[$i]##*/}"
            local colour
            [[ "$label" == "NEW" ]] && colour="\033[32m" || colour="\033[33m"
            # Show resolved paths (selective or whole dir).
            local resolved; resolved="$(_ssr_mackup_resolve_paths "${to_write[$i]}")"
            local line_count; line_count="$(printf '%s\n' "$resolved" | wc -l | tr -d ' ')"
            local paths_hint
            if [[ "$line_count" -eq 1 && "$resolved" == "${to_write[$i]}" ]]; then
                paths_hint="${to_write[$i]}/"   # whole directory
            else
                paths_hint="$line_count sub-path(s) of ${to_write[$i]}/"
            fi
            printf "  ${colour}%s\033[0m  %-38s  %s\n" \
                "$label" "~/.mackup/$path" "$paths_hint"
        done
    fi

    if [[ ${#to_remove[@]} -gt 0 ]]; then
        printf '\nStale duplicates to remove (now covered by built-in):\n'
        local f
        for f in "${to_remove[@]}"; do
            printf "  \033[31mDEL\033[0m  %s\n" "~/.mackup/${f##*/}"
        done
    fi
    printf '\n'

    # Confirm.
    local total=$(( ${#to_write[@]} + ${#to_remove[@]} ))
    ssr::confirm "Apply $total change(s)?" 60 || { printf 'Aborted.\n'; return 0; }

    # Write new/updated files.
    for it in "${to_write[@]:-}"; do
        _ssr_mackup_write_cfg "$cfg_dir" "$it"
    done

    # Remove stale duplicates.
    for f in "${to_remove[@]:-}"; do
        rm -f "$f"
        ssr::log "Removed stale: ${f##*/}"
    done

    ssr::ok "Done — ${#to_write[@]} written, ${#to_remove[@]} removed."
    printf '\nRun \033[1mssr sync\033[0m to back up with the new definitions.\n\n'
}

# ---------------------------------------------------------------------------
# list — show existing generated files
# ---------------------------------------------------------------------------
cmd_list() {
    local cfg_dir="$HOME/.mackup"
    local found=0 cfg path

    for cfg in "$cfg_dir"/ssr-*.cfg; do
        [[ -f "$cfg" ]] || continue
        path="$(awk '/^\[configuration_files\]/{f=1;next}/^\[/{f=0}f&&/^[^#[:space:]]/{print $1;exit}' "$cfg")"
        printf '  %-42s  %s\n' "~/.mackup/${cfg##*/}" "$path"
        found=$((found + 1))
    done

    if [[ $found -eq 0 ]]; then
        printf 'No generated ssr-*.cfg files found in ~/.mackup/\n'
        printf 'Run: ssr mackup scan\n'
    else
        printf '\n%d file(s) total.\n' "$found"
    fi
}

# ---------------------------------------------------------------------------
# clean — remove all generated files
# ---------------------------------------------------------------------------
cmd_clean() {
    local cfg_dir="$HOME/.mackup"
    local -a found=()
    local cfg
    for cfg in "$cfg_dir"/ssr-*.cfg; do
        [[ -f "$cfg" ]] && found+=("$cfg")
    done

    if [[ ${#found[@]} -eq 0 ]]; then
        ssr::ok "No generated ssr-*.cfg files to remove."
        return 0
    fi

    printf 'Will remove %d file(s):\n' "${#found[@]}"
    for cfg in "${found[@]}"; do
        printf '  %s\n' "~/.mackup/${cfg##*/}"
    done
    printf '\n'

    ssr::confirm "Remove all generated ssr-*.cfg files?" 60 || { printf 'Aborted.\n'; return 0; }
    for cfg in "${found[@]}"; do rm -f "$cfg"; done
    ssr::ok "Removed ${#found[@]} file(s)."
}

# ---------------------------------------------------------------------------
# Dispatch
# ---------------------------------------------------------------------------
[[ $# -gt 0 ]] || { usage; exit 1; }

case "$1" in
    scan)  cmd_scan  ;;
    list)  cmd_list  ;;
    clean) cmd_clean ;;
    -h|--help) usage ;;
    *) ssr::err "Unknown subcommand: $1"; usage; exit 1 ;;
esac
