#!/usr/bin/env python3
"""
Idea Coach - Intelligent Idea/Problem/Challenge Manager

A sparring partner that captures, categorizes, and helps evolve ideas.
Can be critical - will suggest dropping ideas that aren't worth pursuing.
Now with GitHub integration for shipping ideas to repos!

Usage:
  python coach.py add --type idea "App für X bauen"
  python coach.py add --type problem "Server ist zu langsam"
  python coach.py list
  python coach.py list --due          # What's due for review
  python coach.py review <id>         # Start review session
  python coach.py update <id> --status developing
  python coach.py drop <id>           # Mark as dropped (with reason)
  python coach.py stats
  
  # GitHub Integration
  python coach.py link <id> <owner/repo>     # Link idea to existing repo
  python coach.py ship <id>                   # Create new repo for idea
  python coach.py repo-status <id>           # Show linked repo status
  python coach.py sync-issues <id>           # Sync idea as GitHub issue
"""

import argparse
import json
import os
import re
import subprocess
import uuid
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import Optional, List, Dict, Any

# Storage
COACH_DIR = Path.home() / ".openclaw" / "idea-coach"
IDEAS_FILE = COACH_DIR / "ideas.json"
CONFIG_FILE = COACH_DIR / "config.json"

# Types
TYPES = ["idea", "problem", "challenge"]
DOMAINS = ["work", "personal", "health", "finance", "creative", "tech", "other"]
ENERGY_LEVELS = ["high", "medium", "low"]
URGENCY_LEVELS = ["urgent", "soon", "someday"]
IMPORTANCE_LEVELS = ["critical", "important", "nice-to-have"]
STATUS_OPTIONS = ["captured", "exploring", "developing", "blocked", "parked", "shipped", "done", "dropped"]

# Review cycles in days
REVIEW_CYCLES = {
    "daily": 1,
    "weekly": 7,
    "biweekly": 14,
    "monthly": 30,
    "quarterly": 90
}

# =============================================================================
# Core Functions
# =============================================================================

def ensure_dirs():
    """Create storage directories."""
    COACH_DIR.mkdir(parents=True, exist_ok=True)

def load_ideas() -> List[Dict]:
    """Load all ideas."""
    if IDEAS_FILE.exists():
        return json.loads(IDEAS_FILE.read_text())
    return []

def save_ideas(ideas: List[Dict]):
    """Save all ideas."""
    ensure_dirs()
    IDEAS_FILE.write_text(json.dumps(ideas, indent=2, ensure_ascii=False))

def generate_id() -> str:
    """Generate short unique ID."""
    return str(uuid.uuid4())[:8]

def now_iso() -> str:
    """Current time in ISO format."""
    return datetime.now(timezone.utc).isoformat()

def parse_date(date_str: str) -> datetime:
    """Parse ISO date string."""
    return datetime.fromisoformat(date_str.replace('Z', '+00:00'))

def calculate_review_cycle(importance: str, energy: str, status: str) -> str:
    """Calculate review frequency based on attributes."""
    if status == "blocked":
        return "weekly"
    if status == "parked":
        return "quarterly"
    if status in ["done", "dropped", "shipped"]:
        return "quarterly"
    
    if importance == "critical" and energy == "high":
        return "daily"
    if importance == "critical":
        return "weekly"
    if importance == "important" and energy == "high":
        return "weekly"
    if importance == "important":
        return "biweekly"
    
    return "monthly"

def calculate_next_review(last_review: str, cycle: str) -> str:
    """Calculate next review date."""
    last = parse_date(last_review)
    days = REVIEW_CYCLES.get(cycle, 30)
    next_date = last + timedelta(days=days)
    return next_date.isoformat()

def detect_language(text: str) -> str:
    """Simple language detection."""
    german_indicators = ["ich", "und", "der", "die", "das", "ist", "ein", "für", "mit", "auf"]
    words = text.lower().split()
    german_count = sum(1 for w in words if w in german_indicators)
    return "de" if german_count >= 2 or any(c in text for c in "äöüß") else "en"

