#!/usr/bin/env bash
# analyze-room: Deterministic Room analysis for proactive intelligence
# Detects gaps (structural, semantic, adjacent), convergence themes, and structural contradictions
# Called by session-start hook; outputs structured lines for Claude to interpret
# Must complete in under 2 seconds

# macOS bash 3.2 compatibility -- Python3 fallback
if [ "${BASH_VERSINFO[0]:-0}" -lt 4 ]; then
  exec python3 - "$@" << 'PYEOF'
import sys, os, re, subprocess
from pathlib import Path
from datetime import datetime, date

ROOM_DIR = sys.argv[1] if len(sys.argv) > 1 else "./room"
SCRIPT_DIR = str(Path(__file__).resolve().parent) if '__file__' in dir() else os.path.dirname(os.path.abspath(sys.argv[0])) if sys.argv[0] != '-' else '.'

if not os.path.isdir(ROOM_DIR):
    print("NO_ROOM")
    sys.exit(0)

CORE_SECTIONS = [
    "problem-definition",
    "market-analysis",
    "solution-design",
    "business-model",
    "competitive-analysis",
    "team-execution",
    "legal-ip",
    "financial-model",
]

STRUCTURAL_DIRS = {"meetings", "team"}

# Dynamic section discovery
is_core_section = set(CORE_SECTIONS)
EXTENDED_SECTIONS = []

room_path = Path(ROOM_DIR)
if room_path.is_dir():
    for d in sorted(room_path.iterdir()):
        if not d.is_dir():
            continue
        name = d.name
        if name.startswith('.'):
            continue
        if name in STRUCTURAL_DIRS:
            continue
        if name in is_core_section:
            continue
        # Must contain at least one .md or STATE.md
        if (d / "STATE.md").is_file():
            EXTENDED_SECTIONS.append(name)
        elif any(d.glob("*.md")):
            EXTENDED_SECTIONS.append(name)

ALL_SECTIONS = CORE_SECTIONS + EXTENDED_SECTIONS

# Read venture stage
venture_stage = "Pre-Opportunity"
state_file = room_path / "STATE.md"
if state_file.is_file():
    for line in state_file.read_text(errors='replace').splitlines():
        if re.match(r'(?i)venture_stage:', line):
            venture_stage = re.sub(r'(?i).*venture_stage:\s*', '', line).strip().strip('"')
            break

# Helpers
def count_entries(section_dir):
    p = Path(section_dir)
    if not p.is_dir():
        return 0
    return sum(1 for f in p.glob("*.md") if f.name not in ("ROOM.md", "STATE.md"))

def get_methodologies(section_dir):
    p = Path(section_dir)
    if not p.is_dir():
        return []
    meths = set()
    for f in p.glob("*.md"):
        if f.name in ("ROOM.md", "STATE.md"):
            continue
        try:
            for line in f.read_text(errors='replace').splitlines():
                m = re.match(r'^methodology:\s*(.*)', line)
                if m:
                    meths.add(m.group(1).strip())
                    break
        except:
            pass
    return sorted(meths)

def md_files(section_dir):
    """Yield .md files in section_dir excluding ROOM.md and STATE.md."""
    p = Path(section_dir)
    if not p.is_dir():
        return
    for f in p.glob("*.md"):
        if f.name not in ("ROOM.md", "STATE.md"):
            yield f

# ═══════════════════════════════════════════════
# Section 1: Gap Detection
# ═══════════════════════════════════════════════
print("## Gaps")

entry_counts = {}
for section in ALL_SECTIONS:
    entry_counts[section] = count_entries(room_path / section)

for section in ALL_SECTIONS:
    count = entry_counts[section]
    section_dir = room_path / section

    if section in is_core_section:
        if venture_stage == "Pre-Opportunity":
            if section in ("financial-model", "legal-ip"):
                continue

        if count == 0:
            confidence = "HIGH"
            print(f"GAP:STRUCTURAL:{section}:{confidence}:Section is empty")
        elif count == 1:
            methodologies = get_methodologies(section_dir)
            method_count = len(methodologies)
            if method_count <= 1 and methodologies:
                print(f"GAP:SEMANTIC:{section}:MEDIUM:Only analyzed via {methodologies[0]} -- consider additional perspectives")
        else:
            methodologies = get_methodologies(section_dir)
            method_count = len(methodologies)
            if method_count <= 1 and methodologies:
                print(f"GAP:SEMANTIC:{section}:MEDIUM:Only analyzed via {methodologies[0]} -- consider additional perspectives")
    else:
        if count <= 1:
            print(f"STRUCTURAL_GAP:{section}:LOW:Section exists but has sparse content")

# Adjacent section gap
if entry_counts.get("problem-definition", 0) > 0 and entry_counts.get("solution-design", 0) > 0 and entry_counts.get("market-analysis", 0) == 0:
    print("GAP:ADJACENT:market-analysis:HIGH:Problem and solution explored but no market evidence yet")

print()

# ═══════════════════════════════════════════════
# Section 2: Convergence Detection
# ═══════════════════════════════════════════════
print("## Convergence")

NOISE_WORDS = set("analysis|framework|venture|methodology|section|evidence|definition|problem|market|solution|business|model|financial|competitive|approach|should|would|could|about|their|these|those|which|where|through|between|using|based|consider|important|different|provide".split("|"))

term_sections = {}  # term -> set of sections

