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

###############################################################################
# KRIS EDIT — Content metadata editor for krisyotam.com
#
# Maintainer:   Kris Yotam <krisyotam@pm.me>
# License:      MIT
# Created:      2026-02-15
# Description:  Edit metadata fields (title, preview, category, tags, status,
#               confidence, importance, state) for any content entry in
#               content.db. Select entries via fzf or nnn.
###############################################################################

###############################################################################
# config
###############################################################################

DB="/home/krisyotam/dev/krisyotam.com/public/data/content.db"
CONTENT_DIR="$HOME/content"

CONTENT_TYPES=(
    blog diary essays fiction news notes ocs
    papers progymnasmata reviews verse
)

# Diary has no status/confidence/importance columns
DIARY_FIELDS=(title preview category_slug state)
STANDARD_FIELDS=(title preview category_slug status confidence importance state)

VALID_STATUSES=("Notes" "Draft" "In Progress" "Finished" "Abandoned")
VALID_CONFIDENCES=(
    "certain" "highly likely" "likely" "possible"
    "unlikely" "highly unlikely" "remote" "impossible"
)
VALID_STATES=("active" "hidden")

###############################################################################
# helpers
###############################################################################

have_cmd() { command -v "$1" >/dev/null 2>&1; }
die() { echo "ERROR: $1" >&2; exit 1; }

have_cmd fzf     || die "fzf not found"
have_cmd sqlite3 || die "sqlite3 not found"
[[ -f "$DB" ]]   || die "content.db not found at $DB"

sql() { sqlite3 "$DB" "$1"; }

###############################################################################
# ui
###############################################################################

print_banner() {
    local cols
    cols="$(tput cols 2>/dev/null || echo 80)"

    if have_cmd figlet; then
        figlet -w "$cols" -f big "EDIT" 2>/dev/null \
            || figlet -w "$cols" "EDIT"
    else
        echo "=== EDIT ==="
    fi

    echo
    echo "  Content metadata editor for krisyotam.com"
    echo
}

# Draw a box around metadata
show_metadata() {
    local type="$1" slug="$2"

    local title preview category status confidence importance state tags

    title="$(sql "SELECT title FROM $type WHERE slug='$slug'")"
    preview="$(sql "SELECT preview FROM $type WHERE slug='$slug'")"
    category="$(sql "SELECT category_slug FROM $type WHERE slug='$slug'")"
    state="$(sql "SELECT state FROM $type WHERE slug='$slug'")"

    # Get tags
    local id
    id="$(sql "SELECT id FROM $type WHERE slug='$slug'")"
    tags="$(sql "SELECT t.slug FROM tags t JOIN content_tags ct ON ct.tag_id = t.id WHERE ct.content_type = '$type' AND ct.content_id = $id ORDER BY t.slug" | paste -sd', ' -)"

    echo
    echo "  ┌─ $slug ─────────────────────────────────"
    printf "  │ %-14s %s\n" "Title:" "$title"
    printf "  │ %-14s %s\n" "Preview:" "${preview:0:60}"
    printf "  │ %-14s %s\n" "Category:" "$category"
    printf "  │ %-14s %s\n" "Tags:" "$tags"

    if [[ "$type" != "diary" ]]; then
        status="$(sql "SELECT status FROM $type WHERE slug='$slug'")"
        confidence="$(sql "SELECT confidence FROM $type WHERE slug='$slug'")"
        importance="$(sql "SELECT importance FROM $type WHERE slug='$slug'")"
        printf "  │ %-14s %s\n" "Status:" "$status"
        printf "  │ %-14s %s\n" "Confidence:" "$confidence"
        printf "  │ %-14s %s\n" "Importance:" "$importance"
    fi

    printf "  │ %-14s %s\n" "State:" "$state"
    echo "  └──────────────────────────────────────────"
    echo
}

###############################################################################
# field editing
###############################################################################