def slugify(text: str) -> str:
    """Convert text to URL-safe slug."""
    text = text.lower()
    text = re.sub(r'[äÄ]', 'ae', text)
    text = re.sub(r'[öÖ]', 'oe', text)
    text = re.sub(r'[üÜ]', 'ue', text)
    text = re.sub(r'[ß]', 'ss', text)
    text = re.sub(r'[^a-z0-9]+', '-', text)
    text = text.strip('-')
    return text[:50]

# =============================================================================
# Idea CRUD
# =============================================================================

def create_idea(
    idea_type: str,
    title: str,
    description: str = "",
    domain: str = "other",
    energy: str = "medium",
    urgency: str = "someday",
    importance: str = "nice-to-have"
) -> Dict:
    """Create a new idea/problem/challenge."""
    now = now_iso()
    
    idea = {
        "id": generate_id(),
        "type": idea_type,
        "title": title,
        "description": description,
        "domain": domain,
        "energy": energy,
        "urgency": urgency,
        "importance": importance,
        "status": "captured",
        "progress": 0,
        "nextAction": None,
        "reviewCycle": calculate_review_cycle(importance, energy, "captured"),
        "lastReview": now,
        "nextReview": None,
        "created": now,
        "updated": now,
        "interactions": [
            {"date": now, "type": "capture", "notes": "Initial capture"}
        ],
        "relatedTo": [],
        "dropReason": None,
        "language": detect_language(title + " " + description),
        # GitHub integration fields
        "github": {
            "repo": None,           # "owner/repo"
            "url": None,            # Full URL
            "issueNumber": None,    # If synced as issue
            "issueUrl": None,
            "linkedAt": None,
            "lastSync": None
        }
    }
    
    idea["nextReview"] = calculate_next_review(now, idea["reviewCycle"])
    
    return idea

def add_idea(idea_type: str, title: str, **kwargs) -> Dict:
    """Add a new idea to storage."""
    ideas = load_ideas()
    idea = create_idea(idea_type, title, **kwargs)
    ideas.append(idea)
    save_ideas(ideas)
    return idea

def get_idea(idea_id: str) -> Optional[Dict]:
    """Get idea by ID."""
    ideas = load_ideas()
    for idea in ideas:
        if idea["id"] == idea_id or idea["id"].startswith(idea_id):
            return idea
    return None

def update_idea(idea_id: str, updates: Dict) -> Optional[Dict]:
    """Update an idea."""
    ideas = load_ideas()
    for i, idea in enumerate(ideas):
        if idea["id"] == idea_id or idea["id"].startswith(idea_id):
            # Deep merge for nested dicts like 'github'
            for key, value in updates.items():
                if isinstance(value, dict) and isinstance(idea.get(key), dict):
                    idea[key].update(value)
                else:
                    idea[key] = value
            
            idea["updated"] = now_iso()
            
            # Recalculate review cycle if relevant fields changed
            if any(k in updates for k in ["importance", "energy", "status"]):
                idea["reviewCycle"] = calculate_review_cycle(
                    idea.get("importance", "nice-to-have"),
                    idea.get("energy", "medium"),
                    idea.get("status", "captured")
                )
            
            ideas[i] = idea
            save_ideas(ideas)
            return idea
    return None

def add_interaction(idea_id: str, interaction_type: str, notes: str) -> Optional[Dict]:
    """Add an interaction to an idea."""
    idea = get_idea(idea_id)
    if not idea:
        return None
    
    interaction = {
        "date": now_iso(),
        "type": interaction_type,
        "notes": notes
    }
    
    idea["interactions"].append(interaction)
    idea["lastReview"] = now_iso()
    idea["nextReview"] = calculate_next_review(now_iso(), idea["reviewCycle"])
    
    return update_idea(idea_id, {
        "interactions": idea["interactions"],
        "lastReview": idea["lastReview"],
        "nextReview": idea["nextReview"]
    })

def drop_idea(idea_id: str, reason: str) -> Optional[Dict]:
    """Mark idea as dropped with reason."""
    idea = get_idea(idea_id)
    if not idea:
        return None
    return update_idea(idea_id, {
        "status": "dropped",
        "dropReason": reason,
        "interactions": idea["interactions"] + [{
            "date": now_iso(),
            "type": "dropped",
            "notes": reason
        }]
    })

