#!/bin/bash

# filemd_restore - Consolidated restore tool for AGENTS.md, plugins, skills, and subagents
# Usage: filemd_restore
# Interactive 4-column selection mode

set -e

STORAGE_DIR="$HOME/00_central/volatile"
TYPE_DESC_FILE="$STORAGE_DIR/.type_descriptions"
PLUGINS_DIR=".opencode/plugins"
SKILLS_DIR=".opencode/skills"
AGENTS_DIR=".opencode/agents"
ASKILLS_DIR=".agents/skills"

# Check dependencies
compare_files() {
    local f1="$1"
    local f2="$2"
    if command -v icdiff >/dev/null 2>&1; then
        icdiff "$f1" "$f2" -t --show-no-spaces --no-bold | grep -ve "^\s*$" || true
    else
        diff -u "$f1" "$f2" || true
    fi
}

load_type_descriptions() {
    TYPE_DESCRIPTIONS=()
    if [[ -f "$TYPE_DESC_FILE" ]]; then
        while IFS='|' read -r cat type_name desc; do
            TYPE_DESCRIPTIONS["${cat}:${type_name}"]="$desc"
        done < "$TYPE_DESC_FILE"
    fi
}

# Ensure storage exists
mkdir -p "$STORAGE_DIR"

# --- Data Gathering ---

# Fixed timestamp length (YYYYMMDD_HHMMSS_)
TS_LEN=16

get_types() {
    local pattern="$1"
    local suffix="$2"
    ls "$STORAGE_DIR" 2>/dev/null | grep -E "$pattern" | while read -r file; do
        # Strip prefix and suffix
        local type_part="${file:$TS_LEN}"
        echo "${type_part%$suffix}"
    done | sort -u
}

# Column 1: AGENTS.md types
AGENT_TYPES=($(get_types "_AGENTS.md$" "_AGENTS.md"))
# Column 2: Plugin types
PLUGIN_TYPES=($(get_types "_PLUGIN" "_PLUGIN*"))
# Column 3: Skill types
SKILL_TYPES=($(get_types "_SKILL.tar.gz$" "_SKILL.tar.gz"))
# Column 4: Subagent types
SUBAGENT_TYPES=($(get_types "_SUBAGENT.md$" "_SUBAGENT.md"))

# Index-to-display: 1..9, 11..N (skip 10)
_idx2disp() { local i=$1; if [[ $i -lt 9 ]]; then echo $((i+1)); else echo $((i+2)); fi; }
_disp2idx() { local n=$1; if [[ $n -le 9 ]]; then echo $((n-1)); else echo $((n-2)); fi; }

# Selection states
SELECTED_AGENT=""
declare -A SELECTED_PLUGINS
declare -A SELECTED_SKILLS
declare -A SELECTED_SUBAGENTS
declare -A TYPE_DESCRIPTIONS
LAST_DESC=""

# Key mappings
# 1-9 for Agents
# a-i for Plugins
# j-r for Skills
# z backwards for Subagents (dynamic based on count)

# --- UI Functions ---