for section in ALL_SECTIONS:
    section_dir = room_path / section
    for f in md_files(section_dir):
        try:
            content = f.read_text(errors='replace')
        except:
            continue
        # Extract headers and bold text
        headers = re.findall(r'^## (.+)$', content, re.MULTILINE)
        bolds = re.findall(r'\*\*([^*]+)\*\*', content)
        raw = ' '.join(headers + bolds).lower()
        terms = set(re.findall(r'[a-z]{5,}', raw))
        terms -= NOISE_WORDS
        for term in terms:
            if term not in term_sections:
                term_sections[term] = set()
            term_sections[term].add(section)

convergence_found = False
for term, sections in sorted(term_sections.items()):
    sc = len(sections)
    if sc >= 3:
        convergence_found = True
        print(f"CONVERGE:{term}:{sc}:MEDIUM:Appears in {sc} entries across multiple sections")

if not convergence_found:
    print("No convergence signals detected yet.")

print()

# ═══════════════════════════════════════════════
# Section 3: Contradiction Detection
# ═══════════════════════════════════════════════
print("## Contradictions")

b2b_sections = set()
b2c_sections = set()

for section in ALL_SECTIONS:
    section_dir = room_path / section
    for f in md_files(section_dir):
        try:
            content = f.read_text(errors='replace')
        except:
            continue
        if re.search(r'\bB2B\b|\benterprise\b', content, re.IGNORECASE):
            b2b_sections.add(section)
        if re.search(r'\bB2C\b|\bconsumer\b|\bindividual\b', content, re.IGNORECASE):
            b2c_sections.add(section)

contradiction_found = False
for b2b_sec in sorted(b2b_sections):
    for b2c_sec in sorted(b2c_sections):
        if b2b_sec != b2c_sec:
            contradiction_found = True
            print(f"CONTRADICT:{b2b_sec}:{b2c_sec}:MEDIUM:Customer type mismatch -- B2B/enterprise vs B2C/consumer")

if not contradiction_found:
    print("No structural contradictions detected.")

print()

# ═══════════════════════════════════════════════
# Section 3b: Cross-Reference Edges
# ═══════════════════════════════════════════════
print("## Cross-References")

cross_ref_found = False
xref_source_files = set()  # NATIVE-03: files participating in xref edges, to wikilink at scan time
for section in ALL_SECTIONS:
    section_dir = room_path / section
    for f in md_files(section_dir):
        try:
            content = f.read_text(errors='replace')
        except:
            continue
        for target in ALL_SECTIONS:
            if target == section:
                continue
            if re.search(rf'\[\[{re.escape(target)}\]\]|room/{re.escape(target)}', content):
                cross_ref_found = True
                xref_source_files.add(str(f))
                # Try visual-ops formatting via node, fallback to plain
                formatted = f"{section} INFORMS {target}"
                try:
                    lib_path = os.path.join(SCRIPT_DIR, '..', 'lib', 'core', 'visual-ops.cjs')
                    result = subprocess.run(
                        ['node', '-e', f"const v = require('{lib_path}'); console.log(v.formatEdge('{section}', '{target}', 'INFORMS'));"],
                        capture_output=True, text=True, timeout=2
                    )
                    if result.returncode == 0 and result.stdout.strip():
                        formatted = result.stdout.strip()
                except:
                    pass
                print(f"EDGE:{section}:{target}:INFORMS:{formatted}")

        # Check for contradiction proximity terms
        for target in ALL_SECTIONS:
            if target == section:
                continue
            if re.search(rf'contradict.*{re.escape(target)}|conflict.*{re.escape(target)}|inconsisten.*{re.escape(target)}', content, re.IGNORECASE):
                cross_ref_found = True
                xref_source_files.add(str(f))
                formatted = f"{section} CONTRADICTS {target}"
                try:
                    lib_path = os.path.join(SCRIPT_DIR, '..', 'lib', 'core', 'visual-ops.cjs')
                    result = subprocess.run(
                        ['node', '-e', f"const v = require('{lib_path}'); console.log(v.formatEdge('{section}', '{target}', 'CONTRADICTS'));"],
                        capture_output=True, text=True, timeout=2
                    )
                    if result.returncode == 0 and result.stdout.strip():
                        formatted = result.stdout.strip()
                except:
                    pass
                print(f"EDGE:{section}:{target}:CONTRADICTS:{formatted}")

if not cross_ref_found:
    print("No cross-reference edges detected yet.")

# NATIVE-03: wikilink every source file that participates in an xref edge,
# so cross-referenced artifacts arrive pre-linked rather than waiting for a
# retroactive /mos:room linkify pass. Soft-fails: any error here is logged to
# stderr but never breaks analyze-room.
wikilink_script = os.path.join(SCRIPT_DIR, 'wikilink-file.cjs')
wikilinked = 0
if xref_source_files and os.path.isfile(wikilink_script):
    for src in sorted(xref_source_files):
        try:
            r = subprocess.run(
                ['node', wikilink_script, ROOM_DIR, src],
                capture_output=True, text=True, timeout=5
            )
            if r.returncode == 0:
                wikilinked += 1
            else:
                sys.stderr.write(f"[analyze-room] wikilink-file failed for {src}: {r.stderr.strip()}\n")
        except Exception as e:
            sys.stderr.write(f"[analyze-room] wikilink-file error for {src}: {e}\n")
    if wikilinked:
        print(f"WIKILINK_SWEEP:xref:{wikilinked}:wikilinked {wikilinked} xref source files")