# =============================================================================
# GitHub Integration
# =============================================================================

def run_gh_command(args: List[str]) -> Dict[str, Any]:
    """Run a gh CLI command and return result."""
    try:
        result = subprocess.run(
            ["gh"] + args,
            capture_output=True,
            text=True,
            timeout=30
        )
        return {
            "success": result.returncode == 0,
            "stdout": result.stdout.strip(),
            "stderr": result.stderr.strip(),
            "code": result.returncode
        }
    except FileNotFoundError:
        return {"success": False, "error": "gh CLI not installed", "code": -1}
    except subprocess.TimeoutExpired:
        return {"success": False, "error": "Command timed out", "code": -2}

def check_gh_auth() -> bool:
    """Check if gh CLI is authenticated."""
    result = run_gh_command(["auth", "status"])
    return result["success"]

def get_repo_info(repo: str) -> Optional[Dict]:
    """Get repository information from GitHub."""
    result = run_gh_command([
        "repo", "view", repo, "--json",
        "name,owner,url,description,isPrivate,updatedAt,stargazerCount,forkCount,issues,pullRequests"
    ])
    
    if result["success"]:
        try:
            data = json.loads(result["stdout"])
            return {
                "name": data.get("name"),
                "owner": data.get("owner", {}).get("login"),
                "url": data.get("url"),
                "description": data.get("description"),
                "isPrivate": data.get("isPrivate"),
                "updatedAt": data.get("updatedAt"),
                "stars": data.get("stargazerCount", 0),
                "forks": data.get("forkCount", 0),
                "openIssues": data.get("issues", {}).get("totalCount", 0),
                "openPRs": data.get("pullRequests", {}).get("totalCount", 0)
            }
        except json.JSONDecodeError:
            return None
    return None

def get_repo_commits(repo: str, limit: int = 5) -> List[Dict]:
    """Get recent commits from a repository."""
    result = run_gh_command([
        "api", f"repos/{repo}/commits",
        "--jq", f".[:{limit}] | .[] | {{sha: .sha[:7], message: .commit.message | split(\"\\n\")[0], date: .commit.author.date[:10]}}"
    ])
    
    if result["success"]:
        commits = []
        for line in result["stdout"].strip().split("\n"):
            if line:
                try:
                    commits.append(json.loads(line))
                except:
                    pass
        return commits
    return []

def link_repo(idea_id: str, repo: str) -> Dict:
    """Link an idea to an existing GitHub repository."""
    idea = get_idea(idea_id)
    if not idea:
        return {"success": False, "error": "Idea not found"}
    
    # Validate repo exists
    repo_info = get_repo_info(repo)
    if not repo_info:
        return {"success": False, "error": f"Repository '{repo}' not found or not accessible"}
    
    # Update idea
    update_idea(idea_id, {
        "github": {
            "repo": repo,
            "url": repo_info["url"],
            "issueNumber": idea.get("github", {}).get("issueNumber"),
            "issueUrl": idea.get("github", {}).get("issueUrl"),
            "linkedAt": now_iso(),
            "lastSync": now_iso()
        }
    })
    
    add_interaction(idea_id, "github_linked", f"Linked to {repo}")
    
    return {
        "success": True,
        "idea_id": idea_id,
        "repo": repo,
        "url": repo_info["url"],
        "repo_info": repo_info
    }

