"""Context Manager for maintaining project understanding and goals."""
import json
import os
from datetime import datetime
from typing import Dict, List, Optional, Any
from pathlib import Path
import logging
import git
from dataclasses import dataclass, asdict

logger = logging.getLogger(__name__)

@dataclass
class ProjectContext:
    """Represents the current state and goals of the project."""
    name: str
    description: str
    goals: List[Dict[str, Any]]
    success_criteria: List[str]
    current_phase: str
    technologies: Dict[str, str]
    dependencies: Dict[str, str]
    last_updated: str

@dataclass
class CodebaseSnapshot:
    """Represents a snapshot of the codebase state."""
    timestamp: str
    files_changed: List[str]
    lines_changed: int
    commit_message: str
    branch: str
    author: str

class ContextManager:
    """Manages project context and understanding."""
    
    def __init__(self, workspace_root: str):
        """Initialize the Context Manager."""
        self.workspace_root = Path(workspace_root)
        self.context_db_path = self.workspace_root / '.cursor' / 'context_db.json'
        self.context_db_path.parent.mkdir(parents=True, exist_ok=True)
        self.repo = git.Repo(workspace_root)
        self.load_context_db()

    def load_context_db(self):
        """Load the context database from disk."""
        if self.context_db_path.exists():
            try:
                with open(self.context_db_path, 'r') as f:
                    self.context_db = json.load(f)
            except json.JSONDecodeError:
                logger.error("Error loading context database, creating new one")
                self.context_db = self._create_default_context()
        else:
            self.context_db = self._create_default_context()

    def save_context_db(self):
        """Save the context database to disk."""
        with open(self.context_db_path, 'w') as f:
            json.dump(self.context_db, f, indent=2)

    def _create_default_context(self) -> Dict[str, Any]:
        """Create a default context structure."""
        return {
            'project': asdict(ProjectContext(
                name=self.workspace_root.name,
                description="",
                goals=[],
                success_criteria=[],
                current_phase="initialization",
                technologies={},
                dependencies={},
                last_updated=datetime.now().isoformat()
            )),
            'snapshots': [],
            'insights': [],
            'documentation': {}
        }

    def update_project_context(self, updates: Dict[str, Any]):
        """Update project context with new information."""
        project = self.context_db['project']
        for key, value in updates.items():
            if key in project:
                if isinstance(project[key], dict):
                    project[key].update(value)
                elif isinstance(project[key], list):
                    project[key].extend(value)
                else:
                    project[key] = value
        
        project['last_updated'] = datetime.now().isoformat()
        self.save_context_db()

    def record_codebase_snapshot(self):
        """Take a snapshot of the current codebase state."""
        repo = self.repo
        commit = repo.head.commit
        
        # Get files changed in last commit
        files_changed = [item.a_path for item in commit.diff('HEAD~1')]
        
        snapshot = CodebaseSnapshot(
            timestamp=datetime.now().isoformat(),
            files_changed=files_changed,
            lines_changed=sum(1 for _ in commit.stats.files.values()),
            commit_message=commit.message,
            branch=repo.active_branch.name,
            author=f"{commit.author.name} <{commit.author.email}>"
        )
        
        self.context_db['snapshots'].append(asdict(snapshot))
        self._analyze_snapshot(snapshot)
        self.save_context_db()

    def add_insight(self, insight: str, category: str, source: str):
        """Add a new insight about the project."""
        self.context_db['insights'].append({
            'timestamp': datetime.now().isoformat(),
            'insight': insight,
            'category': category,
            'source': source
        })
        self.save_context_db()

    def update_documentation(self, path: str, content: str):
        """Update documentation for a specific part of the project."""
        self.context_db['documentation'][path] = {
            'content': content,
            'last_updated': datetime.now().isoformat()
        }
        self.save_context_db()

    def get_project_context(self) -> ProjectContext:
        """Get the current project context."""
        return ProjectContext(**self.context_db['project'])

    def get_recent_changes(self, n: int = 5) -> List[CodebaseSnapshot]:
        """Get the N most recent codebase snapshots."""
        snapshots = self.context_db['snapshots'][-n:]
        return [CodebaseSnapshot(**s) for s in snapshots]

    def get_insights(self, category: Optional[str] = None) -> List[Dict[str, Any]]:
        """Get project insights, optionally filtered by category."""
        insights = self.context_db['insights']
        if category:
            insights = [i for i in insights if i['category'] == category]
        return insights

    def get_documentation(self, path: Optional[str] = None) -> Dict[str, Any]:
        """Get documentation, optionally for a specific path."""
        if path:
            return self.context_db['documentation'].get(path, {})
        return self.context_db['documentation']

    def _analyze_snapshot(self, snapshot: CodebaseSnapshot):
        """Analyze a codebase snapshot for insights."""
        # Analyze commit message for intent
        message = snapshot.commit_message.lower()
        if 'fix' in message:
            self.add_insight(
                f"Bug fix in {', '.join(snapshot.files_changed)}",
                'bug_fix',
                'commit_analysis'
            )
        elif 'feature' in message:
            self.add_insight(
                f"New feature added: {snapshot.commit_message}",
                'feature',
                'commit_analysis'
            )
        elif 'refactor' in message:
            self.add_insight(
                f"Code refactoring in {', '.join(snapshot.files_changed)}",
                'refactoring',
                'commit_analysis'
            )
        
        # Analyze file patterns
        file_types = [Path(f).suffix for f in snapshot.files_changed]
        if '.py' in file_types:
            self.update_project_context({
                'technologies': {'Python': 'active'}
            })
        
        # Update project phase based on patterns
        if any('test' in f for f in snapshot.files_changed):
            self.update_project_context({
                'current_phase': 'testing'
            }) 