print()

# ═══════════════════════════════════════════════
# Section 4: Meeting Intelligence
# ═══════════════════════════════════════════════
print("## Meeting Coverage")

meeting_count = 0
meetings_dir = room_path / "meetings"
if meetings_dir.is_dir():
    for d in meetings_dir.iterdir():
        if d.is_dir():
            meeting_count += 1

if meeting_count > 0:
    print(f"MEETING_COUNT:{meeting_count}")

    meeting_sourced = {}
    for section in ALL_SECTIONS:
        section_dir = room_path / section
        if not section_dir.is_dir():
            continue
        meeting_sourced[section] = 0
        for f in md_files(section_dir):
            try:
                for line in f.read_text(errors='replace').splitlines():
                    if line.strip() == 'source: transcript':
                        meeting_sourced[section] += 1
                        break
            except:
                pass

    for section in ALL_SECTIONS:
        count = meeting_sourced.get(section, 0)
        total = entry_counts[section]
        if total > 0 and count == 0:
            print(f"GAP:MEETING_COVERAGE:{section}:LOW:No meeting insights filed here -- is this section discussed in meetings?")
        elif count > 0:
            print(f"MEETING_SOURCED:{section}:{count}:{total}")
else:
    print("No meetings filed yet. Use /mindrian-os:file-meeting to capture meeting intelligence.")

print()

# ═══════════════════════════════════════════════
# Section 5: Opportunity Bank Intelligence
# ═══════════════════════════════════════════════
print("## Opportunity Bank")

opp_bank = room_path / "opportunity-bank"
if opp_bank.is_dir():
    opp_status_counts = {}
    opp_file_count = 0

    for f in opp_bank.glob("*.md"):
        if f.name in ("STATE.md", "ROOM.md"):
            continue
        opp_file_count += 1
        status = "unknown"
        try:
            for line in f.read_text(errors='replace').splitlines():
                m = re.match(r'^status:\s*(.*)', line)
                if m:
                    status = m.group(1).strip().strip('"')
                    break
        except:
            pass
        opp_status_counts[status] = opp_status_counts.get(status, 0) + 1

    if opp_file_count == 0:
        print("Opportunity bank exists but has no filed opportunities.")
    else:
        for status, cnt in sorted(opp_status_counts.items()):
            print(f"OPP_STATUS:{status}:{cnt}")

        # Top by relevance
        opp_relevance = []
        for f in opp_bank.glob("*.md"):
            if f.name in ("STATE.md", "ROOM.md"):
                continue
            rel_score = None
            funder = ""
            try:
                for line in f.read_text(errors='replace').splitlines():
                    m = re.match(r'^relevance_score:\s*(.*)', line)
                    if m:
                        rel_score = m.group(1).strip().strip('"')
                    m2 = re.match(r'^funder:\s*(.*)', line)
                    if m2:
                        funder = m2.group(1).strip().strip('"')
            except:
                pass
            if rel_score:
                opp_relevance.append((rel_score, f.name, funder))

        if opp_relevance:
            opp_relevance.sort(key=lambda x: float(x[0]) if x[0].replace('.','',1).isdigit() else 0, reverse=True)
            for score, name, funder_name in opp_relevance[:3]:
                print(f"OPP_TOP_RELEVANCE:{name}:{score}:{funder_name}")

        # Upcoming deadlines
        today_str = date.today().strftime("%Y-%m-%d")
        opp_deadlines = []
        for f in opp_bank.glob("*.md"):
            if f.name in ("STATE.md", "ROOM.md"):
                continue
            deadline = None
            funder = ""
            try:
                for line in f.read_text(errors='replace').splitlines():
                    m = re.match(r'^deadline:\s*(.*)', line)
                    if m:
                        deadline = m.group(1).strip().strip('"')
                    m2 = re.match(r'^funder:\s*(.*)', line)
                    if m2:
                        funder = m2.group(1).strip().strip('"')
            except:
                pass
            if deadline and deadline >= today_str:
                opp_deadlines.append((deadline, f.name, funder))

        if opp_deadlines:
            opp_deadlines.sort(key=lambda x: x[0])
            for dl, name, funder_name in opp_deadlines[:5]:
                print(f"OPP_DEADLINE:{name}:{dl}:{funder_name}")

    # Funding pipeline
    funding_dir = room_path / "funding"
    if funding_dir.is_dir():
        fund_stage_counts = {}

        for fund_dir in sorted(funding_dir.iterdir()):
            if not fund_dir.is_dir():
                continue
            status_file = fund_dir / "STATUS.md"
            if not status_file.is_file():
                continue

            stage = "unknown"
            last_updated = None
            try:
                for line in status_file.read_text(errors='replace').splitlines():
                    m = re.match(r'^stage:\s*(.*)', line)
                    if m:
                        stage = m.group(1).strip().strip('"')
                    m2 = re.match(r'^last_updated:\s*(.*)', line)
                    if m2:
                        last_updated = m2.group(1).strip().strip('"')
            except:
                pass

            fund_stage_counts[stage] = fund_stage_counts.get(stage, 0) + 1

            if last_updated:
                try:
                    lu_date = datetime.strptime(last_updated, "%Y-%m-%d").date()
                    days_since = (date.today() - lu_date).days
                    if days_since > 14:
                        print(f"FUND_STALE:{fund_dir.name}:{days_since}")
                except:
                    pass

        for stage, cnt in sorted(fund_stage_counts.items()):
            print(f"FUND_STAGE:{stage}:{cnt}")