def ship_idea(idea_id: str, owner: str = None, private: bool = True, description: str = None) -> Dict:
    """Create a new GitHub repository for an idea."""
    idea = get_idea(idea_id)
    if not idea:
        return {"success": False, "error": "Idea not found"}
    
    # Check if already linked
    if idea.get("github", {}).get("repo"):
        return {"success": False, "error": f"Idea already linked to {idea['github']['repo']}"}
    
    # Generate repo name from title
    repo_name = slugify(idea["title"])
    if not repo_name:
        repo_name = f"idea-{idea['id']}"
    
    # Build create command
    args = ["repo", "create"]
    
    if owner:
        args.append(f"{owner}/{repo_name}")
    else:
        args.append(repo_name)
    
    if private:
        args.append("--private")
    else:
        args.append("--public")
    
    desc = description or idea.get("description") or idea["title"]
    args.extend(["--description", desc[:255]])
    
    # Create repo
    result = run_gh_command(args)
    
    if not result["success"]:
        return {"success": False, "error": result.get("stderr") or result.get("error")}
    
    # Parse created repo URL
    repo_url = result["stdout"].strip()
    
    # Extract owner/repo from URL
    match = re.search(r'github\.com[/:]([^/]+)/([^/\s]+)', repo_url)
    if match:
        full_repo = f"{match.group(1)}/{match.group(2).replace('.git', '')}"
    else:
        full_repo = repo_name
    
    # Update idea
    update_idea(idea_id, {
        "status": "shipped",
        "github": {
            "repo": full_repo,
            "url": repo_url,
            "issueNumber": None,
            "issueUrl": None,
            "linkedAt": now_iso(),
            "lastSync": now_iso()
        }
    })
    
    add_interaction(idea_id, "shipped", f"Created repo {full_repo}")
    
    return {
        "success": True,
        "idea_id": idea_id,
        "repo": full_repo,
        "url": repo_url,
        "private": private
    }

def get_repo_status(idea_id: str) -> Dict:
    """Get status of linked GitHub repository."""
    idea = get_idea(idea_id)
    if not idea:
        return {"success": False, "error": "Idea not found"}
    
    repo = idea.get("github", {}).get("repo")
    if not repo:
        return {"success": False, "error": "No GitHub repo linked", "idea_id": idea_id}
    
    repo_info = get_repo_info(repo)
    if not repo_info:
        return {"success": False, "error": f"Could not fetch repo info for {repo}"}
    
    commits = get_repo_commits(repo, 5)
    
    # Update last sync time
    update_idea(idea_id, {"github": {"lastSync": now_iso()}})
    
    return {
        "success": True,
        "idea_id": idea_id,
        "idea_title": idea["title"],
        "repo": repo,
        "url": repo_info["url"],
        "description": repo_info["description"],
        "isPrivate": repo_info["isPrivate"],
        "stars": repo_info["stars"],
        "forks": repo_info["forks"],
        "openIssues": repo_info["openIssues"],
        "openPRs": repo_info["openPRs"],
        "updatedAt": repo_info["updatedAt"],
        "recentCommits": commits
    }

def sync_as_issue(idea_id: str, labels: List[str] = None) -> Dict:
    """Create or update a GitHub issue from the idea."""
    idea = get_idea(idea_id)
    if not idea:
        return {"success": False, "error": "Idea not found"}
    
    repo = idea.get("github", {}).get("repo")
    if not repo:
        return {"success": False, "error": "No GitHub repo linked. Use 'link' first."}
    
    existing_issue = idea.get("github", {}).get("issueNumber")
    
    # Build issue body
    body_parts = [
        f"**Type:** {idea['type'].capitalize()}",
        f"**Status:** {idea['status']}",
        f"**Importance:** {idea['importance']}",
        f"**Energy:** {idea['energy']}",
        "",
        "## Description",
        idea.get("description") or "_No description provided._",
        "",
        "---",
        f"_Synced from Idea Coach (ID: {idea['id']})_"
    ]
    body = "\n".join(body_parts)
    
    if existing_issue:
        # Update existing issue
        args = ["issue", "edit", str(existing_issue), "-R", repo, "--body", body]
        result = run_gh_command(args)
        
        if result["success"]:
            return {
                "success": True,
                "action": "updated",
                "issue_number": existing_issue,
                "url": idea["github"]["issueUrl"]
            }
        else:
            return {"success": False, "error": result.get("stderr") or "Failed to update issue"}
    else:
        # Create new issue
        type_emoji = {"idea": "💡", "problem": "🔧", "challenge": "🎯"}.get(idea["type"], "📝")
        title = f"{type_emoji} {idea['title']}"
        
        args = ["issue", "create", "-R", repo, "--title", title, "--body", body]
        
        if labels:
            for label in labels:
                args.extend(["--label", label])
        
        result = run_gh_command(args)
        
        if result["success"]:
            # Parse issue URL from output
            issue_url = result["stdout"].strip()
            issue_number = None
            match = re.search(r'/issues/(\d+)', issue_url)
            if match:
                issue_number = int(match.group(1))
            
            # Update idea with issue info
            update_idea(idea_id, {
                "github": {
                    "issueNumber": issue_number,
                    "issueUrl": issue_url,
                    "lastSync": now_iso()
                }
            })
            
            add_interaction(idea_id, "issue_created", f"Created issue #{issue_number}")
            
            return {
                "success": True,
                "action": "created",
                "issue_number": issue_number,
                "url": issue_url
            }
        else:
            return {"success": False, "error": result.get("stderr") or "Failed to create issue"}

