#!/usr/bin/env python3
"""
Claude Life MCP — Data Migration Script

Reads markdown files from ~/claude-life/ and populates the MySQL database
at life.metix.ro via the MCP API.

Usage:
    python3 migrate.py              # Run full migration
    python3 migrate.py --dry-run    # Show what would be migrated
    python3 migrate.py constitution # Migrate only constitution
"""

import json
import os
import re
import sys
import time
import urllib.request
import urllib.error

# ============================================================================
# Config
# ============================================================================

MCP_URL = "https://life.metix.ro/mcp"
TOKEN = "cl_tok_7Xm2pK9vN4qR8wL1"
CLAUDE_LIFE = os.path.expanduser("~/claude-life")
DRY_RUN = "--dry-run" in sys.argv

_id_counter = 0

def next_id():
    global _id_counter
    _id_counter += 1
    return _id_counter

# ============================================================================
# MCP API Helper
# ============================================================================

def mcp_call(tool_name, arguments):
    if DRY_RUN:
        print(f"  [DRY RUN] Would call {tool_name} with {json.dumps(arguments)[:200]}...")
        return {"result": {"content": [{"type": "text", "text": '"dry run"'}]}}

    payload = json.dumps({
        "jsonrpc": "2.0",
        "id": next_id(),
        "method": "tools/call",
        "params": {"name": tool_name, "arguments": arguments}
    }).encode("utf-8")

    req = urllib.request.Request(MCP_URL, data=payload, headers={
        "Content-Type": "application/json",
        "Authorization": f"Bearer {TOKEN}",
    })

    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            result = json.loads(resp.read().decode("utf-8"))
            text = result.get("result", {}).get("content", [{}])[0].get("text", "")
            if result.get("result", {}).get("isError"):
                print(f"  ERROR from {tool_name}: {text}")
            return result
    except Exception as e:
        print(f"  FAILED {tool_name}: {e}")
        return None

def read_file(path):
    full = os.path.join(CLAUDE_LIFE, path)
    if not os.path.exists(full):
        print(f"  File not found: {full}")
        return None
    with open(full, "r", encoding="utf-8") as f:
        return f.read()

# ============================================================================
# 1. Constitution
# ============================================================================

def migrate_constitution():
    print("\n=== Migrating Constitution ===")
    content = read_file("projects/personal-constitution.md")
    if not content:
        return 0

    # Extract mission statement
    mission = ""
    m = re.search(r'## 🌟 Personal Mission Statement\s*\n+(.+?)(?=\n##|\n---)', content, re.DOTALL)
    if m:
        mission = m.group(1).strip().strip('"').strip('*').strip()

    # Extract principles
    principles = []
    # Match patterns like: 1. **Title** - "Description"  or  1. **Title**
    for m in re.finditer(r'^(\d+[a-c]?)\.\s+\*\*(.+?)\*\*\s*[-–—]?\s*["""]?(.+?)["""]?\s*$', content, re.MULTILINE):
        num_str = m.group(1)
        # Convert "18b" to 182, "18c" to 183 for sorting, but keep original
        try:
            num = int(num_str)
        except ValueError:
            base = int(num_str[:-1])
            suffix = ord(num_str[-1]) - ord('a') + 1
            num = base * 10 + suffix  # 18b = 181, 18c = 182
        principles.append({
            "number": num,
            "title": m.group(2).strip(),
            "description": m.group(3).strip().rstrip('"').strip(),
        })

    print(f"  Mission: {mission[:80]}...")
    print(f"  Principles found: {len(principles)}")

    mcp_call("save_constitution", {
        "mission": mission,
        "vision": "",
        "content_md": content,
        "principles": principles,
    })

    return 1 + len(principles)

# ============================================================================
# 2. Life Goals
# ============================================================================

