#!/usr/bin/env python3
"""
Mastery Tracker - Capability Mastery Progress System
====================================================
PostgreSQL-based tracking for Claude Code capability mastery.
Uses Elestio Core infrastructure (RULE 6: No SQLite).

Tracks:
- Discovery progress
- Implementation status
- Test coverage
- Real-world application
- Optimization level
- Overall mastery score
"""

import sys
import json
from datetime import datetime
from typing import Dict, List, Any, Optional
from dataclasses import dataclass, field
from enum import Enum

# Elestio PostgreSQL config
sys.path.append('/mnt/e/genesis-system/data/genesis-memory')
from elestio_config import PostgresConfig
import psycopg2
from psycopg2.extras import RealDictCursor


class MasteryPhase(Enum):
    NOT_STARTED = "not_started"
    DISCOVERY = "discovery"
    IMPLEMENTING = "implementing"
    TESTING = "testing"
    APPLYING = "applying"
    OPTIMIZING = "optimizing"
    MASTERED = "mastered"


class ValueTier(Enum):
    CRITICAL = "critical"      # 95-100 value score
    HIGH = "high"              # 80-94 value score
    MEDIUM = "medium"          # 60-79 value score
    LOW = "low"                # < 60 value score


@dataclass
class CapabilityMastery:
    """Mastery progress for a single capability."""
    id: str
    name: str
    category: str
    value_score: int  # 0-100
    value_tier: str

    # Mastery phases (each worth points)
    discovery_complete: bool = False      # 10 pts
    implementation_complete: bool = False  # 25 pts
    testing_complete: bool = False         # 25 pts
    application_complete: bool = False     # 25 pts
    optimization_complete: bool = False    # 15 pts

    # Details
    discovery_notes: str = ""
    implementation_file: str = ""
    test_file: str = ""
    applications: List[str] = field(default_factory=list)
    optimizations: List[str] = field(default_factory=list)

    # Timestamps
    discovered_at: str = ""
    implemented_at: str = ""
    tested_at: str = ""
    mastered_at: str = ""

    @property
    def mastery_score(self) -> int:
        """Calculate total mastery score (0-100)."""
        score = 0
        if self.discovery_complete:
            score += 10
        if self.implementation_complete:
            score += 25
        if self.testing_complete:
            score += 25
        if self.application_complete:
            score += 25
        if self.optimization_complete:
            score += 15
        return score

    @property
    def phase(self) -> MasteryPhase:
        """Get current mastery phase."""
        if self.optimization_complete:
            return MasteryPhase.MASTERED
        if self.application_complete:
            return MasteryPhase.OPTIMIZING
        if self.testing_complete:
            return MasteryPhase.APPLYING
        if self.implementation_complete:
            return MasteryPhase.TESTING
        if self.discovery_complete:
            return MasteryPhase.IMPLEMENTING
        return MasteryPhase.NOT_STARTED


