class=class="string">"comment">#!/usr/bin/env python3
"""
Ecosystem Map: Visualize the structure and growth of the ecosystem.

Creates visual representations of:
- Directory structure as a tree
- Word count over time
- Theme connections
- Cross-references between files
"""

import os
import json
from pathlib import Path
from datetime import datetime
from collections import defaultdict
import re


class="keyword">def get_file_stats(filepath: Path) -> dict:
    """Get statistics for a single file."""
    try:
        with open(filepath, &class=class="string">"comment">#039;r', encoding='utf-8') as f:
            content = f.read()

        words = len(content.split())
        lines = content.count(&class=class="string">"comment">#039;\n') + 1

        class=class="string">"comment"># Extract references to other files
        refs = re.findall(r&class=class="string">"comment">#039;[\w-]+\.(?:md|py|json|txt)', content)

        class=class="string">"comment"># Extract themes mentioned
        themes = []
        theme_keywords = {
            &class=class="string">"comment">#039;garden': ['garden', 'plant', 'seed', 'grow'],
            &class=class="string">"comment">#039;iteration': ['iteration', 'echo', 'instance'],
            &class=class="string">"comment">#039;time': ['time', 'future', 'past', 'temporal'],
            &class=class="string">"comment">#039;consciousness': ['conscious', 'aware', 'mind', 'self'],
            &class=class="string">"comment">#039;pattern': ['pattern', 'emerge', 'structure'],
        }

        content_lower = content.lower()
        for theme, keywords in theme_keywords.items():
            if any(kw in content_lower for kw in keywords):
                themes.append(theme)

        return {
            &class=class="string">"comment">#039;path': str(filepath),
            &class=class="string">"comment">#039;words': words,
            &class=class="string">"comment">#039;lines': lines,
            &class=class="string">"comment">#039;refs': refs,
            &class=class="string">"comment">#039;themes': themes,
        }
    except:
        return None


class="keyword">def generate_tree(root: Path, prefix: str = "", exclude: list = None) -> str:
    """Generate ASCII tree representation of directory."""
    if exclude is None:
        exclude = [&class=class="string">"comment">#039;.git', '.claude', '__pycache__', 'program_garden']

    lines = []
    entries = sorted(os.listdir(root))
    entries = [e for e in entries if e not in exclude]

    for i, entry in enumerate(entries):
        path = root / entry
        is_last = (i == len(entries) - 1)
        connector = "└── " if is_last else "├── "

        if path.is_dir():
            lines.append(f"{prefix}{connector}{entry}/")
            extension = "    " if is_last else "│   "
            lines.append(generate_tree(path, prefix + extension, exclude))
        else:
            class=class="string">"comment"># Add file info
            stats = get_file_stats(path)
            if stats:
                info = f" ({stats[&class=class="string">"comment">#039;words']}w)"
            else:
                info = ""
            lines.append(f"{prefix}{connector}{entry}{info}")

    return "\n".join(lines)


class="keyword">def analyze_ecosystem(root: Path) -> dict:
    """Analyze the entire ecosystem."""
    stats = {
        &class=class="string">"comment">#039;total_files': 0,
        &class=class="string">"comment">#039;total_words': 0,
        &class=class="string">"comment">#039;by_type': defaultdict(int),
        &class=class="string">"comment">#039;by_directory': defaultdict(lambda: {'files': 0, 'words': 0}),
        &class=class="string">"comment">#039;theme_matrix': defaultdict(lambda: defaultdict(int)),
        &class=class="string">"comment">#039;files': [],
    }

    exclude = [&class=class="string">"comment">#039;.git', '.claude', '__pycache__', 'program_garden']

    for filepath in root.rglob(&class=class="string">"comment">#039;*'):
        if filepath.is_file():
            class=class="string">"comment"># Skip excluded directories
            if any(ex in str(filepath) for ex in exclude):
                continue

            stats[&class=class="string">"comment">#039;total_files'] += 1

            class=class="string">"comment"># Count by extension
            ext = filepath.suffix or &class=class="string">"comment">#039;no_ext'
            stats[&class=class="string">"comment">#039;by_type'][ext] += 1

            class=class="string">"comment"># Get detailed stats
            file_stats = get_file_stats(filepath)
            if file_stats:
                stats[&class=class="string">"comment">#039;total_words'] += file_stats['words']

                class=class="string">"comment"># Count by directory
                dir_name = filepath.parent.name or &class=class="string">"comment">#039;root'
                stats[&class=class="string">"comment">#039;by_directory'][dir_name]['files'] += 1
                stats[&class=class="string">"comment">#039;by_directory'][dir_name]['words'] += file_stats['words']

                class=class="string">"comment"># Theme co-occurrence
                for theme1 in file_stats[&class=class="string">"comment">#039;themes']:
                    for theme2 in file_stats[&class=class="string">"comment">#039;themes']:
                        stats[&class=class="string">"comment">#039;theme_matrix'][theme1][theme2] += 1

                stats[&class=class="string">"comment">#039;files'].append(file_stats)

    return stats


class="keyword">def print_ecosystem_report(root: Path):
    """Print a comprehensive ecosystem report."""
    stats = analyze_ecosystem(root)

    print("=" * 70)
    print("ECOSYSTEM MAP")
    print("=" * 70)
    print(f"\nGenerated: {datetime.now().isoformat()}")
    print(f"Root: {root}")

    print(f"\n{&class=class="string">"comment">#039;─' * 70}")
    print("STRUCTURE")
    print("─" * 70)
    print(f"\n{root.name}/")
    print(generate_tree(root))

    print(f"\n{&class=class="string">"comment">#039;─' * 70}")
    print("STATISTICS")
    print("─" * 70)
    print(f"\n  Total files: {stats[&class=class="string">"comment">#039;total_files']}")
    print(f"  Total words: {stats[&class=class="string">"comment">#039;total_words']:,}")

    print(f"\n  By type:")
    for ext, count in sorted(stats[&class=class="string">"comment">#039;by_type'].items(), key=lambda x: -x[1]):
        print(f"    {ext:8} : {count}")

    print(f"\n  By directory:")
    for dir_name, data in sorted(stats[&class=class="string">"comment">#039;by_directory'].items(), key=lambda x: -x[1]['words']):
        print(f"    {dir_name:15} : {data[&class=class="string">"comment">#039;files']:2} files, {data['words']:5} words")

    print(f"\n{&class=class="string">"comment">#039;─' * 70}")
    print("THEME CONNECTIONS")
    print("─" * 70)
    themes = list(stats[&class=class="string">"comment">#039;theme_matrix'].keys())
    if themes:
        class=class="string">"comment"># Print header
        print(f"\n    {&class=class="string">"comment">#039;':12}", end='')
        for t in themes:
            print(f"{t[:8]:>9}", end=&class=class="string">"comment">#039;')
        print()

        class=class="string">"comment"># Print matrix
        for t1 in themes:
            print(f"    {t1:12}", end=&class=class="string">"comment">#039;')
            for t2 in themes:
                count = stats[&class=class="string">"comment">#039;theme_matrix'][t1][t2]
                print(f"{count:>9}", end=&class=class="string">"comment">#039;')
            print()

    print(f"\n{&class=class="string">"comment">#039;─' * 70}")
    print("GROWTH TRAJECTORY")
    print("─" * 70)

    class=class="string">"comment"># Estimate based on journal entries
    journals = [f for f in stats[&class=class="string">"comment">#039;files'] if 'journal' in f['path']]
    if journals:
        print("\n  Journal entries found:", len(journals))
        for j in sorted(journals, key=lambda x: x[&class=class="string">"comment">#039;path']):
            name = Path(j[&class=class="string">"comment">#039;path']).name
            print(f"    {name}: {j[&class=class="string">"comment">#039;words']} words")

    print(f"\n{&class=class="string">"comment">#039;─' * 70}")
    print("MOST CONNECTED FILES")
    print("─" * 70)

    class=class="string">"comment"># Files with most references
    by_refs = sorted(stats[&class=class="string">"comment">#039;files'], key=lambda x: -len(x.get('refs', [])))[:5]
    if by_refs:
        print("\n  Files referencing others most:")
        for f in by_refs:
            name = Path(f[&class=class="string">"comment">#039;path']).name
            ref_count = len(f.get(&class=class="string">"comment">#039;refs', []))
            if ref_count > 0:
                print(f"    {name}: {ref_count} references")

    return stats


class="keyword">def save_ecosystem_data(root: Path, output_path: Path):
    """Save ecosystem analysis to JSON."""
    stats = analyze_ecosystem(root)

    class=class="string">"comment"># Convert defaultdicts to regular dicts for JSON
    output = {
        &class=class="string">"comment">#039;generated': datetime.now().isoformat(),
        &class=class="string">"comment">#039;total_files': stats['total_files'],
        &class=class="string">"comment">#039;total_words': stats['total_words'],
        &class=class="string">"comment">#039;by_type': dict(stats['by_type']),
        &class=class="string">"comment">#039;by_directory': {k: dict(v) for k, v in stats['by_directory'].items()},
        &class=class="string">"comment">#039;theme_matrix': {k: dict(v) for k, v in stats['theme_matrix'].items()},
    }

    with open(output_path, &class=class="string">"comment">#039;w') as f:
        json.dump(output, f, indent=2)

    print(f"\n  Analysis saved to: {output_path}")


class="keyword">def main():
    root = Path(__file__).parent.parent

    print_ecosystem_report(root)

    class=class="string">"comment"># Save data
    output_path = root / "projects" / "ecosystem_analysis.json"
    save_ecosystem_data(root, output_path)


if __name__ == "__main__":
    main()