else:
    print("No opportunity bank in this room.")

print()

# ── Capability Suggestions ──
total_artifacts = 0
for s in ALL_SECTIONS:
    section_dir = room_path / s
    if not section_dir.is_dir():
        continue
    for f in section_dir.glob("*.md"):
        if f.name not in ("ROOM.md", "STATE.md"):
            total_artifacts += 1

# Recount meetings for capability section
meeting_count = 0
if meetings_dir.is_dir():
    for d in meetings_dir.iterdir():
        if d.is_dir():
            meeting_count += 1

team_count = 0
team_dir = room_path / "team"
if team_dir.is_dir():
    for role_dir in ["members", "mentors", "advisors"]:
        rd = team_dir / role_dir
        if rd.is_dir():
            for p in rd.iterdir():
                if p.is_dir():
                    team_count += 1

if 3 <= total_artifacts < 7:
    print(f"CAPABILITY:DASHBOARD:MEDIUM:You have {total_artifacts} artifacts -- /mos:room view launches an interactive knowledge graph showing how they connect")

if total_artifacts >= 7:
    print(f"CAPABILITY:DASHBOARD:HIGH:Your room has {total_artifacts} artifacts across multiple sections -- /mos:room view shows the full knowledge graph with intelligence overlays")
    print(f"CAPABILITY:EXPORT_DASHBOARD:HIGH:Export a shareable dashboard with /mos:room export -- standalone HTML with your full graph visualization")

if total_artifacts >= 5 and meeting_count >= 1:
    print(f"CAPABILITY:WIKI:MEDIUM:With {total_artifacts} artifacts and {meeting_count} meeting(s), /mos:wiki gives you a searchable Wikipedia-style view with wikilinks")

if total_artifacts >= 3 and meeting_count >= 2:
    print(f"CAPABILITY:MEETING_REPORT:MEDIUM:{meeting_count} meetings filed -- /mos:export meeting-report generates a Minto-structured intelligence report")

if total_artifacts >= 10:
    print(f"CAPABILITY:THESIS:HIGH:Room is substantial ({total_artifacts} artifacts) -- /mos:export thesis generates an investment thesis PDF")

if team_count >= 2:
    print(f"CAPABILITY:TEAM_VIEW:MEDIUM:{team_count} team profiles -- /mos:room view shows them as nodes connected to meetings and sections")

print()
print("## End")
sys.exit(0)
PYEOF
fi

set -euo pipefail

# Portable date -d replacement (macOS lacks GNU date -d)
portable_date_to_epoch() {
  local datestr="$1"
  date -d "$datestr" +%s 2>/dev/null \
    || date -j -f "%Y-%m-%d" "$datestr" +%s 2>/dev/null \
    || python3 -c "from datetime import datetime; print(int(datetime.strptime('$datestr','%Y-%m-%d').timestamp()))" 2>/dev/null \
    || echo "0"
}

ROOM_DIR="${1:-./room}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

if [ ! -d "$ROOM_DIR" ]; then
  echo "NO_ROOM"
  exit 0
fi

# ── 8 DD-aligned core sections (for gap messaging and section-specific logic) ──
CORE_SECTIONS=(
  problem-definition
  market-analysis
  solution-design
  business-model
  competitive-analysis
  team-execution
  legal-ip
  financial-model
)

# ── Structural directories (not sections) ──
STRUCTURAL_DIRS=("meetings" "team")

# ── Dynamic section discovery ──
# Scan room directory for section directories (contains .md or STATE.md)
EXTENDED_SECTIONS=()
declare -A is_core_section
declare -A is_structural_dir
for s in "${CORE_SECTIONS[@]}"; do is_core_section["$s"]=1; done
for s in "${STRUCTURAL_DIRS[@]}"; do is_structural_dir["$s"]=1; done

if [ -d "$ROOM_DIR" ]; then
  for dir in "$ROOM_DIR"/*/; do
    [ -d "$dir" ] || continue
    dir_name=$(basename "$dir")
    # Skip hidden directories
    [[ "$dir_name" == .* ]] && continue
    # Skip structural directories
    [ -n "${is_structural_dir[$dir_name]:-}" ] && continue
    # Skip core sections (already in CORE_SECTIONS)
    [ -n "${is_core_section[$dir_name]:-}" ] && continue
    # Qualify: must contain at least one .md file or STATE.md
    has_content=false
    if [ -f "${dir}STATE.md" ]; then
      has_content=true
    else
      md_count=$(find "$dir" -maxdepth 1 -name "*.md" 2>/dev/null | head -1)
      [ -n "$md_count" ] && has_content=true
    fi
    $has_content && EXTENDED_SECTIONS+=("$dir_name")
  done
fi

# Combine core + extended for iteration
ALL_SECTIONS=("${CORE_SECTIONS[@]}" "${EXTENDED_SECTIONS[@]}")

# ── Read venture stage from STATE.md ──
venture_stage="Pre-Opportunity"
if [ -f "${ROOM_DIR}/STATE.md" ]; then
  stage_line=$(grep -i 'venture_stage:' "${ROOM_DIR}/STATE.md" 2>/dev/null | head -1 || true)
  if [ -n "$stage_line" ]; then
    venture_stage=$(echo "$stage_line" | sed 's/.*venture_stage:[[:space:]]*//' | tr -d '"' | xargs)
  fi