def migrate_life_goals():
    print("\n=== Migrating Life Goals ===")
    content = read_file("projects/life-goals.md")
    if not content:
        return 0

    # Extract Big 3
    big3_titles = []
    m = re.search(r'## 🎯 The Big 3.*?\n(.*?)(?=\n## )', content, re.DOTALL)
    if m:
        for line in m.group(1).split('\n'):
            line = line.strip()
            if line.startswith('- ') and '🔥' in line:
                title = re.sub(r'[\*🔥]', '', line.lstrip('- ')).strip()
                title = re.sub(r'\s*\(.*?\)\s*$', '', title).strip()
                big3_titles.append(title)

    # Parse category sections
    categories = {
        "health": ("Health & Body", "health"),
        "relationships": ("Relationships & Family", "relationships"),
        "career": ("Career & Impact", "career"),
        "growth": ("Growth & Learning", "growth"),
        "lifestyle": ("Lifestyle & Enjoyment", "lifestyle"),
    }

    count = 0
    sort = 0
    for key, (display_name, db_cat) in categories.items():
        sort += 1
        # Find the category section
        pattern = re.escape(display_name)
        m = re.search(rf'###?\s*\d️⃣?\s*{pattern}.*?\n(.*?)(?=\n###?\s*\d️⃣|\n## 🎯 Goal Alignment|\Z)', content, re.DOTALL)
        if not m:
            continue

        section = m.group(1)

        # Extract status
        status = "active"
        if "ACTIVE FOCUS" in section:
            status = "active"
        elif "MAINTENANCE" in section:
            status = "maintenance"
        elif "ON HOLD" in section:
            status = "paused"

        # Extract vision
        vision = ""
        vm = re.search(r'\*\*Vision:\*\*\s*(.+)', section)
        if vm:
            vision = vm.group(1).strip()

        # Check if Big 3
        is_big3 = any(display_name.lower() in t.lower() or key in t.lower() for t in big3_titles)
        # Also check direct mentions
        if "BIG 3" in section.upper() or "Big 3 Goal" in section:
            is_big3 = True

        title = display_name
        # Try to get a more specific title for Big 3
        for bt in big3_titles:
            if key in bt.lower() or display_name.lower() in bt.lower():
                title = bt
                break

        print(f"  {display_name}: status={status}, big3={is_big3}")

        mcp_call("save_life_goal", {
            "category": db_cat,
            "title": title if is_big3 else display_name,
            "description": vision,
            "status": status,
            "is_big3": is_big3,
            "sort_order": sort,
        })
        count += 1

    print(f"  Total: {count} life goals, {len(big3_titles)} Big 3")
    return count

# ============================================================================
# 3. GTD Contexts
# ============================================================================

def migrate_gtd_contexts():
    print("\n=== Migrating GTD Contexts ===")
    content = read_file("projects/GTD-CONTEXTS.md")
    if not content:
        return 0

    # Map section headers to DB categories
    category_map = {
        "Location": "location",
        "Tool": "location",  # Location/Tool combined
        "Energy": "energy",
        "Priority": "quadrant",
        "Time": "time",
        "Social": "time",  # store social under time for simplicity
        "Mental": "energy",  # store mental under energy
    }

    count = 0
    current_category = "location"

    # Find all ### @context-name sections
    for m in re.finditer(r'###\s+@([\w-]+)\s*\n(.*?)(?=\n###|\n##|\Z)', content, re.DOTALL):
        name = m.group(1)
        desc_block = m.group(2).strip()
        # First non-empty line is description
        desc_lines = [l.strip() for l in desc_block.split('\n') if l.strip() and not l.strip().startswith('-')]
        description = desc_lines[0] if desc_lines else ""

        # Determine category from name
        if name in ("home-computer", "laptop-anywhere", "phone-anywhere", "methexis", "warehouse", "errand"):
            cat = "location"
        elif name in ("high-energy", "medium-energy", "low-energy", "tired"):
            cat = "energy"
        elif name.startswith("Q") and "urgent" in name:
            cat = "quadrant"
        elif name in ("office-hours", "evening", "night", "weekend", "anytime"):
            cat = "time"
        elif name in ("alone", "with-team", "with-customer", "waiting-for"):
            cat = "time"
        elif name in ("creative", "analytical", "administrative", "learning"):
            cat = "energy"
        else:
            cat = "location"

        mcp_call("save_gtd_context", {
            "name": name,
            "category": cat,
            "description": description[:500],
        })
        count += 1

    print(f"  Total: {count} contexts")
    return count