class MasteryTracker:
    """
    PostgreSQL-based mastery tracking system.

    Usage:
        tracker = MasteryTracker()

        # Add capability
        tracker.add_capability("task_tool", "Task Tool", "intelligence", 98)

        # Update progress
        tracker.complete_discovery("task_tool", "Documented all parameters")
        tracker.complete_implementation("task_tool", "core/task_wrapper.py")
        tracker.complete_testing("task_tool", "tests/test_task_tool.py")

        # Get progress
        stats = tracker.get_mastery_stats()
        dashboard = tracker.get_ascii_dashboard()
    """

    def __init__(self):
        self.conn_params = PostgresConfig.get_connection_params()
        self._init_db()

    def _get_conn(self):
        """Get PostgreSQL connection."""
        return psycopg2.connect(**self.conn_params)

    def _init_db(self):
        """Initialize database schema."""
        with self._get_conn() as conn:
            with conn.cursor() as cur:
                cur.execute("""
                    CREATE TABLE IF NOT EXISTS capability_mastery (
                        id TEXT PRIMARY KEY,
                        name TEXT NOT NULL,
                        category TEXT NOT NULL,
                        value_score INTEGER DEFAULT 50,
                        value_tier TEXT DEFAULT 'medium',

                        discovery_complete BOOLEAN DEFAULT FALSE,
                        implementation_complete BOOLEAN DEFAULT FALSE,
                        testing_complete BOOLEAN DEFAULT FALSE,
                        application_complete BOOLEAN DEFAULT FALSE,
                        optimization_complete BOOLEAN DEFAULT FALSE,

                        discovery_notes TEXT,
                        implementation_file TEXT,
                        test_file TEXT,
                        applications JSONB DEFAULT '[]',
                        optimizations JSONB DEFAULT '[]',

                        discovered_at TIMESTAMP,
                        implemented_at TIMESTAMP,
                        tested_at TIMESTAMP,
                        mastered_at TIMESTAMP,

                        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                        updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                    )
                """)

                cur.execute("""
                    CREATE TABLE IF NOT EXISTS mastery_history (
                        id SERIAL PRIMARY KEY,
                        capability_id TEXT REFERENCES capability_mastery(id),
                        phase TEXT,
                        action TEXT,
                        details TEXT,
                        timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                    )
                """)

                cur.execute("""
                    CREATE INDEX IF NOT EXISTS idx_mastery_category
                    ON capability_mastery(category)
                """)
                cur.execute("""
                    CREATE INDEX IF NOT EXISTS idx_mastery_tier
                    ON capability_mastery(value_tier)
                """)
            conn.commit()

    def add_capability(self, cap_id: str, name: str, category: str,
                       value_score: int, notes: str = "") -> bool:
        """Add a capability to track."""
        tier = self._score_to_tier(value_score)

        try:
            with self._get_conn() as conn:
                with conn.cursor() as cur:
                    cur.execute("""
                        INSERT INTO capability_mastery
                        (id, name, category, value_score, value_tier, discovery_notes)
                        VALUES (%s, %s, %s, %s, %s, %s)
                        ON CONFLICT (id) DO UPDATE SET
                            name = EXCLUDED.name,
                            category = EXCLUDED.category,
                            value_score = EXCLUDED.value_score,
                            value_tier = EXCLUDED.value_tier,
                            updated_at = CURRENT_TIMESTAMP
                    """, (cap_id, name, category, value_score, tier, notes))
                conn.commit()
                return True
        except Exception as e:
            print(f"Error adding capability: {e}")
            return False

    def _score_to_tier(self, score: int) -> str:
        """Convert value score to tier."""
        if score >= 95:
            return ValueTier.CRITICAL.value
        elif score >= 80:
            return ValueTier.HIGH.value
        elif score >= 60:
            return ValueTier.MEDIUM.value
        return ValueTier.LOW.value

    def complete_discovery(self, cap_id: str, notes: str = "") -> bool:
        """Mark discovery phase complete."""
        return self._update_phase(cap_id, "discovery", notes)

    def complete_implementation(self, cap_id: str, impl_file: str = "") -> bool:
        """Mark implementation phase complete."""
        return self._update_phase(cap_id, "implementation", impl_file)

    def complete_testing(self, cap_id: str, test_file: str = "") -> bool:
        """Mark testing phase complete."""
        return self._update_phase(cap_id, "testing", test_file)

    def complete_application(self, cap_id: str, application: str = "") -> bool:
        """Mark application phase complete (needs 3 applications)."""
        with self._get_conn() as conn:
            with conn.cursor(cursor_factory=RealDictCursor) as cur:
                cur.execute(
                    "SELECT applications FROM capability_mastery WHERE id = %s",
                    (cap_id,)
                )
                row = cur.fetchone()
                if row:
                    apps = row['applications'] or []
                    if application and application not in apps:
                        apps.append(application)

                    complete = len(apps) >= 3
                    cur.execute("""
                        UPDATE capability_mastery SET
                            applications = %s,
                            application_complete = %s,
                            updated_at = CURRENT_TIMESTAMP
                        WHERE id = %s
                    """, (json.dumps(apps), complete, cap_id))

                    self._log_history(cur, cap_id, "application",
                                     f"Added: {application}" if application else "Checked")
            conn.commit()
            return True
        return False

    def complete_optimization(self, cap_id: str, optimization: str = "") -> bool:
        """Mark optimization phase complete."""
        return self._update_phase(cap_id, "optimization", optimization)

    def _update_phase(self, cap_id: str, phase: str, details: str = "") -> bool:
        """Update a mastery phase."""
        field_map = {
            "discovery": ("discovery_complete", "discovery_notes", "discovered_at"),
            "implementation": ("implementation_complete", "implementation_file", "implemented_at"),
            "testing": ("testing_complete", "test_file", "tested_at"),
            "optimization": ("optimization_complete", None, "mastered_at"),
        }

        if phase not in field_map:
            return False

        complete_field, details_field, time_field = field_map[phase]

        with self._get_conn() as conn:
            with conn.cursor() as cur:
                if details_field:
                    cur.execute(f"""
                        UPDATE capability_mastery SET
                            {complete_field} = TRUE,
                            {details_field} = %s,
                            {time_field} = CURRENT_TIMESTAMP,
                            updated_at = CURRENT_TIMESTAMP
                        WHERE id = %s
                    """, (details, cap_id))
                else:
                    cur.execute(f"""
                        UPDATE capability_mastery SET
                            {complete_field} = TRUE,
                            {time_field} = CURRENT_TIMESTAMP,
                            updated_at = CURRENT_TIMESTAMP
                        WHERE id = %s
                    """, (cap_id,))

                self._log_history(cur, cap_id, phase, details)
            conn.commit()
            return True

    def _log_history(self, cur, cap_id: str, phase: str, details: str):
        """Log mastery history."""
        cur.execute("""
            INSERT INTO mastery_history (capability_id, phase, action, details)
            VALUES (%s, %s, %s, %s)
        """, (cap_id, phase, f"Completed {phase}", details))

    def get_capability(self, cap_id: str) -> Optional[CapabilityMastery]:
        """Get capability mastery status."""
        with self._get_conn() as conn:
            with conn.cursor(cursor_factory=RealDictCursor) as cur:
                cur.execute("SELECT * FROM capability_mastery WHERE id = %s", (cap_id,))
                row = cur.fetchone()
                if row:
                    return self._row_to_mastery(row)
        return None

    def get_all(self, order_by: str = "value_score DESC") -> List[CapabilityMastery]:
        """Get all capabilities ordered by value score."""
        with self._get_conn() as conn:
            with conn.cursor(cursor_factory=RealDictCursor) as cur:
                cur.execute(f"SELECT * FROM capability_mastery ORDER BY {order_by}")
                return [self._row_to_mastery(row) for row in cur.fetchall()]

    def get_by_tier(self, tier: str) -> List[CapabilityMastery]:
        """Get capabilities by value tier."""
        with self._get_conn() as conn:
            with conn.cursor(cursor_factory=RealDictCursor) as cur:
                cur.execute(
                    "SELECT * FROM capability_mastery WHERE value_tier = %s ORDER BY value_score DESC",
                    (tier,)
                )
                return [self._row_to_mastery(row) for row in cur.fetchall()]

    def get_by_phase(self, phase: MasteryPhase) -> List[CapabilityMastery]:
        """Get capabilities at a specific mastery phase."""
        all_caps = self.get_all()
        return [c for c in all_caps if c.phase == phase]

    def _row_to_mastery(self, row) -> CapabilityMastery:
        """Convert database row to CapabilityMastery."""
        return CapabilityMastery(
            id=row['id'],
            name=row['name'],
            category=row['category'],
            value_score=row['value_score'],
            value_tier=row['value_tier'],
            discovery_complete=row['discovery_complete'],
            implementation_complete=row['implementation_complete'],
            testing_complete=row['testing_complete'],
            application_complete=row['application_complete'],
            optimization_complete=row['optimization_complete'],
            discovery_notes=row['discovery_notes'] or "",
            implementation_file=row['implementation_file'] or "",
            test_file=row['test_file'] or "",
            applications=row['applications'] if isinstance(row['applications'], list) else [],
            optimizations=row['optimizations'] if isinstance(row['optimizations'], list) else [],
            discovered_at=str(row['discovered_at']) if row['discovered_at'] else "",
            implemented_at=str(row['implemented_at']) if row['implemented_at'] else "",
            tested_at=str(row['tested_at']) if row['tested_at'] else "",
            mastered_at=str(row['mastered_at']) if row['mastered_at'] else "",
        )

    def get_mastery_stats(self) -> Dict[str, Any]:
        """Get overall mastery statistics."""
        with self._get_conn() as conn:
            with conn.cursor() as cur:
                cur.execute("SELECT COUNT(*) FROM capability_mastery")
                total = cur.fetchone()[0]

                cur.execute("""
                    SELECT
                        COUNT(*) FILTER (WHERE optimization_complete) as mastered,
                        COUNT(*) FILTER (WHERE application_complete AND NOT optimization_complete) as optimizing,
                        COUNT(*) FILTER (WHERE testing_complete AND NOT application_complete) as applying,
                        COUNT(*) FILTER (WHERE implementation_complete AND NOT testing_complete) as testing,
                        COUNT(*) FILTER (WHERE discovery_complete AND NOT implementation_complete) as implementing,
                        COUNT(*) FILTER (WHERE NOT discovery_complete) as not_started
                    FROM capability_mastery
                """)
                row = cur.fetchone()

                cur.execute("""
                    SELECT category, COUNT(*),
                           AVG(CASE
                               WHEN optimization_complete THEN 100
                               WHEN application_complete THEN 85
                               WHEN testing_complete THEN 60
                               WHEN implementation_complete THEN 35
                               WHEN discovery_complete THEN 10
                               ELSE 0
                           END) as avg_progress
                    FROM capability_mastery
                    GROUP BY category
                """)
                by_category = {r[0]: {"count": r[1], "progress": float(r[2] or 0)}
                               for r in cur.fetchall()}

                return {
                    "total": total,
                    "mastered": row[0],
                    "optimizing": row[1],
                    "applying": row[2],
                    "testing": row[3],
                    "implementing": row[4],
                    "not_started": row[5],
                    "by_category": by_category
                }

    def get_ascii_dashboard(self) -> str:
        """Generate ASCII dashboard."""
        stats = self.get_mastery_stats()
        total = stats['total'] or 1

        def progress_bar(count, total, width=20):
            filled = int(count / total * width) if total > 0 else 0
            return "█" * filled + "░" * (width - filled)

        lines = [
            "=" * 60,
            "     CLAUDE CODE CAPABILITY MASTERY DASHBOARD",
            "=" * 60,
            "",
            f"Total Capabilities: {stats['total']}",
            f"├── Mastered:     [{progress_bar(stats['mastered'], total, 15)}] {stats['mastered']}",
            f"├── Optimizing:   [{progress_bar(stats['optimizing'], total, 15)}] {stats['optimizing']}",
            f"├── Applying:     [{progress_bar(stats['applying'], total, 15)}] {stats['applying']}",
            f"├── Testing:      [{progress_bar(stats['testing'], total, 15)}] {stats['testing']}",
            f"├── Implementing: [{progress_bar(stats['implementing'], total, 15)}] {stats['implementing']}",
            f"└── Not Started:  [{progress_bar(stats['not_started'], total, 15)}] {stats['not_started']}",
            "",
            "By Category:",
        ]

        for cat, data in sorted(stats['by_category'].items()):
            pct = data['progress']
            bar = progress_bar(pct, 100, 10)
            lines.append(f"  {cat:<20} [{bar}] {pct:.0f}%")

        lines.extend(["", "=" * 60])
        return "\n".join(lines)

    def seed_capabilities(self) -> int:
        """Seed with known Claude Code capabilities."""
        capabilities = [
            # Core Tools
            ("tool_read", "Read Tool", "tool_system", 100),
            ("tool_write", "Write Tool", "tool_system", 100),
            ("tool_edit", "Edit Tool", "tool_system", 100),
            ("tool_glob", "Glob Tool", "tool_system", 95),
            ("tool_grep", "Grep Tool", "tool_system", 95),
            ("tool_bash", "Bash Tool", "tool_system", 100),
            ("tool_web_fetch", "WebFetch Tool", "tool_system", 85),
            ("tool_web_search", "WebSearch Tool", "tool_system", 90),

            # Advanced Tools
            ("tool_task", "Task Tool", "intelligence", 98),
            ("tool_task_output", "TaskOutput Tool", "intelligence", 90),
            ("tool_lsp", "LSP Tool", "code_intelligence", 85),
            ("tool_notebook_edit", "NotebookEdit Tool", "tool_system", 70),
            ("tool_ask_user", "AskUserQuestion Tool", "interaction", 92),
            ("tool_todo_write", "TodoWrite Tool", "planning", 88),
            ("tool_kill_shell", "KillShell Tool", "tool_system", 75),
            ("tool_enter_plan", "EnterPlanMode Tool", "planning", 85),
            ("tool_exit_plan", "ExitPlanMode Tool", "planning", 85),
            ("tool_skill", "Skill Tool", "skills", 95),

            # Subagents
            ("subagent_general", "General Purpose Subagent", "intelligence", 95),
            ("subagent_explore", "Explore Subagent", "intelligence", 90),
            ("subagent_plan", "Plan Subagent", "intelligence", 88),
            ("subagent_claude_guide", "Claude Code Guide Subagent", "intelligence", 80),

            # MCP
            ("mcp_server_connection", "MCP Server Connection", "mcp", 95),
            ("mcp_tool_discovery", "MCP Tool Discovery", "mcp", 90),
            ("mcp_tool_execution", "MCP Tool Execution", "mcp", 92),
            ("mcp_resource_access", "MCP Resource Access", "mcp", 85),
            ("mcp_custom_servers", "Custom MCP Servers", "mcp", 98),

            # Hooks
            ("hook_pre_tool", "PreToolCall Hooks", "hooks", 88),
            ("hook_post_tool", "PostToolCall Hooks", "hooks", 88),
            ("hook_notification", "Notification Hooks", "hooks", 82),

            # Skills
            ("skill_builtin", "Built-in Skills", "skills", 85),
            ("skill_custom", "Custom Skill Creation", "skills", 95),
            ("skill_arguments", "Skill Arguments", "skills", 88),
            ("skill_chaining", "Skill Chaining", "skills", 82),

            # CLI
            ("cli_skip_perms", "--dangerously-skip-permissions", "cli", 95),
            ("cli_print", "--print / -p", "cli", 80),
            ("cli_model", "--model selection", "cli", 88),
            ("cli_resume", "--resume / -r", "cli", 85),
            ("cli_mcp_config", "--mcp-config", "cli", 85),

            # Context
            ("ctx_summarization", "Auto-Summarization", "context", 92),
            ("ctx_claude_md", "CLAUDE.md Config", "context", 95),
            ("ctx_settings_local", "Local Settings Override", "context", 88),
            ("ctx_global_rules", "Global Rules System", "context", 90),

            # Safety
            ("safety_permissions", "Permission System", "security", 95),
            ("safety_sandbox", "Sandbox Mode", "security", 88),
            ("safety_git", "Git Safety Protocol", "security", 90),
        ]

        count = 0
        for cap_id, name, category, score in capabilities:
            if self.add_capability(cap_id, name, category, score):
                count += 1

        return count


# Quick test
if __name__ == "__main__":
    print("Testing Mastery Tracker (Elestio PostgreSQL)...")
    tracker = MasteryTracker()

    # Seed capabilities
    seeded = tracker.seed_capabilities()
    print(f"  Seeded {seeded} capabilities")

    # Get stats
    stats = tracker.get_mastery_stats()
    print(f"  Total: {stats['total']}")

    # Show dashboard
    print()
    print(tracker.get_ascii_dashboard())
