"""
Project Context Management

Maintains comprehensive project state including:
- File index with AST metadata
- Dependency graphs
- Test coverage
- Conversation history
- Active tasks
"""

from pathlib import Path
from typing import Dict, List, Optional, Any
from datetime import datetime
import json

from groknroll.storage.database import Database
from groknroll.storage.models import Project, FileIndex


class ProjectContext:
    """
    Project context manager

    Maintains all project state in SQLite database for instant access.
    """

    def __init__(self, project_path: Path, database: Optional[Database] = None):
        """
        Initialize project context

        Args:
            project_path: Path to project root
            database: Database instance (creates new if None)
        """
        self.project_path = project_path.resolve()
        self.db = database or Database()

        # Get or create project in database
        self.project = self.db.get_or_create_project(self.project_path)

    def index_project(self, force: bool = False) -> Dict[str, Any]:
        """
        Index entire project

        Args:
            force: Force re-indexing even if up-to-date

        Returns:
            Indexing statistics
        """
        indexed_count = 0
        total_lines = 0
        skipped_count = 0

        # File extensions to index
        code_extensions = {
            '.py', '.js', '.ts', '.jsx', '.tsx',
            '.go', '.rs', '.java', '.c', '.cpp', '.h', '.hpp',
            '.rb', '.php', '.swift', '.kt', '.scala'
        }

        for file_path in self.project_path.rglob('*'):
            if not file_path.is_file():
                continue

            if file_path.suffix not in code_extensions:
                continue

            # Skip common directories
            if any(part.startswith('.') or part in ['node_modules', 'venv', '.venv', 'dist', 'build']
                   for part in file_path.parts):
                skipped_count += 1
                continue

            try:
                # Get file stats
                stat = file_path.stat()
                relative_path = str(file_path.relative_to(self.project_path))

                # Count lines
                with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                    lines = len(f.readlines())
                    total_lines += lines

                # Determine language
                language = self._detect_language(file_path.suffix)

                # Index file
                self.db.index_file(
                    project_id=self.project.id,
                    file_path=file_path,
                    relative_path=relative_path,
                    language=language,
                    size_bytes=stat.st_size,
                    lines_of_code=lines,
                    last_modified=datetime.fromtimestamp(stat.st_mtime)
                )

                indexed_count += 1

            except Exception as e:
                print(f"Error indexing {file_path}: {e}")
                continue

        # Update project stats
        self.db.update_project_stats(
            project_id=self.project.id,
            total_files=indexed_count,
            total_lines=total_lines
        )

        return {
            "indexed": indexed_count,
            "skipped": skipped_count,
            "total_lines": total_lines
        }

    def get_file_context(self, file_path: Path) -> Optional[Dict[str, Any]]:
        """Get context for specific file"""
        files = self.db.get_project_files(self.project.id)

        for f in files:
            if Path(f.path) == file_path:
                return {
                    "path": f.path,
                    "relative_path": f.relative_path,
                    "language": f.language,
                    "lines_of_code": f.lines_of_code,
                    "complexity": f.complexity,
                    "imports": f.imports,
                    "exports": f.exports,
                }

        return None

    def search_files(self, query: str, language: Optional[str] = None) -> List[Dict[str, Any]]:
        """Search indexed files"""
        results = self.db.search_files(
            project_id=self.project.id,
            query=query,
            language=language
        )

        return [
            {
                "path": f.path,
                "relative_path": f.relative_path,
                "language": f.language,
                "lines_of_code": f.lines_of_code,
            }
            for f in results
        ]

    def get_project_overview(self) -> Dict[str, Any]:
        """Get project overview"""
        files = self.db.get_project_files(self.project.id)

        # Group by language
        language_stats = {}
        for f in files:
            lang = f.language or "unknown"
            if lang not in language_stats:
                language_stats[lang] = {"files": 0, "lines": 0}

            language_stats[lang]["files"] += 1
            language_stats[lang]["lines"] += f.lines_of_code or 0

        return {
            "name": self.project.name,
            "path": self.project.path,
            "total_files": self.project.total_files or 0,
            "total_lines": self.project.total_lines or 0,
            "last_indexed": self.project.last_indexed,
            "languages": language_stats
        }

    def get_execution_stats(self) -> Dict[str, Any]:
        """Get RLM execution statistics"""
        return self.db.get_execution_stats(self.project.id)

    def log_execution(
        self,
        task: str,
        response: str,
        **metrics
    ) -> None:
        """Log RLM execution"""
        self.db.log_execution(
            project_id=self.project.id,
            task=task,
            response=response,
            **metrics
        )

    def save_analysis(
        self,
        analysis_type: str,
        results: Dict[str, Any],
        **metadata
    ) -> None:
        """Save analysis results"""
        self.db.save_analysis(
            project_id=self.project.id,
            analysis_type=analysis_type,
            results=results,
            **metadata
        )

    def get_latest_analysis(self, analysis_type: str) -> Optional[Dict[str, Any]]:
        """Get latest analysis of given type"""
        analysis = self.db.get_latest_analysis(
            project_id=self.project.id,
            analysis_type=analysis_type
        )

        if analysis:
            return {
                "type": analysis.analysis_type,
                "results": analysis.results,
                "recommendations": analysis.recommendations,
                "issues": analysis.issues,
                "metrics": analysis.metrics,
                "created_at": analysis.created_at
            }

        return None

    def _detect_language(self, extension: str) -> str:
        """Detect language from file extension"""
        mapping = {
            '.py': 'python',
            '.js': 'javascript',
            '.ts': 'typescript',
            '.jsx': 'javascript',
            '.tsx': 'typescript',
            '.go': 'go',
            '.rs': 'rust',
            '.java': 'java',
            '.c': 'c',
            '.cpp': 'cpp',
            '.h': 'c',
            '.hpp': 'cpp',
            '.rb': 'ruby',
            '.php': 'php',
            '.swift': 'swift',
            '.kt': 'kotlin',
            '.scala': 'scala',
        }

        return mapping.get(extension, 'unknown')