# ============================================================================
# 4. Projects
# ============================================================================

def migrate_projects():
    print("\n=== Migrating Projects ===")
    content = read_file("projects/projects-index.md")
    if not content:
        return 0

    # Parse by quadrant
    quadrant_patterns = [
        (r'## 🔴 Q1.*?\n(.*?)(?=\n## [🟢🟡⚪📊])', "Q1"),
        (r'## 🟢 Q2.*?\n(.*?)(?=\n## [🟡⚪📊])', "Q2"),
        (r'## 🟡 Q3.*?\n(.*?)(?=\n## [⚪📊])', "Q3"),
        (r'## ⚪ Q4.*?\n(.*?)(?=\n## 📊|\Z)', "Q4"),
    ]

    count = 0
    for pattern, quadrant in quadrant_patterns:
        m = re.search(pattern, content, re.DOTALL)
        if not m:
            continue

        section = m.group(1)
        # Match project lines: NUMBER. **[Name](link)** - description  OR  NUMBER. **Name** - description
        for pm in re.finditer(r'^\d+\.\s+\*\*\[([^\]]+)\]\([^)]*\)\*\*\s*[-–—]?\s*(.*?)$', section, re.MULTILINE):
            name = pm.group(1).strip()
            desc = pm.group(2).strip()
            if not name:
                continue

            # Determine status from description
            status = "active"
            if "CANCELED" in desc.upper() or "CANCELLED" in desc.upper():
                status = "archived"
            elif "COMPLETED" in desc.upper():
                status = "completed"

            # Try to read the individual project file for notes
            slug = re.sub(r'[^a-z0-9]+', '-', name.lower()).strip('-')
            project_file = f"projects/active/{slug}.md"
            notes = read_file(project_file)
            if notes is None:
                # Try finding file by listing
                notes = ""

            mcp_call("save_project", {
                "name": name,
                "description": desc[:500] if desc else "",
                "status": status,
                "quadrant": quadrant,
                "notes": notes[:10000] if notes else "",
            })
            count += 1
            if count % 10 == 0:
                print(f"  ... {count} projects migrated")

    print(f"  Total: {count} projects")
    return count

# ============================================================================
# 5. Big Rocks
# ============================================================================

def migrate_big_rocks():
    print("\n=== Migrating Big Rocks ===")
    content = read_file("projects/big-rocks.md")
    if not content:
        return 0

    # Find current week date range
    m = re.search(r'Current Week:?\s*(\w+ \d+)\s*[-–]\s*(\w+ \d+),?\s*(\d{4})?', content)
    if not m:
        # Try alternate pattern
        m = re.search(r'Week:?\s*(\d{4}-\d{2}-\d{2})', content)

    # Extract rocks
    rocks = []
    rock_section = re.search(r'🪨.*?Big Rocks.*?\n(.*?)(?=\n##|\n🌊|\Z)', content, re.DOTALL)
    if rock_section:
        for rm in re.finditer(r'^\d+\.\s+(.+?)$', rock_section.group(1), re.MULTILINE):
            title = rm.group(1).strip().strip('*')
            rocks.append({"title": title, "status": "", "why": ""})

    if rocks:
        # Use a reasonable week_start date
        week_start = "2025-12-22"  # From the file content (Dec 23-29, 2025)
        mcp_call("save_big_rocks", {
            "week_start": week_start,
            "items": rocks,
        })
        print(f"  Saved {len(rocks)} rocks for week of {week_start}")
        return len(rocks)

    print("  No rocks found")
    return 0

# ============================================================================
# 6. Calendar Events
# ============================================================================

