#!/usr/bin/env bash
# gstack-learnings-search — read and filter project learnings
# Usage: gstack-learnings-search [--type TYPE] [--query KEYWORD] [--limit N] [--cross-project]
#
# Reads ~/.gstack/projects/$SLUG/learnings.jsonl, applies confidence decay,
# resolves duplicates (latest winner per key+type), and outputs formatted text.
# Exit 0 silently if no learnings file exists.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
eval "$("$SCRIPT_DIR/gstack-slug" 2>/dev/null)"
GSTACK_HOME="${GSTACK_HOME:-$HOME/.gstack}"

TYPE=""
QUERY=""
LIMIT=10
CROSS_PROJECT=false

while [[ $# -gt 0 ]]; do
  case "$1" in
    --type) TYPE="$2"; shift 2 ;;
    --query) QUERY="$2"; shift 2 ;;
    --limit) LIMIT="$2"; shift 2 ;;
    --cross-project) CROSS_PROJECT=true; shift ;;
    *) shift ;;
  esac
done

LEARNINGS_FILE="$GSTACK_HOME/projects/$SLUG/learnings.jsonl"

# Collect all JSONL files to search
FILES=()
[ -f "$LEARNINGS_FILE" ] && FILES+=("$LEARNINGS_FILE")

if [ "$CROSS_PROJECT" = true ]; then
  # Add other projects' learnings (max 5, sorted by mtime)
  for f in $(find "$GSTACK_HOME/projects" -name "learnings.jsonl" -not -path "*/$SLUG/*" 2>/dev/null | head -5); do
    FILES+=("$f")
  done
fi

if [ ${#FILES[@]} -eq 0 ]; then
  exit 0
fi

# Process all files through bun for JSON parsing, decay, dedup, filtering
cat "${FILES[@]}" 2>/dev/null | bun -e "
const lines = (await Bun.stdin.text()).trim().split('\n').filter(Boolean);
const now = Date.now();
const type = '${TYPE}';
const query = '${QUERY}'.toLowerCase();
const limit = ${LIMIT};
const slug = '${SLUG}';

const entries = [];
for (const line of lines) {
  try {
    const e = JSON.parse(line);
    if (!e.key || !e.type) continue;

    // Apply confidence decay: observed/inferred lose 1pt per 30 days
    let conf = e.confidence || 5;
    if (e.source === 'observed' || e.source === 'inferred') {
      const days = Math.floor((now - new Date(e.ts).getTime()) / 86400000);
      conf = Math.max(0, conf - Math.floor(days / 30));
    }
    e._effectiveConfidence = conf;

    // Determine if this is from the current project or cross-project
    // Cross-project entries are tagged for display
    e._crossProject = !line.includes(slug) && '${CROSS_PROJECT}' === 'true';

    entries.push(e);
  } catch {}
}

// Dedup: latest winner per key+type
const seen = new Map();
for (const e of entries) {
  const dk = e.key + '|' + e.type;
  const existing = seen.get(dk);
  if (!existing || new Date(e.ts) > new Date(existing.ts)) {
    seen.set(dk, e);
  }
}
let results = Array.from(seen.values());

// Filter by type
if (type) results = results.filter(e => e.type === type);

// Filter by query
if (query) results = results.filter(e =>
  (e.key || '').toLowerCase().includes(query) ||
  (e.insight || '').toLowerCase().includes(query) ||
  (e.files || []).some(f => f.toLowerCase().includes(query))
);

// Sort by effective confidence desc, then recency
results.sort((a, b) => {
  if (b._effectiveConfidence !== a._effectiveConfidence) return b._effectiveConfidence - a._effectiveConfidence;
  return new Date(b.ts).getTime() - new Date(a.ts).getTime();
});

// Limit
results = results.slice(0, limit);

if (results.length === 0) process.exit(0);

// Format output
const byType = {};
for (const e of results) {
  const t = e.type || 'unknown';
  if (!byType[t]) byType[t] = [];
  byType[t].push(e);
}

// Summary line
const counts = Object.entries(byType).map(([t, arr]) => arr.length + ' ' + t + (arr.length > 1 ? 's' : ''));
console.log('LEARNINGS: ' + results.length + ' loaded (' + counts.join(', ') + ')');
console.log('');

for (const [t, arr] of Object.entries(byType)) {
  console.log('## ' + t.charAt(0).toUpperCase() + t.slice(1) + 's');
  for (const e of arr) {
    const cross = e._crossProject ? ' [cross-project]' : '';
    const files = e.files?.length ? ' (files: ' + e.files.join(', ') + ')' : '';
    console.log('- [' + e.key + '] (confidence: ' + e._effectiveConfidence + '/10, ' + e.source + ', ' + (e.ts || '').split('T')[0] + ')' + cross);
    console.log('  ' + e.insight + files);
  }
  console.log('');
}
" 2>/dev/null || exit 0
