"""Senior Developer for handling code implementation and technical guidance."""
import json
from datetime import datetime
from typing import Dict, List, Optional, Any, Union
from dataclasses import dataclass, asdict
import logging
import re
from pathlib import Path

logger = logging.getLogger(__name__)

@dataclass
class CodeReview:
    """Represents a code review with comments and suggestions."""
    id: str
    pr_number: str
    reviewer: str
    files_reviewed: List[str]
    comments: List[Dict[str, Any]]
    suggestions: List[Dict[str, Any]]
    status: str
    created_at: str
    updated_at: str

@dataclass
class Implementation:
    """Represents a code implementation task."""
    id: str
    task_id: str
    developer: str
    files_changed: List[str]
    commit_messages: List[str]
    status: str
    review_status: str
    test_status: str
    created_at: str
    updated_at: str
    completed_at: Optional[str] = None

@dataclass
class TechnicalGuidance:
    """Represents technical guidance or best practices."""
    id: str
    title: str
    description: str
    category: str
    code_examples: List[str]
    references: List[str]
    tags: List[str]
    created_at: str
    updated_at: str

class SeniorDeveloper:
    """Manages code implementation and technical guidance."""
    
    def __init__(self, context_manager, intelligence_manager,
                 engineering_manager, qa_manager):
        """Initialize the Senior Developer."""
        self.context_manager = context_manager
        self.intelligence_manager = intelligence_manager
        self.engineering_manager = engineering_manager
        self.qa_manager = qa_manager
        self.code_reviews: Dict[str, CodeReview] = {}
        self.implementations: Dict[str, Implementation] = {}
        self.guidance: Dict[str, TechnicalGuidance] = {}
        self.load_developer_data()

    def load_developer_data(self):
        """Load developer data from context database."""
        context = self.context_manager.get_project_context()
        dev_data = context.get('developer_data', {})
        
        # Load code reviews
        for review_dict in dev_data.get('code_reviews', []):
            review = CodeReview(**review_dict)
            self.code_reviews[review.id] = review
            
        # Load implementations
        for impl_dict in dev_data.get('implementations', []):
            implementation = Implementation(**impl_dict)
            self.implementations[implementation.id] = implementation
            
        # Load technical guidance
        for guide_dict in dev_data.get('guidance', []):
            guidance = TechnicalGuidance(**guide_dict)
            self.guidance[guidance.id] = guidance

    def save_developer_data(self):
        """Save developer data to context database."""
        dev_data = {
            'code_reviews': [asdict(review) for review in self.code_reviews.values()],
            'implementations': [
                asdict(impl) for impl in self.implementations.values()
            ],
            'guidance': [asdict(guide) for guide in self.guidance.values()]
        }
        
        self.context_manager.update_project_context({
            'developer_data': dev_data
        })

    def start_implementation(self, task_id: str, developer: str) -> Implementation:
        """Start implementing a technical task."""
        if task_id not in self.engineering_manager.tasks:
            raise ValueError(f"Task {task_id} not found")
            
        impl_id = f"impl_{task_id}"
        now = datetime.now().isoformat()
        
        implementation = Implementation(
            id=impl_id,
            task_id=task_id,
            developer=developer,
            files_changed=[],
            commit_messages=[],
            status="in_progress",
            review_status="pending",
            test_status="pending",
            created_at=now,
            updated_at=now
        )
        
        self.implementations[impl_id] = implementation
        self.save_developer_data()
        
        # Add insight about implementation start
        self.context_manager.add_insight(
            f"Started implementation of task {task_id} by {developer}",
            'development',
            'senior_developer'
        )
        
        return implementation

    def update_implementation(self, impl_id: str,
                            files_changed: List[str],
                            commit_message: str) -> Implementation:
        """Update implementation progress."""
        if impl_id not in self.implementations:
            raise ValueError(f"Implementation {impl_id} not found")
            
        implementation = self.implementations[impl_id]
        implementation.files_changed.extend(files_changed)
        implementation.commit_messages.append(commit_message)
        implementation.updated_at = datetime.now().isoformat()
        
        self.save_developer_data()
        return implementation

    def create_code_review(self, pr_number: str, reviewer: str,
                          files: List[str]) -> CodeReview:
        """Create a new code review."""
        review_id = f"review_{pr_number}"
        now = datetime.now().isoformat()
        
        review = CodeReview(
            id=review_id,
            pr_number=pr_number,
            reviewer=reviewer,
            files_reviewed=files,
            comments=[],
            suggestions=[],
            status="in_progress",
            created_at=now,
            updated_at=now
        )
        
        self.code_reviews[review_id] = review
        self.save_developer_data()
        
        # Add insight about code review
        self.context_manager.add_insight(
            f"Started code review for PR #{pr_number} by {reviewer}",
            'development',
            'senior_developer'
        )
        
        return review

    def add_review_comment(self, review_id: str, file_path: str,
                          line_number: int, comment: str,
                          suggestion: Optional[str] = None) -> CodeReview:
        """Add a comment to a code review."""
        if review_id not in self.code_reviews:
            raise ValueError(f"Code review {review_id} not found")
            
        review = self.code_reviews[review_id]
        now = datetime.now().isoformat()
        
        comment_data = {
            'file': file_path,
            'line': line_number,
            'comment': comment,
            'timestamp': now
        }
        review.comments.append(comment_data)
        
        if suggestion:
            suggestion_data = {
                'file': file_path,
                'line': line_number,
                'suggestion': suggestion,
                'timestamp': now
            }
            review.suggestions.append(suggestion_data)
        
        review.updated_at = now
        self.save_developer_data()
        
        return review

    def complete_code_review(self, review_id: str,
                            status: str) -> CodeReview:
        """Complete a code review with final status."""
        if review_id not in self.code_reviews:
            raise ValueError(f"Code review {review_id} not found")
            
        review = self.code_reviews[review_id]
        review.status = status
        review.updated_at = datetime.now().isoformat()
        
        # Update implementation status if found
        impl_id = f"impl_{review.pr_number}"
        if impl_id in self.implementations:
            self.implementations[impl_id].review_status = status
        
        self.save_developer_data()
        
        # Add insight about review completion
        self.context_manager.add_insight(
            f"Completed code review {review_id} with status: {status}",
            'development',
            'senior_developer'
        )
        
        return review

    def add_technical_guidance(self, title: str, description: str,
                             category: str, code_examples: List[str],
                             references: List[str], tags: List[str]) -> TechnicalGuidance:
        """Add technical guidance or best practices."""
        guide_id = f"guide_{len(self.guidance) + 1}"
        now = datetime.now().isoformat()
        
        guidance = TechnicalGuidance(
            id=guide_id,
            title=title,
            description=description,
            category=category,
            code_examples=code_examples,
            references=references,
            tags=tags,
            created_at=now,
            updated_at=now
        )
        
        self.guidance[guide_id] = guidance
        self.save_developer_data()
        
        # Add insight about new guidance
        self.context_manager.add_insight(
            f"Added technical guidance: {title}",
            'development',
            'senior_developer'
        )
        
        return guidance

    def search_guidance(self, query: str) -> List[Dict[str, Any]]:
        """Search technical guidance by query."""
        results = []
        query = query.lower()
        
        for guidance in self.guidance.values():
            # Check title and description
            if query in guidance.title.lower() or query in guidance.description.lower():
                results.append(asdict(guidance))
                continue
            
            # Check tags
            if any(query in tag.lower() for tag in guidance.tags):
                results.append(asdict(guidance))
                continue
            
            # Check code examples
            if any(query in example.lower() for example in guidance.code_examples):
                results.append(asdict(guidance))
                continue
        
        return results

    def analyze_implementation_quality(self, impl_id: str) -> Dict[str, Any]:
        """Analyze the quality of an implementation."""
        if impl_id not in self.implementations:
            raise ValueError(f"Implementation {impl_id} not found")
            
        implementation = self.implementations[impl_id]
        task = self.engineering_manager.tasks[implementation.task_id]
        
        analysis = {
            'implementation': asdict(implementation),
            'task': asdict(task),
            'metrics': {
                'files_changed': len(implementation.files_changed),
                'commits': len(implementation.commit_messages),
                'review_comments': sum(
                    1 for review in self.code_reviews.values()
                    if review.pr_number == impl_id.replace('impl_', '')
                ),
                'test_coverage': self._calculate_test_coverage(implementation)
            },
            'review_status': implementation.review_status,
            'test_status': implementation.test_status,
            'recommendations': []
        }
        
        # Analyze commit messages
        if any(len(msg) < 10 for msg in implementation.commit_messages):
            analysis['recommendations'].append(
                "Some commit messages are too short. Please provide more detailed descriptions."
            )
        
        # Check test coverage
        if analysis['metrics']['test_coverage'] < 80:
            analysis['recommendations'].append(
                f"Test coverage is {analysis['metrics']['test_coverage']}%. Please add more tests."
            )
        
        # Check review status
        if implementation.review_status == "needs_work":
            review = next(
                (r for r in self.code_reviews.values()
                 if r.pr_number == impl_id.replace('impl_', '')),
                None
            )
            if review:
                analysis['recommendations'].extend(
                    [s['suggestion'] for s in review.suggestions]
                )
        
        return analysis

    def get_implementation_status(self, impl_id: str) -> Dict[str, Any]:
        """Get detailed status of an implementation."""
        if impl_id not in self.implementations:
            raise ValueError(f"Implementation {impl_id} not found")
            
        implementation = self.implementations[impl_id]
        task = self.engineering_manager.tasks[implementation.task_id]
        
        # Get associated code reviews
        reviews = [
            review for review in self.code_reviews.values()
            if review.pr_number == impl_id.replace('impl_', '')
        ]
        
        # Get test results
        test_results = []
        for test_case in self.qa_manager.test_cases.values():
            if task.component_id == test_case.component_id:
                runs = self.qa_manager.test_runs.get(test_case.id, [])
                if runs:
                    latest_run = max(runs, key=lambda r: r.start_time)
                    test_results.append({
                        'test_case': asdict(test_case),
                        'latest_run': asdict(latest_run)
                    })
        
        return {
            'implementation': asdict(implementation),
            'task': asdict(task),
            'reviews': [asdict(review) for review in reviews],
            'test_results': test_results,
            'quality_analysis': self.analyze_implementation_quality(impl_id)
        }

    def _calculate_test_coverage(self, implementation: Implementation) -> float:
        """Calculate test coverage for an implementation."""
        # This would typically integrate with a coverage tool
        # For now, return a simple estimate based on test cases
        component_id = self.engineering_manager.tasks[implementation.task_id].component_id
        coverage = self.qa_manager.analyze_test_coverage(component_id)
        return coverage['coverage_percentage'] 