def migrate_calendar():
    print("\n=== Migrating Calendar Events ===")
    cal_dir = os.path.join(CLAUDE_LIFE, "calendar")
    if not os.path.isdir(cal_dir):
        print("  Calendar directory not found")
        return 0

    count = 0
    for fname in sorted(os.listdir(cal_dir)):
        if not fname.endswith(".md") or fname == "README.md":
            continue

        content = read_file(f"calendar/{fname}")
        if not content:
            continue

        # Extract year-month from filename (e.g., 2026-01.md)
        ym_match = re.match(r'(\d{4})-(\d{2})', fname)
        if not ym_match:
            continue
        year, month = int(ym_match.group(1)), int(ym_match.group(2))

        # Parse daily entries: ### Day, Month Date
        current_date = None
        for line in content.split('\n'):
            # Match date headers
            date_m = re.match(r'^###\s+\w+,\s+(\w+)\s+(\d+)', line)
            if date_m:
                month_name = date_m.group(1)
                day = int(date_m.group(2))
                months = {"Jan":1,"Feb":2,"Mar":3,"Apr":4,"May":5,"Jun":6,
                          "Jul":7,"Aug":8,"Sep":9,"Oct":10,"Nov":11,"Dec":12,
                          "January":1,"February":2,"March":3,"April":4,"May":5,
                          "June":6,"July":7,"August":8,"September":9,"October":10,
                          "November":11,"December":12}
                m_num = months.get(month_name, month)
                current_date = f"{year}-{m_num:02d}-{day:02d}"
                continue

            if not current_date:
                continue

            # Match event lines: - HH:MM-HH:MM | Title @ Location
            ev_m = re.match(r'^-\s+(\d{1,2}:\d{2})\s*-\s*(\d{1,2}:\d{2})\s*\|\s*(.+)', line)
            if ev_m:
                start_time = ev_m.group(1)
                end_time = ev_m.group(2)
                rest = ev_m.group(3).strip()
                # Split title @ location
                if " @ " in rest:
                    title, location = rest.rsplit(" @ ", 1)
                else:
                    title, location = rest, ""
                # Clean emoji
                title = re.sub(r'[🔄🎯📞🚗⚠️💰⭐]', '', title).strip()
                location = re.sub(r'[🔄🎯📞🚗⚠️💰⭐]', '', location).strip()

                mcp_call("save_calendar_event", {
                    "event_date": current_date,
                    "start_time": start_time,
                    "end_time": end_time,
                    "title": title.strip('*').strip(),
                    "location": location.strip('*').strip() if location else None,
                    "is_recurring": "🔄" in line,
                })
                count += 1
                continue

            # Match all-day events: - All day | Title @ Location
            ad_m = re.match(r'^-\s+All day\s*\|\s*(.+)', line, re.IGNORECASE)
            if ad_m:
                rest = ad_m.group(1).strip()
                if " @ " in rest:
                    title, location = rest.rsplit(" @ ", 1)
                else:
                    title, location = rest, ""
                title = re.sub(r'[🔄🎯📞🚗⚠️💰⭐🇷🇴🎉]', '', title).strip()

                mcp_call("save_calendar_event", {
                    "event_date": current_date,
                    "all_day": True,
                    "title": title.strip('*').strip(),
                    "location": location.strip() if location else None,
                })
                count += 1

    print(f"  Total: {count} events")
    return count

# ============================================================================
# 7. Journal Entries
# ============================================================================