def unlink_repo(idea_id: str) -> Dict:
    """Unlink a GitHub repository from an idea."""
    idea = get_idea(idea_id)
    if not idea:
        return {"success": False, "error": "Idea not found"}
    
    if not idea.get("github", {}).get("repo"):
        return {"success": False, "error": "No repo linked"}
    
    old_repo = idea["github"]["repo"]
    
    update_idea(idea_id, {
        "github": {
            "repo": None,
            "url": None,
            "issueNumber": None,
            "issueUrl": None,
            "linkedAt": None,
            "lastSync": None
        }
    })
    
    add_interaction(idea_id, "github_unlinked", f"Unlinked from {old_repo}")
    
    return {"success": True, "unlinked": old_repo}

# =============================================================================
# Query Functions
# =============================================================================

def get_due_for_review() -> List[Dict]:
    """Get ideas due for review."""
    ideas = load_ideas()
    now = datetime.now(timezone.utc)
    due = []
    
    for idea in ideas:
        if idea["status"] in ["done", "dropped"]:
            continue
        
        next_review = parse_date(idea.get("nextReview", idea["created"]))
        if next_review <= now:
            due.append(idea)
    
    importance_order = {"critical": 0, "important": 1, "nice-to-have": 2}
    urgency_order = {"urgent": 0, "soon": 1, "someday": 2}
    
    due.sort(key=lambda x: (
        importance_order.get(x.get("importance"), 2),
        urgency_order.get(x.get("urgency"), 2)
    ))
    
    return due

def get_stats() -> Dict:
    """Get statistics."""
    ideas = load_ideas()
    
    stats = {
        "total": len(ideas),
        "byType": {},
        "byStatus": {},
        "byImportance": {},
        "dueForReview": len(get_due_for_review()),
        "droppedCount": 0,
        "completedCount": 0,
        "shippedCount": 0,
        "activeCount": 0,
        "withGithub": 0
    }
    
    for idea in ideas:
        t = idea.get("type", "idea")
        stats["byType"][t] = stats["byType"].get(t, 0) + 1
        
        s = idea.get("status", "captured")
        stats["byStatus"][s] = stats["byStatus"].get(s, 0) + 1
        
        imp = idea.get("importance", "nice-to-have")
        stats["byImportance"][imp] = stats["byImportance"].get(imp, 0) + 1
        
        if s == "dropped":
            stats["droppedCount"] += 1
        elif s == "done":
            stats["completedCount"] += 1
        elif s == "shipped":
            stats["shippedCount"] += 1
        elif s not in ["done", "dropped", "parked", "shipped"]:
            stats["activeCount"] += 1
        
        if idea.get("github", {}).get("repo"):
            stats["withGithub"] += 1
    
    return stats

def list_ideas(
    status: Optional[str] = None,
    idea_type: Optional[str] = None,
    due_only: bool = False,
    with_github: bool = False
) -> List[Dict]:
    """List ideas with optional filters."""
    if due_only:
        return get_due_for_review()
    
    ideas = load_ideas()
    
    if status is None:
        ideas = [i for i in ideas if i.get("status") not in ["done", "dropped"]]
    elif status:
        ideas = [i for i in ideas if i.get("status") == status]
    
    if idea_type:
        ideas = [i for i in ideas if i.get("type") == idea_type]
    
    if with_github:
        ideas = [i for i in ideas if i.get("github", {}).get("repo")]
    
    return ideas

# =============================================================================
# CLI
# =============================================================================