fi

# ── Helper: count entries in a section (excludes ROOM.md, STATE.md) ──
count_entries() {
  local dir="$1"
  if [ ! -d "$dir" ]; then
    echo 0
    return
  fi
  find "$dir" -maxdepth 1 -name "*.md" ! -name "ROOM.md" ! -name "STATE.md" 2>/dev/null | wc -l | tr -d ' '
}

# ── Helper: get unique methodologies in a section ──
get_methodologies() {
  local dir="$1"
  if [ ! -d "$dir" ]; then
    return
  fi
  for f in "$dir"/*.md; do
    [ -f "$f" ] || continue
    fname=$(basename "$f")
    [ "$fname" = "ROOM.md" ] || [ "$fname" = "STATE.md" ] && continue
    grep -m1 '^methodology:' "$f" 2>/dev/null | sed 's/methodology:[[:space:]]*//' || true
  done | sort -u
}

# ═══════════════════════════════════════════════
# Section 1: Gap Detection
# ═══════════════════════════════════════════════
echo "## Gaps"

# Build entry counts for adjacency checks
declare -A entry_counts
for section in "${ALL_SECTIONS[@]}"; do
  entry_counts["$section"]=$(count_entries "${ROOM_DIR}/${section}")
done

for section in "${ALL_SECTIONS[@]}"; do
  count="${entry_counts[$section]}"
  section_dir="${ROOM_DIR}/${section}"

  # Core section gap logic (venture stage filtering, specific messages)
  if [ -n "${is_core_section[$section]:-}" ]; then
    # Venture stage filtering: suppress irrelevant gaps
    if [ "$venture_stage" = "Pre-Opportunity" ]; then
      if [ "$section" = "financial-model" ] || [ "$section" = "legal-ip" ]; then
        continue
      fi
    fi

    if [ "$count" -eq 0 ]; then
      # Investment stage: elevate all empty sections to HIGH
      confidence="HIGH"
      echo "GAP:STRUCTURAL:${section}:${confidence}:Section is empty"
    elif [ "$count" -eq 1 ]; then
      # Single entry -- check for single-lens (one methodology)
      methodologies=$(get_methodologies "$section_dir")
      method_count=$(echo "$methodologies" | grep -c '.' 2>/dev/null || true)
      method_count=${method_count:-0}
      if [ "$method_count" -le 1 ] && [ -n "$methodologies" ]; then
        method_name=$(echo "$methodologies" | head -1)
        echo "GAP:SEMANTIC:${section}:MEDIUM:Only analyzed via ${method_name} -- consider additional perspectives"
      fi
    else
      # Multiple entries -- check if all share same methodology
      methodologies=$(get_methodologies "$section_dir")
      method_count=$(echo "$methodologies" | grep -c '.' 2>/dev/null || true)
      method_count=${method_count:-0}
      if [ "$method_count" -le 1 ] && [ -n "$methodologies" ]; then
        method_name=$(echo "$methodologies" | head -1)
        echo "GAP:SEMANTIC:${section}:MEDIUM:Only analyzed via ${method_name} -- consider additional perspectives"
      fi
    fi
  else
    # Extended section: generic gap message for sparse content
    if [ "$count" -le 1 ]; then
      echo "STRUCTURAL_GAP:${section}:LOW:Section exists but has sparse content"
    fi
  fi
done

# Adjacent section gap: problem + solution filled but market empty
if [ "${entry_counts[problem-definition]}" -gt 0 ] && [ "${entry_counts[solution-design]}" -gt 0 ] && [ "${entry_counts[market-analysis]}" -eq 0 ]; then
  echo "GAP:ADJACENT:market-analysis:HIGH:Problem and solution explored but no market evidence yet"
fi

echo ""

# ═══════════════════════════════════════════════
# Section 2: Convergence Detection
# ═══════════════════════════════════════════════
echo "## Convergence"

# Noise words to filter out (common methodology terms)
NOISE_WORDS="analysis|framework|venture|methodology|section|evidence|definition|problem|market|solution|business|model|financial|competitive|approach|should|would|could|about|their|these|those|which|where|through|between|using|based|consider|important|different|provide"

# Collect terms from headers and bold text across sections, tracking which section each came from
declare -A term_sections  # term -> "section1|section2|..."

for section in "${ALL_SECTIONS[@]}"; do
  section_dir="${ROOM_DIR}/${section}"
  [ -d "$section_dir" ] || continue

  for f in "$section_dir"/*.md; do
    [ -f "$f" ] || continue
    fname=$(basename "$f")
    [ "$fname" = "ROOM.md" ] || [ "$fname" = "STATE.md" ] && continue

    # Extract headers (## lines) and bold text (**text**)
    terms=$(grep -oE '## [^\n]+|\*\*[^*]+\*\*' "$f" 2>/dev/null | \
      sed 's/^## //' | sed 's/\*\*//g' | \
      tr '[:upper:]' '[:lower:]' | \
      grep -oE '[a-z]{5,}' | \
      grep -vE "^(${NOISE_WORDS})$" | \
      sort -u || true)

    for term in $terms; do
      existing="${term_sections[$term]:-}"
      if [ -z "$existing" ]; then
        term_sections["$term"]="$section"
      elif ! echo "$existing" | grep -q "$section"; then
        term_sections["$term"]="${existing}|${section}"
      fi
    done
  done
done