draw_menu() {
    clear
    echo -e "\033[33m=== filemd_restore - Consolidated Selection ===\033[0m"
    echo ""
    printf "%-25s %-25s %-25s %-25s\n" "COL 1: AGENTS.md" "COL 2: PLUGINS" "COL 3: SKILLS" "COL 4: SUBAGENTS"
    printf "%-25s %-25s %-25s %-25s\n" "----------------" "--------------" "-------------" "----------------"

    local max_rows=${#AGENT_TYPES[@]}
    [[ ${#PLUGIN_TYPES[@]} -gt $max_rows ]] && max_rows=${#PLUGIN_TYPES[@]}
    [[ ${#SKILL_TYPES[@]} -gt $max_rows ]] && max_rows=${#SKILL_TYPES[@]}
    [[ ${#SUBAGENT_TYPES[@]} -gt $max_rows ]] && max_rows=${#SUBAGENT_TYPES[@]}

    for ((i=0; i<max_rows; i++)); do
        # Column 1: Agents (numbered keys, skip 10)
        local col1_text=""
        if [[ $i -lt ${#AGENT_TYPES[@]} ]]; then
            local type="${AGENT_TYPES[$i]}"
            local key=$(_idx2disp $i)
            local mark="[ ]"
            [[ "$SELECTED_AGENT" == "$type" ]] && mark="[x]"
            col1_text="${key}) $mark $type"
        fi

        # Column 2: Plugins (keys a-i)
        local col2_text=""
        if [[ $i -lt ${#PLUGIN_TYPES[@]} ]]; then
            local type="${PLUGIN_TYPES[$i]}"
            local key_code=$((97 + i)) # 'a' is 97
            local key=$(printf "\\$(printf '%03o' $key_code)")
            local mark="[ ]"
            [[ "${SELECTED_PLUGINS[$type]}" == "1" ]] && mark="[x]"
            # Truncate long plugin names
            local display_name="$type"
            if [[ ${#display_name} -gt 18 ]]; then
                display_name="${display_name:0:15}..."
            fi
            col2_text="${key}) $mark $display_name"
        fi

        # Column 3: Skills (keys j-r)
        local col3_text=""
        if [[ $i -lt ${#SKILL_TYPES[@]} ]]; then
            local type="${SKILL_TYPES[$i]}"
            local key_code=$((106 + i)) # 'j' is 106
            local key=$(printf "\\$(printf '%03o' $key_code)")
            local mark="[ ]"
            [[ "${SELECTED_SKILLS[$type]}" == "1" ]] && mark="[x]"
            col3_text="${key}) $mark $type"
        fi

        # Column 4: Subagents (keys from z backwards)
        local col4_text=""
        if [[ $i -lt ${#SUBAGENT_TYPES[@]} ]]; then
            local type="${SUBAGENT_TYPES[$i]}"
            local sub_count=${#SUBAGENT_TYPES[@]}
            local key_code=$((123 - sub_count + i))
            local key=$(printf "\\$(printf '%03o' $key_code)")
            local mark="[ ]"
            [[ "${SELECTED_SUBAGENTS[$type]}" == "1" ]] && mark="[x]"
            col4_text="${key}) $mark $type"
        fi

        printf "%-25s %-25s %-25s %-25s\n" "$col1_text" "$col2_text" "$col3_text" "$col4_text"
    done

    echo ""
    local sub_count=${#SUBAGENT_TYPES[@]}
    local sub_keys=""
    if [[ $sub_count -ge 2 ]]; then
        sub_keys=$(printf "\\$(printf '%03o' $((123 - sub_count)))-z")
    elif [[ $sub_count -eq 1 ]]; then
        sub_keys="z"
    fi
    local sub_help=""
    if [[ -n "$sub_keys" ]]; then
        sub_help=" | [$sub_keys]: Subagents"
    fi
    echo -e "\033[33m[number]: Agents | [a-i]: Plugins | [j-r]: Skills${sub_help} | [ENTER]: Confirm | [q]: Quit\033[0m"
    if [[ -n "$LAST_DESC" ]]; then
        echo ""
        echo -e "\033[2m${LAST_DESC}\033[0m"
    fi
}

# --- Restoration Logic ---

restore_agent() {
    local type="$1"
    local md_file="AGENTS.md"
    echo -e "\n\033[34m>>> Processing AGENTS.md ($type)\033[0m"
    
    local latest=$(ls -t "$STORAGE_DIR"/*"${type}_${md_file}" 2>/dev/null | head -1)
    if [[ -z "$latest" ]]; then
        echo -e "\033[31mError: Stored file not found for type $type\033[0m"
        return
    fi

    if [[ -f "$md_file" ]]; then
        if ! diff -q "$md_file" "$latest" > /dev/null; then
            echo "Differences found in $md_file:"
            compare_files "$md_file" "$latest"
            echo -n -e "\033[33mOverwrite $md_file? (y/N) \033[0m"
            read -n 1 -r REPLY
            echo
            if [[ "$REPLY" =~ ^[Yy]$ ]]; then
                cp "$latest" "$md_file"
                echo -e "\033[32mRestored: $md_file\033[0m"
            fi
        else
            echo -e "\033[32m$md_file is already up to date.\033[0m"
        fi
    else
        cp "$latest" "$md_file"
        echo -e "\033[32mRestored: $md_file\033[0m"
    fi
}

restore_plugin() {
    local type="$1"
    echo -e "\n\033[34m>>> Processing Plugin ($type)\033[0m"
    
    local latest=$(ls -t "$STORAGE_DIR"/*_"${type}_PLUGIN"* 2>/dev/null | grep -E "[0-9]{8}_[0-9]{6}_${type}_PLUGIN(\..*)?$" | head -1)
    if [[ -z "$latest" ]]; then
        echo -e "\033[31mError: Stored plugin not found for type $type\033[0m"
        return
    fi

    local filename_ext=$(basename "$latest")
    local ext="${filename_ext##*.}"
    local plugin_name
    if [[ "$ext" == "$filename_ext" ]]; then
        plugin_name="$type"
    else
        plugin_name="$type.$ext"
    fi
    local target="$PLUGINS_DIR/$plugin_name"

    mkdir -p "$PLUGINS_DIR"

    if [[ -f "$target" ]]; then
        if ! diff -q "$target" "$latest" > /dev/null; then
            echo "Differences found in $plugin_name:"
            compare_files "$target" "$latest"
            echo -n -e "\033[33mOverwrite $target? (y/N) \033[0m"
            read -n 1 -r REPLY
            echo
            if [[ "$REPLY" =~ ^[Yy]$ ]]; then
                cp "$latest" "$target"
                echo -e "\033[32mRestored: $target\033[0m"
            fi
        else
            echo -e "\033[32m$target is already up to date.\033[0m"
        fi
    else
        cp "$latest" "$target"
        echo -e "\033[32mRestored: $target\033[0m"
    fi
}

restore_skill() {
    local type="$1"
    local skill_name="$type"

    echo -e "\n\033[34m>>> Processing Skill ($type)\033[0m"

    local latest=$(ls -t "$STORAGE_DIR"/*"${type}_SKILL.tar.gz" 2>/dev/null | head -1)
    if [[ -z "$latest" ]]; then
        echo -e "\033[31mError: Stored skill archive not found for type $type\033[0m"
        return
    fi

    # Check archive contents for .opencode and .agents
    local has_opencode=0
    local has_agents=0
    local archive_contents=$(tar -tzf "$latest")

    # Determine skill name from archive (for backward compatibility)
    local archive_skill_name=$(echo "$archive_contents" | grep -m1 "^[^.]*/$" | sed 's|/$||')
    if [[ -n "$archive_skill_name" ]] && [[ "$archive_skill_name" != ".agents" ]]; then
        skill_name="$archive_skill_name"
    fi

    if echo "$archive_contents" | grep -q "^${skill_name}/"; then
        has_opencode=1
    fi
    if echo "$archive_contents" | grep -q "^\.agents/skills/${skill_name}/"; then
        has_agents=1
    fi

    local target_dir="$SKILLS_DIR/$skill_name"
    local atarget_dir="$ASKILLS_DIR/$skill_name"

    # Show what will be restored
    if [[ $has_opencode -eq 1 ]]; then
        echo -e "  .opencode: $target_dir"
    fi
    if [[ $has_agents -eq 1 ]]; then
        echo -e "  .agents:   $atarget_dir"
    fi

    # Extract archive to temp dir for comparison
    local temp_dir=$(mktemp -d)
    tar -xzf "$latest" -C "$temp_dir" --exclude="*undo-tree~"

    local diff_found=0
    local need_confirm=0

    # Compare .opencode skills
    if [[ $has_opencode -eq 1 ]]; then
        local extracted_oc="$temp_dir/$skill_name"
        mkdir -p "$SKILLS_DIR"

        if [[ -d "$target_dir" ]]; then
            echo -e "\033[33m.opencode: $target_dir exists. Comparing...\033[0m"
            find "$target_dir" -type f ! -name "*undo-tree~" -printf "%P\n" | sort > "$temp_dir/local_oc.txt"
            find "$extracted_oc" -type f ! -name "*undo-tree~" -printf "%P\n" | sort > "$temp_dir/archive_oc.txt"

            while IFS= read -r file; do
                local_file="$target_dir/$file"
                archive_file="$extracted_oc/$file"
                if [[ -f "$local_file" && -f "$archive_file" ]]; then
                    if [[ $(stat -c%s "$local_file") -ne $(stat -c%s "$archive_file") ]]; then
                        echo -e "  \033[31m[.opencode] $file (DIFFERENT SIZE)\033[0m"
                        diff_found=1
                    fi
                elif [[ -f "$local_file" ]]; then
                    echo -e "  \033[31m[.opencode] $file (Missing in archive)\033[0m"
                    diff_found=1
                else
                    echo -e "  \033[32m[.opencode] $file (New in archive)\033[0m"
                    diff_found=1
                fi
            done < <(cat "$temp_dir/local_oc.txt" "$temp_dir/archive_oc.txt" | sort -u)

            need_confirm=1
        else
            echo -e "\033[32m[.opencode] New directory: $target_dir\033[0m"
        fi
    fi

    # Compare .agents skills
    if [[ $has_agents -eq 1 ]]; then
        local extracted_ag="$temp_dir/.agents/skills/$skill_name"
        mkdir -p "$ASKILLS_DIR"

        if [[ -d "$atarget_dir" ]]; then
            echo -e "\033[33m.agents: $atarget_dir exists. Comparing...\033[0m"
            find "$atarget_dir" -type f ! -name "*undo-tree~" -printf "%P\n" | sort > "$temp_dir/local_ag.txt"
            find "$extracted_ag" -type f ! -name "*undo-tree~" -printf "%P\n" | sort > "$temp_dir/archive_ag.txt"

            while IFS= read -r file; do
                local_file="$atarget_dir/$file"
                archive_file="$extracted_ag/$file"
                if [[ -f "$local_file" && -f "$archive_file" ]]; then
                    if [[ $(stat -c%s "$local_file") -ne $(stat -c%s "$archive_file") ]]; then
                        echo -e "  \033[31m[.agents] $file (DIFFERENT SIZE)\033[0m"
                        diff_found=1
                    fi
                elif [[ -f "$local_file" ]]; then
                    echo -e "  \033[31m[.agents] $file (Missing in archive)\033[0m"
                    diff_found=1
                else
                    echo -e "  \033[32m[.agents] $file (New in archive)\033[0m"
                    diff_found=1
                fi
            done < <(cat "$temp_dir/local_ag.txt" "$temp_dir/archive_ag.txt" | sort -u)

            need_confirm=1
        else
            echo -e "\033[32m[.agents] New directory: $atarget_dir\033[0m"
        fi
    fi

    if [[ $diff_found -eq 0 ]] && [[ $need_confirm -eq 0 ]]; then
        rm -rf "$temp_dir"
    else
        if [[ $diff_found -eq 0 ]]; then
            echo -e "\033[32mNo differences found.\033[0m"
        else
            echo -e "\033[32mNo differences found.\033[0m"
        fi

        echo -n -e "\033[33mOverwrite? (y/N) \033[0m"
        read -n 1 -r REPLY
        echo
        rm -rf "$temp_dir"
        if [[ ! "$REPLY" =~ ^[Yy]$ ]]; then
            echo "Skipped $type"
            return
        fi

        # Remove existing directories before restore
        if [[ $has_opencode -eq 1 ]] && [[ -d "$target_dir" ]]; then
            rm -rf "$target_dir"
        fi
        if [[ $has_agents -eq 1 ]] && [[ -d "$atarget_dir" ]]; then
            rm -rf "$atarget_dir"
        fi
    fi

    # Restore .opencode skills
    if [[ $has_opencode -eq 1 ]]; then
        mkdir -p "$SKILLS_DIR"
        tar -xzf "$latest" -C "$SKILLS_DIR" --exclude="*undo-tree~" "$skill_name"
        echo -e "\033[32mRestored skill to: $target_dir\033[0m"
    fi

    # Restore .agents skills
    if [[ $has_agents -eq 1 ]]; then
        mkdir -p "$ASKILLS_DIR"
        local ag_temp=$(mktemp -d)
        tar -xzf "$latest" -C "$ag_temp" --exclude="*undo-tree~" ".agents"
        cp -a "$ag_temp/.agents/skills/$skill_name" "$ASKILLS_DIR/"
        rm -rf "$ag_temp"
        echo -e "\033[32mRestored .agents skill to: $atarget_dir\033[0m"
    fi
}

restore_subagent() {
    local type="$1"
    echo -e "\n\033[34m>>> Processing Subagent ($type)\033[0m"
    
    local latest=$(ls -t "$STORAGE_DIR"/*"${type}_SUBAGENT.md" 2>/dev/null | head -1)
    if [[ -z "$latest" ]]; then
        echo -e "\033[31mError: Stored subagent not found for type $type\033[0m"
        return
    fi

    local target="$AGENTS_DIR/${type}.md"

    mkdir -p "$AGENTS_DIR"

    if [[ -f "$target" ]]; then
        if ! diff -q "$target" "$latest" > /dev/null; then
            echo "Differences found in ${type}.md:"
            compare_files "$target" "$latest"
            echo -n -e "\033[33mOverwrite $target? (y/N) \033[0m"
            read -n 1 -r REPLY
            echo
            if [[ "$REPLY" =~ ^[Yy]$ ]]; then
                cp "$latest" "$target"
                echo -e "\033[32mRestored: $target\033[0m"
            fi
        else
            echo -e "\033[32m$target is already up to date.\033[0m"
        fi
    else
        cp "$latest" "$target"
        echo -e "\033[32mRestored: $target\033[0m"
    fi
}

load_type_descriptions

# --- Main Loop ---

while true; do
    draw_menu
    read -r input
    
    case "$input" in
        q|Q)
            echo -e "\033[31mAborted.\033[0m"
            exit 0
            ;;
        "")
            break
            ;;
        [a-i])
            printf -v idx "%d" "'${input:0:1}"
            idx=$((idx - 97))
            if [[ $idx -lt ${#PLUGIN_TYPES[@]} ]]; then
                type="${PLUGIN_TYPES[$idx]}"
                tdesc="${TYPE_DESCRIPTIONS["PLUGIN:${type}"]}"
                LAST_DESC=$([[ -n "$tdesc" ]] && echo "${type}: ${tdesc}" || echo "")
                if [[ "${SELECTED_PLUGINS[$type]}" == "1" ]]; then
                    unset SELECTED_PLUGINS["$type"]
                else
                    SELECTED_PLUGINS["$type"]="1"
                fi
            fi
            ;;
        [j-r])
            printf -v idx "%d" "'${input:0:1}"
            idx=$((idx - 106))
            if [[ $idx -lt ${#SKILL_TYPES[@]} ]]; then
                type="${SKILL_TYPES[$idx]}"
                tdesc="${TYPE_DESCRIPTIONS["SKILL:${type}"]}"
                LAST_DESC=$([[ -n "$tdesc" ]] && echo "${type}: ${tdesc}" || echo "")
                if [[ "${SELECTED_SKILLS[$type]}" == "1" ]]; then
                    unset SELECTED_SKILLS["$type"]
                else
                    SELECTED_SKILLS["$type"]="1"
                fi
            fi
            ;;
        [a-z])
            local sub_count=${#SUBAGENT_TYPES[@]}
            local first_code=$((123 - sub_count))
            printf -v key_val "%d" "'${input:0:1}"
            idx=$((key_val - first_code))
            if [[ $idx -ge 0 ]] && [[ $idx -lt $sub_count ]]; then
                type="${SUBAGENT_TYPES[$idx]}"
                tdesc="${TYPE_DESCRIPTIONS["SUBAGENT:${type}"]}"
                LAST_DESC=$([[ -n "$tdesc" ]] && echo "${type}: ${tdesc}" || echo "")
                if [[ "${SELECTED_SUBAGENTS[$type]}" == "1" ]]; then
                    unset SELECTED_SUBAGENTS["$type"]
                else
                    SELECTED_SUBAGENTS["$type"]="1"
                fi
            fi
            ;;
        *)
            if [[ "$input" =~ ^[0-9]+$ ]] && [[ "$input" -ne 10 ]] && [[ "$input" -ge 1 ]]; then
                idx=$(_disp2idx "$input")
                if [[ $idx -ge 0 ]] && [[ $idx -lt ${#AGENT_TYPES[@]} ]]; then
                    type="${AGENT_TYPES[$idx]}"
                    tdesc="${TYPE_DESCRIPTIONS["AGENTS.md:${type}"]}"
                    LAST_DESC=$([[ -n "$tdesc" ]] && echo "${type}: ${tdesc}" || echo "")
                    if [[ "$SELECTED_AGENT" == "$type" ]]; then
                        SELECTED_AGENT=""
                    else
                        SELECTED_AGENT="$type"
                    fi
                fi
            fi
            ;;
    esac
done

# --- Execute Restorations ---

if [[ -n "$SELECTED_AGENT" ]]; then
    restore_agent "$SELECTED_AGENT"
fi

for type in "${!SELECTED_PLUGINS[@]}"; do
    restore_plugin "$type"
done

for type in "${!SELECTED_SKILLS[@]}"; do
    restore_skill "$type"
done

for type in "${!SELECTED_SUBAGENTS[@]}"; do
    restore_subagent "$type"
done

echo -e "\n\033[32mAll tasks completed.\033[0m"