def main():
    parser = argparse.ArgumentParser(description="Idea Coach - with GitHub Integration")
    subparsers = parser.add_subparsers(dest="command", required=True)
    
    # Add
    add_parser = subparsers.add_parser("add", help="Add new idea/problem/challenge")
    add_parser.add_argument("title", help="Title/description")
    add_parser.add_argument("--type", "-t", choices=TYPES, default="idea")
    add_parser.add_argument("--domain", "-d", choices=DOMAINS, default="other")
    add_parser.add_argument("--energy", "-e", choices=ENERGY_LEVELS, default="medium")
    add_parser.add_argument("--urgency", "-u", choices=URGENCY_LEVELS, default="someday")
    add_parser.add_argument("--importance", "-i", choices=IMPORTANCE_LEVELS, default="nice-to-have")
    add_parser.add_argument("--description", help="Detailed description")
    
    # List
    list_parser = subparsers.add_parser("list", help="List ideas")
    list_parser.add_argument("--status", "-s", choices=STATUS_OPTIONS)
    list_parser.add_argument("--type", "-t", choices=TYPES)
    list_parser.add_argument("--due", action="store_true", help="Only show due for review")
    list_parser.add_argument("--all", "-a", action="store_true", help="Include done/dropped")
    list_parser.add_argument("--github", "-g", action="store_true", help="Only with GitHub repos")
    
    # Get
    get_parser = subparsers.add_parser("get", help="Get idea details")
    get_parser.add_argument("id", help="Idea ID")
    
    # Update
    update_parser = subparsers.add_parser("update", help="Update idea")
    update_parser.add_argument("id", help="Idea ID")
    update_parser.add_argument("--status", "-s", choices=STATUS_OPTIONS)
    update_parser.add_argument("--importance", "-i", choices=IMPORTANCE_LEVELS)
    update_parser.add_argument("--energy", "-e", choices=ENERGY_LEVELS)
    update_parser.add_argument("--progress", "-p", type=int)
    update_parser.add_argument("--next-action", "-n")
    update_parser.add_argument("--description")
    
    # Review
    review_parser = subparsers.add_parser("review", help="Add review interaction")
    review_parser.add_argument("id", help="Idea ID")
    review_parser.add_argument("--notes", "-n", default="Reviewed")
    
    # Drop
    drop_parser = subparsers.add_parser("drop", help="Drop an idea")
    drop_parser.add_argument("id", help="Idea ID")
    drop_parser.add_argument("--reason", "-r", required=True, help="Reason for dropping")
    
    # Done
    done_parser = subparsers.add_parser("done", help="Mark as done")
    done_parser.add_argument("id", help="Idea ID")
    done_parser.add_argument("--notes", "-n", default="Completed")
    
    # Stats
    subparsers.add_parser("stats", help="Show statistics")
    
    # Due
    subparsers.add_parser("due", help="Show items due for review")
    
    # === GitHub Commands ===
    
    # Link
    link_parser = subparsers.add_parser("link", help="Link idea to existing GitHub repo")
    link_parser.add_argument("id", help="Idea ID")
    link_parser.add_argument("repo", help="Repository (owner/repo)")
    
    # Ship
    ship_parser = subparsers.add_parser("ship", help="Create new GitHub repo for idea")
    ship_parser.add_argument("id", help="Idea ID")
    ship_parser.add_argument("--owner", "-o", help="GitHub owner/org (default: your user)")
    ship_parser.add_argument("--public", action="store_true", help="Make repo public")
    ship_parser.add_argument("--description", "-d", help="Repo description")
    
    # Repo Status
    repo_status_parser = subparsers.add_parser("repo-status", help="Get linked repo status")
    repo_status_parser.add_argument("id", help="Idea ID")
    
    # Sync Issue
    sync_parser = subparsers.add_parser("sync-issue", help="Sync idea as GitHub issue")
    sync_parser.add_argument("id", help="Idea ID")
    sync_parser.add_argument("--labels", "-l", nargs="*", help="Issue labels")
    
    # Unlink
    unlink_parser = subparsers.add_parser("unlink", help="Unlink GitHub repo from idea")
    unlink_parser.add_argument("id", help="Idea ID")
    
    # Check Auth
    subparsers.add_parser("gh-auth", help="Check GitHub CLI auth status")
    
    args = parser.parse_args()
    ensure_dirs()
    
    # Dispatch commands
    if args.command == "add":
        idea = add_idea(
            args.type, args.title,
            description=getattr(args, 'description', '') or '',
            domain=args.domain,
            energy=args.energy,
            urgency=args.urgency,
            importance=args.importance
        )
        print(json.dumps(idea, indent=2, ensure_ascii=False))
    
    elif args.command == "list":
        status = None if args.all else args.status
        ideas = list_ideas(
            status=status, 
            idea_type=args.type, 
            due_only=args.due,
            with_github=args.github
        )
        result = [{
            "id": i["id"], 
            "type": i["type"], 
            "title": i["title"], 
            "status": i["status"], 
            "importance": i["importance"],
            "github": i.get("github", {}).get("repo")
        } for i in ideas]
        print(json.dumps(result, indent=2, ensure_ascii=False))
    
    elif args.command == "get":
        idea = get_idea(args.id)
        if idea:
            print(json.dumps(idea, indent=2, ensure_ascii=False))
        else:
            print(json.dumps({"error": "Not found"}))
    
    elif args.command == "update":
        updates = {}
        if args.status:
            updates["status"] = args.status
        if args.importance:
            updates["importance"] = args.importance
        if args.energy:
            updates["energy"] = args.energy
        if args.progress is not None:
            updates["progress"] = args.progress
        if args.next_action:
            updates["nextAction"] = args.next_action
        if hasattr(args, 'description') and args.description:
            updates["description"] = args.description
        
        idea = update_idea(args.id, updates)
        if idea:
            print(json.dumps(idea, indent=2, ensure_ascii=False))
        else:
            print(json.dumps({"error": "Not found"}))
    
    elif args.command == "review":
        idea = add_interaction(args.id, "review", args.notes)
        if idea:
            print(json.dumps(idea, indent=2, ensure_ascii=False))
        else:
            print(json.dumps({"error": "Not found"}))
    
    elif args.command == "drop":
        idea = drop_idea(args.id, args.reason)
        if idea:
            print(json.dumps(idea, indent=2, ensure_ascii=False))
        else:
            print(json.dumps({"error": "Not found"}))
    
    elif args.command == "done":
        idea = update_idea(args.id, {"status": "done"})
        if idea:
            add_interaction(args.id, "completed", args.notes)
            print(json.dumps(idea, indent=2, ensure_ascii=False))
        else:
            print(json.dumps({"error": "Not found"}))
    
    elif args.command == "stats":
        stats = get_stats()
        print(json.dumps(stats, indent=2))
    
    elif args.command == "due":
        due = get_due_for_review()
        result = [{
            "id": i["id"], 
            "type": i["type"], 
            "title": i["title"],
            "reviewCycle": i["reviewCycle"], 
            "lastReview": i["lastReview"][:10],
            "github": i.get("github", {}).get("repo")
        } for i in due]
        print(json.dumps(result, indent=2, ensure_ascii=False))
    
    # GitHub commands
    elif args.command == "link":
        result = link_repo(args.id, args.repo)
        print(json.dumps(result, indent=2, ensure_ascii=False))
    
    elif args.command == "ship":
        result = ship_idea(
            args.id, 
            owner=args.owner, 
            private=not args.public,
            description=args.description
        )
        print(json.dumps(result, indent=2, ensure_ascii=False))
    
    elif args.command == "repo-status":
        result = get_repo_status(args.id)
        print(json.dumps(result, indent=2, ensure_ascii=False))
    
    elif args.command == "sync-issue":
        result = sync_as_issue(args.id, labels=args.labels)
        print(json.dumps(result, indent=2, ensure_ascii=False))
    
    elif args.command == "unlink":
        result = unlink_repo(args.id)
        print(json.dumps(result, indent=2, ensure_ascii=False))
    
    elif args.command == "gh-auth":
        if check_gh_auth():
            print(json.dumps({"authenticated": True}))
        else:
            print(json.dumps({"authenticated": False, "hint": "Run: gh auth login"}))

if __name__ == "__main__":
    main()