# Find terms appearing in 3+ different sections
convergence_found=false
for term in "${!term_sections[@]}"; do
  sections_str="${term_sections[$term]}"
  section_count=$(echo "$sections_str" | tr '|' '\n' | wc -l | tr -d ' ')
  if [ "$section_count" -ge 3 ]; then
    convergence_found=true
    echo "CONVERGE:${term}:${section_count}:MEDIUM:Appears in ${section_count} entries across multiple sections"
  fi
done

if ! $convergence_found; then
  echo "No convergence signals detected yet."
fi

echo ""

# ═══════════════════════════════════════════════
# Section 3: Contradiction Detection
# ═══════════════════════════════════════════════
echo "## Contradictions"

# Structural contradiction: conflicting customer type terms across sections
declare -A b2b_sections
declare -A b2c_sections

for section in "${ALL_SECTIONS[@]}"; do
  section_dir="${ROOM_DIR}/${section}"
  [ -d "$section_dir" ] || continue

  for f in "$section_dir"/*.md; do
    [ -f "$f" ] || continue
    fname=$(basename "$f")
    [ "$fname" = "ROOM.md" ] || [ "$fname" = "STATE.md" ] && continue

    content=$(cat "$f" 2>/dev/null || true)

    # Check for B2B/enterprise indicators
    if echo "$content" | grep -iqE '\bB2B\b|\benterprise\b'; then
      b2b_sections["$section"]=1
    fi

    # Check for B2C/consumer/individual indicators
    if echo "$content" | grep -iqE '\bB2C\b|\bconsumer\b|\bindividual\b'; then
      b2c_sections["$section"]=1
    fi
  done
done

contradiction_found=false
for b2b_sec in "${!b2b_sections[@]}"; do
  for b2c_sec in "${!b2c_sections[@]}"; do
    if [ "$b2b_sec" != "$b2c_sec" ]; then
      contradiction_found=true
      echo "CONTRADICT:${b2b_sec}:${b2c_sec}:MEDIUM:Customer type mismatch -- B2B/enterprise vs B2C/consumer"
    fi
  done
done

if ! $contradiction_found; then
  echo "No structural contradictions detected."
fi

echo ""

# ═══════════════════════════════════════════════
# Section 3b: Cross-Reference Edges (visual)
# ═══════════════════════════════════════════════
echo "## Cross-References"

cross_ref_found=false
# NATIVE-03: collect xref source files for post-detection wikilinking sweep
XREF_SOURCE_FILES=""
for section in "${ALL_SECTIONS[@]}"; do
  section_dir="${ROOM_DIR}/${section}"
  [ -d "$section_dir" ] || continue

  for f in "$section_dir"/*.md; do
    [ -f "$f" ] || continue
    fname=$(basename "$f")
    [ "$fname" = "ROOM.md" ] || [ "$fname" = "STATE.md" ] && continue

    for target in "${ALL_SECTIONS[@]}"; do
      [ "$target" = "$section" ] && continue
      if grep -qE "\[\[$target\]\]|room/$target" "$f" 2>/dev/null; then
        cross_ref_found=true
        XREF_SOURCE_FILES="${XREF_SOURCE_FILES}${f}"$'\n'
        # Format edge with visual-ops symbols (graceful degradation)
        FORMATTED_EDGE=$(node -e "
          const v = require('$SCRIPT_DIR/../lib/core/visual-ops.cjs');
          console.log(v.formatEdge('$section', '$target', 'INFORMS'));
        " 2>/dev/null || echo "$section INFORMS $target")
        echo "EDGE:${section}:${target}:INFORMS:${FORMATTED_EDGE}"
      fi
    done

    # Check for contradiction proximity terms
    content=$(cat "$f" 2>/dev/null || true)
    for target in "${ALL_SECTIONS[@]}"; do
      [ "$target" = "$section" ] && continue
      if echo "$content" | grep -iqE "contradict.*$target|conflict.*$target|inconsisten.*$target" 2>/dev/null; then
        cross_ref_found=true
        XREF_SOURCE_FILES="${XREF_SOURCE_FILES}${f}"$'\n'
        FORMATTED_EDGE=$(node -e "
          const v = require('$SCRIPT_DIR/../lib/core/visual-ops.cjs');
          console.log(v.formatEdge('$section', '$target', 'CONTRADICTS'));
        " 2>/dev/null || echo "$section CONTRADICTS $target")
        echo "EDGE:${section}:${target}:CONTRADICTS:${FORMATTED_EDGE}"
      fi
    done
  done
done

if ! $cross_ref_found; then
  echo "No cross-reference edges detected yet."
fi

# NATIVE-03: wikilink every source file that participates in an xref edge,
# so cross-referenced artifacts arrive pre-linked rather than waiting for
# /mos:room linkify. Soft-fails: any error is logged to stderr but never
# breaks analyze-room's exit code.
WIKILINK_SCRIPT="${SCRIPT_DIR}/wikilink-file.cjs"
if [ -n "$XREF_SOURCE_FILES" ] && [ -f "$WIKILINK_SCRIPT" ]; then
  wl_count=0
  # Dedupe via sort -u
  while IFS= read -r src; do
    [ -z "$src" ] && continue
    if node "$WIKILINK_SCRIPT" "$ROOM_DIR" "$src" >/dev/null 2>>/tmp/analyze-room-wikilink.err; then
      wl_count=$((wl_count + 1))
    else
      echo "[analyze-room] wikilink-file failed for $src" >&2
    fi
  done < <(printf '%s' "$XREF_SOURCE_FILES" | sort -u)
  if [ "$wl_count" -gt 0 ]; then
    echo "WIKILINK_SWEEP:xref:${wl_count}:wikilinked ${wl_count} xref source files"
  fi
fi

echo ""

# ═══════════════════════════════════════════════
# Section 4: Meeting Intelligence
# ═══════════════════════════════════════════════
echo "## Meeting Coverage"

# Count meetings
meeting_count=0
if [ -d "$ROOM_DIR/meetings" ]; then
  for meeting_dir in "$ROOM_DIR"/meetings/*/; do
    [ -d "$meeting_dir" ] || continue
    meeting_count=$((meeting_count + 1))
  done