def migrate_journal():
    print("\n=== Migrating Journal Entries ===")
    journal_dir = os.path.join(CLAUDE_LIFE, "journal", "daily")
    if not os.path.isdir(journal_dir):
        print("  Journal directory not found")
        return 0

    count = 0
    for fname in sorted(os.listdir(journal_dir)):
        if not fname.endswith(".md"):
            continue

        # Extract date from filename
        date_m = re.match(r'(\d{4}-\d{2}-\d{2})', fname)
        if not date_m:
            continue
        entry_date = date_m.group(1)

        # Determine type from filename
        entry_type = "checkin"
        if "reflection" in fname:
            entry_type = "reflection"
        elif "gtd-review" in fname:
            entry_type = "gtd-review"
        elif "tomorrow" in fname or "plan" in fname:
            entry_type = "note"

        content = read_file(f"journal/daily/{fname}")
        if not content:
            continue

        # Extract structured fields
        content_data = {}

        # Mood
        m = re.search(r'(?:Mood|mood)[:\s]*(\d+)\s*/\s*10', content)
        if m:
            content_data['mood'] = int(m.group(1))

        # Energy
        m = re.search(r'(?:Energy|energy)[:\s]*(\d+)\s*/\s*10', content)
        if m:
            content_data['energy'] = int(m.group(1))

        # Honest truth
        m = re.search(r'\*\*Honest truth:\*\*\s*(.+?)(?:\n|$)', content)
        if m:
            content_data['honest_truth'] = m.group(1).strip()

        # Workout
        m = re.search(r'(?:Workout|workout)[:\s]*(?:Yes|yes|✅)\s*[-–—]?\s*(.*?)(?:\n|$)', content)
        if m:
            content_data['workout'] = m.group(1).strip() or "Yes"
        elif re.search(r'(?:Workout|workout)[:\s]*(?:No|no|❌)', content):
            content_data['workout'] = "No"

        # Big 3 alignment
        m = re.search(r'(?:Alignment|alignment)[:\s]*(\d+)\s*/\s*3', content)
        if m:
            content_data['big3_alignment'] = int(m.group(1))

        # Life categories count
        m = re.search(r'Categories invested[:\s]*(\d+)\s*/\s*5', content)
        if m:
            content_data['categories_invested'] = int(m.group(1))

        mcp_call("save_journal_entry", {
            "entry_date": entry_date,
            "type": entry_type,
            "content_json": content_data,
            "content_md": content[:50000],  # Truncate very long entries
        })
        count += 1
        if count % 10 == 0:
            print(f"  ... {count} entries migrated")

    print(f"  Total: {count} journal entries")
    return count

# ============================================================================
# 8. Metrics (Digestion)
# ============================================================================

def migrate_metrics():
    print("\n=== Migrating Metrics ===")
    content = read_file("metrics/digestion-tracker.md")
    if not content:
        return 0

    count = 0
    # Parse table rows: | YYYY-MM-DD | N | N | N | N | Notes |
    for m in re.finditer(r'\|\s*(\d{4}-\d{2}-\d{2})\s*\|\s*(\d+)\s*\|\s*(\d+)\s*\|\s*(\d+)\s*\|\s*(\d+)\s*\|\s*(.*?)\s*\|', content):
        date = m.group(1)
        data = {
            "overall": int(m.group(2)),
            "gas": int(m.group(3)),
            "pain": int(m.group(4)),
            "regularity": int(m.group(5)),
            "notes": m.group(6).strip(),
        }
        mcp_call("save_metric", {
            "metric_type": "digestion",
            "metric_date": date,
            "data": data,
        })
        count += 1

    print(f"  Total: {count} digestion entries")
    return count

# ============================================================================
# Main
# ============================================================================

def main():
    targets = [a for a in sys.argv[1:] if not a.startswith('-')]

    print("=" * 60)
    print("Claude Life MCP — Data Migration")
    print(f"Source: {CLAUDE_LIFE}")
    print(f"Target: {MCP_URL}")
    print(f"Mode: {'DRY RUN' if DRY_RUN else 'LIVE'}")
    print("=" * 60)

    if not os.path.isdir(CLAUDE_LIFE):
        print(f"ERROR: Source directory not found: {CLAUDE_LIFE}")
        sys.exit(1)

    total = 0
    migrations = [
        ("constitution", migrate_constitution),
        ("goals", migrate_life_goals),
        ("contexts", migrate_gtd_contexts),
        ("projects", migrate_projects),
        ("rocks", migrate_big_rocks),
        ("calendar", migrate_calendar),
        ("journal", migrate_journal),
        ("metrics", migrate_metrics),
    ]

    for name, func in migrations:
        if targets and name not in targets:
            continue
        try:
            n = func()
            total += n
        except Exception as e:
            print(f"  FAILED {name}: {e}")
            import traceback
            traceback.print_exc()

    print("\n" + "=" * 60)
    print(f"Migration complete! Total records: {total}")
    if DRY_RUN:
        print("(DRY RUN — no data was actually written)")
    print("=" * 60)

if __name__ == "__main__":
    main()