edit_field() {
    local type="$1" slug="$2" field="$3"
    local new_value=""

    case "$field" in
        title|preview)
            local current
            current="$(sql "SELECT $field FROM $type WHERE slug='$slug'")"
            echo "  Current $field: $current"
            read -rp "  New $field: " new_value
            [[ -z "$new_value" ]] && return
            # Escape single quotes for SQL
            new_value="${new_value//\'/\'\'}"
            sql "UPDATE $type SET $field='$new_value', updated_at=datetime('now') WHERE slug='$slug'"
            echo "  Updated $field."
            ;;
        category_slug)
            new_value="$(
                sql "SELECT slug FROM categories ORDER BY slug" |
                fzf --prompt="category> " --height=20 --reverse
            )" || return
            sql "UPDATE $type SET category_slug='$new_value', updated_at=datetime('now') WHERE slug='$slug'"
            echo "  Updated category to: $new_value"
            ;;
        tags)
            edit_tags "$type" "$slug"
            ;;
        status)
            new_value="$(
                printf "%s\n" "${VALID_STATUSES[@]}" |
                fzf --prompt="status> " --height=10 --reverse
            )" || return
            sql "UPDATE $type SET status='$new_value', updated_at=datetime('now') WHERE slug='$slug'"
            echo "  Updated status to: $new_value"
            ;;
        confidence)
            new_value="$(
                printf "%s\n" "${VALID_CONFIDENCES[@]}" |
                fzf --prompt="confidence> " --height=12 --reverse
            )" || return
            sql "UPDATE $type SET confidence='$new_value', updated_at=datetime('now') WHERE slug='$slug'"
            echo "  Updated confidence to: $new_value"
            ;;
        importance)
            read -rp "  Importance (1-10): " new_value
            if [[ "$new_value" =~ ^[0-9]+$ ]] && (( new_value >= 1 && new_value <= 10 )); then
                sql "UPDATE $type SET importance=$new_value, updated_at=datetime('now') WHERE slug='$slug'"
                echo "  Updated importance to: $new_value"
            else
                echo "  Invalid. Must be 1-10."
            fi
            ;;
        state)
            new_value="$(
                printf "%s\n" "${VALID_STATES[@]}" |
                fzf --prompt="state> " --height=5 --reverse
            )" || return
            sql "UPDATE $type SET state='$new_value', updated_at=datetime('now') WHERE slug='$slug'"
            echo "  Updated state to: $new_value"
            ;;
        *)
            echo "  Unknown field: $field"
            ;;
    esac
}

edit_tags() {
    local type="$1" slug="$2"

    local id
    id="$(sql "SELECT id FROM $type WHERE slug='$slug'")"

    echo
    echo "  Current tags:"
    sql "SELECT t.slug FROM tags t JOIN content_tags ct ON ct.tag_id = t.id WHERE ct.content_type = '$type' AND ct.content_id = $id ORDER BY t.slug" | while read -r tag; do
        echo "    - $tag"
    done

    echo
    echo "  Actions: [a]dd tag, [r]emove tag, [d]one"
    while true; do
        read -rp "  tag> " action
        case "$action" in
            a|add)
                local new_tag
                new_tag="$(
                    sql "SELECT slug FROM tags ORDER BY slug" |
                    fzf --prompt="add tag> " --height=20 --reverse
                )" || continue

                # Check if tag already linked
                local existing
                existing="$(sql "SELECT COUNT(*) FROM content_tags WHERE content_type='$type' AND content_id=$id AND tag_id=(SELECT id FROM tags WHERE slug='$new_tag')")"
                if [[ "$existing" -gt 0 ]]; then
                    echo "  Tag '$new_tag' already linked."
                    continue
                fi

                local tag_id
                tag_id="$(sql "SELECT id FROM tags WHERE slug='$new_tag'")"
                sql "INSERT INTO content_tags (content_type, content_id, tag_id) VALUES ('$type', $id, $tag_id)"
                echo "  Added tag: $new_tag"
                ;;
            r|remove)
                local rm_tag
                rm_tag="$(
                    sql "SELECT t.slug FROM tags t JOIN content_tags ct ON ct.tag_id = t.id WHERE ct.content_type = '$type' AND ct.content_id = $id ORDER BY t.slug" |
                    fzf --prompt="remove tag> " --height=10 --reverse
                )" || continue

                sql "DELETE FROM content_tags WHERE content_type='$type' AND content_id=$id AND tag_id=(SELECT id FROM tags WHERE slug='$rm_tag')"
                echo "  Removed tag: $rm_tag"
                ;;
            d|done|q|quit)
                break
                ;;
            *)
                echo "  Unknown action. Use [a]dd, [r]emove, or [d]one."
                ;;
        esac
    done
}