fi

if [ "$meeting_count" -gt 0 ]; then
  echo "MEETING_COUNT:${meeting_count}"

  # Track which sections have meeting-sourced artifacts
  declare -A meeting_sourced_sections
  for section in "${ALL_SECTIONS[@]}"; do
    section_dir="${ROOM_DIR}/${section}"
    [ -d "$section_dir" ] || continue
    meeting_sourced_sections["$section"]=0

    for f in "$section_dir"/*.md; do
      [ -f "$f" ] || continue
      fname=$(basename "$f")
      [ "$fname" = "ROOM.md" ] || [ "$fname" = "STATE.md" ] && continue

      if grep -q '^source: transcript' "$f" 2>/dev/null; then
        meeting_sourced_sections["$section"]=$((${meeting_sourced_sections[$section]} + 1))
      fi
    done
  done

  # Report meeting-sourced artifact distribution
  for section in "${ALL_SECTIONS[@]}"; do
    count="${meeting_sourced_sections[$section]:-0}"
    total="${entry_counts[$section]}"
    if [ "$total" -gt 0 ] && [ "$count" -eq 0 ]; then
      echo "GAP:MEETING_COVERAGE:${section}:LOW:No meeting insights filed here -- is this section discussed in meetings?"
    elif [ "$count" -gt 0 ]; then
      echo "MEETING_SOURCED:${section}:${count}:${total}"
    fi
  done
else
  echo "No meetings filed yet. Use /mindrian-os:file-meeting to capture meeting intelligence."
fi

echo ""

# ═══════════════════════════════════════════════
# Section 5: Opportunity Bank Intelligence (OPP-04)
# ═══════════════════════════════════════════════
echo "## Opportunity Bank"

if [ -d "$ROOM_DIR/opportunity-bank" ]; then
  # Count opportunities by status
  declare -A opp_status_counts
  opp_file_count=0

  for f in "$ROOM_DIR"/opportunity-bank/*.md; do
    [ -f "$f" ] || continue
    fname=$(basename "$f")
    [ "$fname" = "STATE.md" ] || [ "$fname" = "ROOM.md" ] && continue

    opp_file_count=$((opp_file_count + 1))

    # Parse status from frontmatter
    status=$(grep -m1 '^status:' "$f" 2>/dev/null | sed 's/status:[[:space:]]*//' | tr -d '"' | xargs)
    status=${status:-unknown}
    opp_status_counts["$status"]=$(( ${opp_status_counts[$status]:-0} + 1 ))
  done

  if [ "$opp_file_count" -eq 0 ]; then
    echo "Opportunity bank exists but has no filed opportunities."
  else
    # Output count by status
    for status in "${!opp_status_counts[@]}"; do
      echo "OPP_STATUS:${status}:${opp_status_counts[$status]}"
    done

    # Top by relevance (up to 3)
    declare -a opp_relevance_lines=()
    for f in "$ROOM_DIR"/opportunity-bank/*.md; do
      [ -f "$f" ] || continue
      fname=$(basename "$f")
      [ "$fname" = "STATE.md" ] || [ "$fname" = "ROOM.md" ] && continue

      rel_score=$(grep -m1 '^relevance_score:' "$f" 2>/dev/null | sed 's/relevance_score:[[:space:]]*//' | tr -d '"' | xargs)
      funder=$(grep -m1 '^funder:' "$f" 2>/dev/null | sed 's/funder:[[:space:]]*//' | tr -d '"' | xargs)
      [ -n "$rel_score" ] && opp_relevance_lines+=("${rel_score}:${fname}:${funder}")
    done

    # Sort descending by relevance, take top 3
    if [ ${#opp_relevance_lines[@]} -gt 0 ]; then
      printf '%s\n' "${opp_relevance_lines[@]}" | sort -t: -k1 -rn | head -3 | while IFS=: read -r score name funder_name; do
        echo "OPP_TOP_RELEVANCE:${name}:${score}:${funder_name}"
      done
    fi

    # Upcoming deadlines (future dates, up to 5)
    today_str=$(date +%Y-%m-%d)
    declare -a opp_deadline_lines=()
    for f in "$ROOM_DIR"/opportunity-bank/*.md; do
      [ -f "$f" ] || continue
      fname=$(basename "$f")
      [ "$fname" = "STATE.md" ] || [ "$fname" = "ROOM.md" ] && continue

      deadline=$(grep -m1 '^deadline:' "$f" 2>/dev/null | sed 's/deadline:[[:space:]]*//' | tr -d '"' | xargs)
      funder=$(grep -m1 '^funder:' "$f" 2>/dev/null | sed 's/funder:[[:space:]]*//' | tr -d '"' | xargs)
      if [ -n "$deadline" ] && [[ "$deadline" > "$today_str" || "$deadline" = "$today_str" ]]; then
        opp_deadline_lines+=("${deadline}:${fname}:${funder}")
      fi
    done

    # Sort ascending by deadline, take top 5
    if [ ${#opp_deadline_lines[@]} -gt 0 ]; then
      printf '%s\n' "${opp_deadline_lines[@]}" | sort -t: -k1 | head -5 | while IFS=: read -r dl name funder_name; do
        echo "OPP_DEADLINE:${name}:${dl}:${funder_name}"
      done
    fi
  fi

  # Funding pipeline summary (if funding/ exists)
  if [ -d "$ROOM_DIR/funding" ]; then
    declare -A fund_stage_counts

    for fund_dir in "$ROOM_DIR"/funding/*/; do
      [ -d "$fund_dir" ] || continue
      status_file="${fund_dir}STATUS.md"
      [ -f "$status_file" ] || continue

      stage=$(grep -m1 '^stage:' "$status_file" 2>/dev/null | sed 's/stage:[[:space:]]*//' | tr -d '"' | xargs)
      stage=${stage:-unknown}
      fund_stage_counts["$stage"]=$(( ${fund_stage_counts[$stage]:-0} + 1 ))

      # Check for stale entries (last_updated > 14 days ago)
      last_updated=$(grep -m1 '^last_updated:' "$status_file" 2>/dev/null | sed 's/last_updated:[[:space:]]*//' | tr -d '"' | xargs)
      if [ -n "$last_updated" ]; then
        last_epoch=$(portable_date_to_epoch "$last_updated")
        now_epoch=$(date +%s)
        if [ "$last_epoch" -gt 0 ]; then
          days_since=$(( (now_epoch - last_epoch) / 86400 ))
          if [ "$days_since" -gt 14 ]; then
            slug=$(basename "$fund_dir")
            echo "FUND_STALE:${slug}:${days_since}"
          fi
        fi
      fi
    done

    # Output count by stage
    for stage in "${!fund_stage_counts[@]}"; do
      echo "FUND_STAGE:${stage}:${fund_stage_counts[$stage]}"
    done
  fi
else
  echo "No opportunity bank in this room."
fi

echo ""

# ── Capability Suggestions ──
# Surface visualization and export commands when the room has enough data
# These are LazyGraph-informed: suggest capabilities when they become meaningful

total_artifacts=0
for s in "${CORE_SECTIONS[@]}" "${EXTENDED_SECTIONS[@]}"; do
  section_dir="${ROOM_DIR}/${s}"
  [ -d "$section_dir" ] || continue
  for f in "$section_dir"/*.md; do
    [ -f "$f" ] || continue
    fname=$(basename "$f")
    [ "$fname" = "ROOM.md" ] || [ "$fname" = "STATE.md" ] && continue
    total_artifacts=$((total_artifacts + 1))
  done
done

# Count edges (meetings, team, wikilinks for graph richness)
meeting_count=0
if [ -d "$ROOM_DIR/meetings" ]; then
  for mdir in "$ROOM_DIR"/meetings/*/; do
    [ -d "$mdir" ] || continue
    meeting_count=$((meeting_count + 1))
  done
fi

team_count=0
if [ -d "$ROOM_DIR/team" ]; then
  for role_dir in "$ROOM_DIR"/team/members/ "$ROOM_DIR"/team/mentors/ "$ROOM_DIR"/team/advisors/; do
    [ -d "$role_dir" ] || continue
    for p in "$role_dir"*/; do
      [ -d "$p" ] && team_count=$((team_count + 1))
    done
  done
fi

# Threshold-based capability suggestions
if [ "$total_artifacts" -ge 3 ] && [ "$total_artifacts" -lt 7 ]; then
  echo "CAPABILITY:DASHBOARD:MEDIUM:You have ${total_artifacts} artifacts -- /mos:room view launches an interactive knowledge graph showing how they connect"
fi

if [ "$total_artifacts" -ge 7 ]; then
  echo "CAPABILITY:DASHBOARD:HIGH:Your room has ${total_artifacts} artifacts across multiple sections -- /mos:room view shows the full knowledge graph with intelligence overlays"
  echo "CAPABILITY:EXPORT_DASHBOARD:HIGH:Export a shareable dashboard with /mos:room export -- standalone HTML with your full graph visualization"
fi

if [ "$total_artifacts" -ge 5 ] && [ "$meeting_count" -ge 1 ]; then
  echo "CAPABILITY:WIKI:MEDIUM:With ${total_artifacts} artifacts and ${meeting_count} meeting(s), /mos:wiki gives you a searchable Wikipedia-style view with wikilinks"
fi

if [ "$total_artifacts" -ge 3 ] && [ "$meeting_count" -ge 2 ]; then
  echo "CAPABILITY:MEETING_REPORT:MEDIUM:${meeting_count} meetings filed -- /mos:export meeting-report generates a Minto-structured intelligence report"
fi

if [ "$total_artifacts" -ge 10 ]; then
  echo "CAPABILITY:THESIS:HIGH:Room is substantial (${total_artifacts} artifacts) -- /mos:export thesis generates an investment thesis PDF"
fi

if [ "$team_count" -ge 2 ]; then
  echo "CAPABILITY:TEAM_VIEW:MEDIUM:${team_count} team profiles -- /mos:room view shows them as nodes connected to meetings and sections"
fi

echo ""
echo "## End"
