"""Product Manager for handling product vision, requirements, and user needs."""
import json
from datetime import datetime
from typing import Dict, List, Optional, Any
from dataclasses import dataclass, asdict
import logging

logger = logging.getLogger(__name__)

@dataclass
class UserStory:
    """Represents a user story with acceptance criteria."""
    id: str
    title: str
    description: str
    user_type: str
    acceptance_criteria: List[str]
    priority: int
    status: str
    created_at: str
    updated_at: str
    completed_at: Optional[str] = None

@dataclass
class Feature:
    """Represents a product feature with requirements."""
    id: str
    title: str
    description: str
    user_stories: List[str]  # References to UserStory IDs
    requirements: List[str]
    priority: int
    status: str
    created_at: str
    updated_at: str
    completed_at: Optional[str] = None

@dataclass
class ProductRequirement:
    """Represents a detailed product requirement."""
    id: str
    title: str
    description: str
    feature_id: str
    type: str  # 'functional', 'non-functional', 'technical'
    priority: int
    status: str
    dependencies: List[str]
    created_at: str
    updated_at: str

class ProductManager:
    """Manages product vision, requirements, and user needs."""
    
    def __init__(self, context_manager, intelligence_manager):
        """Initialize the Product Manager."""
        self.context_manager = context_manager
        self.intelligence_manager = intelligence_manager
        self.user_stories: Dict[str, UserStory] = {}
        self.features: Dict[str, Feature] = {}
        self.requirements: Dict[str, ProductRequirement] = {}
        self.load_product_data()

    def load_product_data(self):
        """Load product data from context database."""
        context = self.context_manager.get_project_context()
        product_data = context.get('product_data', {})
        
        # Load user stories
        for story_dict in product_data.get('user_stories', []):
            story = UserStory(**story_dict)
            self.user_stories[story.id] = story
            
        # Load features
        for feature_dict in product_data.get('features', []):
            feature = Feature(**feature_dict)
            self.features[feature.id] = feature
            
        # Load requirements
        for req_dict in product_data.get('requirements', []):
            requirement = ProductRequirement(**req_dict)
            self.requirements[requirement.id] = requirement

    def save_product_data(self):
        """Save product data to context database."""
        product_data = {
            'user_stories': [asdict(story) for story in self.user_stories.values()],
            'features': [asdict(feature) for feature in self.features.values()],
            'requirements': [asdict(req) for req in self.requirements.values()]
        }
        
        self.context_manager.update_project_context({
            'product_data': product_data
        })

    def add_user_story(self, title: str, description: str, user_type: str,
                      acceptance_criteria: List[str], priority: int = 1) -> UserStory:
        """Add a new user story."""
        story_id = f"story_{len(self.user_stories) + 1}"
        now = datetime.now().isoformat()
        
        story = UserStory(
            id=story_id,
            title=title,
            description=description,
            user_type=user_type,
            acceptance_criteria=acceptance_criteria,
            priority=priority,
            status="draft",
            created_at=now,
            updated_at=now
        )
        
        self.user_stories[story_id] = story
        self.save_product_data()
        
        # Add insight about new user story
        self.context_manager.add_insight(
            f"New user story added: {title}",
            'product_management',
            'product_manager'
        )
        
        return story

    def add_feature(self, title: str, description: str, requirements: List[str],
                   user_stories: List[str], priority: int = 1) -> Feature:
        """Add a new product feature."""
        feature_id = f"feature_{len(self.features) + 1}"
        now = datetime.now().isoformat()
        
        feature = Feature(
            id=feature_id,
            title=title,
            description=description,
            user_stories=user_stories,
            requirements=requirements,
            priority=priority,
            status="draft",
            created_at=now,
            updated_at=now
        )
        
        self.features[feature_id] = feature
        self.save_product_data()
        
        # Add insight about new feature
        self.context_manager.add_insight(
            f"New feature added: {title}",
            'product_management',
            'product_manager'
        )
        
        return feature

    def add_requirement(self, title: str, description: str, feature_id: str,
                       req_type: str, priority: int = 1,
                       dependencies: List[str] = None) -> ProductRequirement:
        """Add a new product requirement."""
        req_id = f"req_{len(self.requirements) + 1}"
        now = datetime.now().isoformat()
        
        requirement = ProductRequirement(
            id=req_id,
            title=title,
            description=description,
            feature_id=feature_id,
            type=req_type,
            priority=priority,
            status="draft",
            dependencies=dependencies or [],
            created_at=now,
            updated_at=now
        )
        
        self.requirements[req_id] = requirement
        self.save_product_data()
        
        # Add insight about new requirement
        self.context_manager.add_insight(
            f"New requirement added: {title}",
            'product_management',
            'product_manager'
        )
        
        return requirement

    def update_user_story(self, story_id: str, updates: Dict[str, Any]) -> UserStory:
        """Update an existing user story."""
        if story_id not in self.user_stories:
            raise ValueError(f"User story {story_id} not found")
            
        story = self.user_stories[story_id]
        story_dict = asdict(story)
        
        for key, value in updates.items():
            if key in story_dict:
                story_dict[key] = value
        
        story_dict['updated_at'] = datetime.now().isoformat()
        self.user_stories[story_id] = UserStory(**story_dict)
        self.save_product_data()
        
        return self.user_stories[story_id]

    def update_feature(self, feature_id: str, updates: Dict[str, Any]) -> Feature:
        """Update an existing feature."""
        if feature_id not in self.features:
            raise ValueError(f"Feature {feature_id} not found")
            
        feature = self.features[feature_id]
        feature_dict = asdict(feature)
        
        for key, value in updates.items():
            if key in feature_dict:
                feature_dict[key] = value
        
        feature_dict['updated_at'] = datetime.now().isoformat()
        self.features[feature_id] = Feature(**feature_dict)
        self.save_product_data()
        
        return self.features[feature_id]

    def update_requirement(self, req_id: str, updates: Dict[str, Any]) -> ProductRequirement:
        """Update an existing requirement."""
        if req_id not in self.requirements:
            raise ValueError(f"Requirement {req_id} not found")
            
        requirement = self.requirements[req_id]
        req_dict = asdict(requirement)
        
        for key, value in updates.items():
            if key in req_dict:
                req_dict[key] = value
        
        req_dict['updated_at'] = datetime.now().isoformat()
        self.requirements[req_id] = ProductRequirement(**req_dict)
        self.save_product_data()
        
        return self.requirements[req_id]

    def get_product_roadmap(self) -> Dict[str, Any]:
        """Get the current product roadmap."""
        return {
            'user_stories': [asdict(story) for story in self.user_stories.values()],
            'features': [asdict(feature) for feature in self.features.values()],
            'requirements': [asdict(req) for req in self.requirements.values()]
        }

    def get_feature_dependencies(self, feature_id: str) -> Dict[str, List[str]]:
        """Get all dependencies for a feature."""
        if feature_id not in self.features:
            raise ValueError(f"Feature {feature_id} not found")
            
        feature = self.features[feature_id]
        dependencies = {
            'user_stories': feature.user_stories,
            'requirements': [
                req.id for req in self.requirements.values()
                if req.feature_id == feature_id
            ],
            'dependent_features': [
                f.id for f in self.features.values()
                if feature_id in f.dependencies
            ]
        }
        
        return dependencies

    def analyze_impact(self, feature_id: str) -> Dict[str, Any]:
        """Analyze the impact of implementing a feature."""
        if feature_id not in self.features:
            raise ValueError(f"Feature {feature_id} not found")
            
        feature = self.features[feature_id]
        dependencies = self.get_feature_dependencies(feature_id)
        
        # Get requirements complexity
        requirements = [
            req for req in self.requirements.values()
            if req.feature_id == feature_id
        ]
        
        complexity_score = sum(req.priority for req in requirements)
        
        return {
            'feature': asdict(feature),
            'dependencies': dependencies,
            'complexity_score': complexity_score,
            'affected_user_stories': len(feature.user_stories),
            'total_requirements': len(requirements)
        }

    def prioritize_backlog(self) -> List[Dict[str, Any]]:
        """Prioritize the product backlog."""
        # Convert features to list and sort by priority
        prioritized = [
            {
                'item_type': 'feature',
                'item': asdict(feature),
                'impact': self.analyze_impact(feature.id)
            }
            for feature in sorted(
                self.features.values(),
                key=lambda x: (x.priority, len(x.user_stories)),
                reverse=True
            )
        ]
        
        return prioritized

    def validate_requirements(self) -> Dict[str, List[str]]:
        """Validate all requirements for completeness and consistency."""
        validation_results = {
            'missing_dependencies': [],
            'circular_dependencies': [],
            'incomplete_requirements': [],
            'orphaned_stories': []
        }
        
        # Check for missing dependencies
        for req in self.requirements.values():
            for dep_id in req.dependencies:
                if dep_id not in self.requirements:
                    validation_results['missing_dependencies'].append(
                        f"Requirement {req.id} depends on non-existent requirement {dep_id}"
                    )
        
        # Check for circular dependencies
        for req in self.requirements.values():
            if self._has_circular_dependency(req.id, set()):
                validation_results['circular_dependencies'].append(
                    f"Requirement {req.id} has circular dependencies"
                )
        
        # Check for incomplete requirements
        for req in self.requirements.values():
            if not req.description or not req.title:
                validation_results['incomplete_requirements'].append(
                    f"Requirement {req.id} is incomplete"
                )
        
        # Check for orphaned user stories
        for story in self.user_stories.values():
            if not any(story.id in f.user_stories for f in self.features.values()):
                validation_results['orphaned_stories'].append(
                    f"User story {story.id} is not linked to any feature"
                )
        
        return validation_results

    def _has_circular_dependency(self, req_id: str, visited: set) -> bool:
        """Check for circular dependencies recursively."""
        if req_id in visited:
            return True
            
        visited.add(req_id)
        requirement = self.requirements.get(req_id)
        
        if requirement:
            for dep_id in requirement.dependencies:
                if self._has_circular_dependency(dep_id, visited.copy()):
                    return True
        
        return False 