###############################################################################
# entry selection
###############################################################################

select_entry_fzf() {
    local type="$1"

    sql "SELECT title || '  (' || slug || ')' || char(9) || slug FROM $type WHERE state != '' ORDER BY title" |
    fzf --prompt="$type> " --delimiter=$'\t' --with-nth=1 \
        --preview="sqlite3 '$DB' \"SELECT 'Title: ' || title || char(10) || 'Preview: ' || COALESCE(preview,'') || char(10) || 'Category: ' || COALESCE(category_slug,'') || char(10) || 'State: ' || COALESCE(state,'active') FROM $type WHERE slug='{2}'\"" \
        --height=80% --reverse |
    awk -F'\t' '{print $2}'
}

select_entry_nnn() {
    local type="$1"
    local content_path="$CONTENT_DIR/$type"

    [[ ! -d "$content_path" ]] && { echo ""; return; }

    # Use nnn to pick a file, extract slug from filename
    local tmpfile
    tmpfile="$(mktemp)"

    NNN_TMPFILE="$tmpfile" nnn -p "$tmpfile" "$content_path"

    if [[ -s "$tmpfile" ]]; then
        local selected
        selected="$(cat "$tmpfile")"
        rm -f "$tmpfile"
        # Extract slug from filename: /path/to/my-slug.mdx -> my-slug
        basename "$selected" .mdx
    else
        rm -f "$tmpfile"
        echo ""
    fi
}

###############################################################################
# main
###############################################################################

main() {
    clear
    print_banner

    while true; do
        # Select content type
        local type
        type="$(
            printf "%s\n" "${CONTENT_TYPES[@]}" "quit" |
            fzf --prompt="type> " --height=15 --reverse
        )" || exit 0

        [[ "$type" == "quit" ]] && exit 0

        # Select how to pick entry
        local mode
        mode="$(
            printf "%s\n" "fzf (search by title)" "nnn (browse files)" "back" |
            fzf --prompt="select via> " --height=5 --reverse
        )" || continue

        [[ "$mode" == "back" ]] && continue

        local slug=""
        if [[ "$mode" == *"fzf"* ]]; then
            slug="$(select_entry_fzf "$type")" || continue
        else
            slug="$(select_entry_nnn "$type")" || continue
        fi

        [[ -z "$slug" ]] && continue

        # Verify slug exists in DB
        local count
        count="$(sql "SELECT COUNT(*) FROM $type WHERE slug='$slug'")"
        if [[ "$count" -eq 0 ]]; then
            echo "  Slug '$slug' not found in $type table."
            read -rp "  Press Enter..." _
            continue
        fi

        # Edit loop
        while true; do
            clear
            print_banner
            show_metadata "$type" "$slug"

            # Build field list based on type
            local fields
            if [[ "$type" == "diary" ]]; then
                fields=("${DIARY_FIELDS[@]}" "tags" "done")
            else
                fields=("${STANDARD_FIELDS[@]}" "tags" "done")
            fi

            local field
            field="$(
                printf "%s\n" "${fields[@]}" |
                fzf --prompt="edit field> " --height=12 --reverse
            )" || break

            [[ "$field" == "done" ]] && break

            edit_field "$type" "$slug" "$field"
            read -rp "  Press Enter..." _
        done
    done
}

main
