from typing import List, Optional
import hashlib

from llm_redact.db.database import get_db_manager
from llm_redact.db.models import RuleGroup, RuleRecord


def get_rule_group(group_id: str) -> Optional[RuleGroup]:
    """
    Get a specific rule group by ID.
    
    Args:
        group_id: Rule group ID
        
    Returns:
        RuleGroup object or None if not found
    """
    db_manager = get_db_manager()
    
    with db_manager.get_session() as session:
        return session.query(RuleGroup).filter(
            RuleGroup.id == group_id
        ).first()


def list_rule_groups(
    active_only: bool = True,
    limit: int = 100
) -> List[RuleGroup]:
    """
    List rule groups with filtering options.
    
    Args:
        active_only: Only return active rule groups (default: True)
        limit: Maximum number of rule groups to return
        
    Returns:
        List of RuleGroup objects
    """
    db_manager = get_db_manager()
    
    with db_manager.get_session() as session:
        query = session.query(RuleGroup)
        
        if active_only:
            query = query.filter(RuleGroup.is_active)
        
        return query.order_by(RuleGroup.created_at.desc()).limit(limit).all()


def create_rule_group(
    name: str, 
    description: str, 
    rule_ids: List[str]
) -> RuleGroup:
    """
    Create a new rule group with existing rules.
    
    Args:
        name: Name of the rule group
        description: Description of the rule group
        rule_ids: List of existing rule IDs to add to the group
        
    Returns:
        The created RuleGroup
    """
    db_manager = get_db_manager()
    
    # Generate hash ID from group content with prefix
    group_content = f"{name}|{description}|{len(rule_ids)}"
    group_hash = hashlib.sha256(group_content.encode()).hexdigest()
    group_id = f"group_{group_hash[:8]}"
    
    with db_manager.get_session() as session:
        # Check if group with this ID already exists
        existing_group = session.query(RuleGroup).filter(
            RuleGroup.id == group_id
        ).first()
        
        if existing_group:
            raise ValueError(
                f"Rule group already exists (ID: {group_id})"
            )
        
        # Verify all rule IDs exist
        existing_rules = session.query(RuleRecord).filter(
            RuleRecord.id.in_(rule_ids)
        ).all()
        
        if len(existing_rules) != len(rule_ids):
            found_ids = {rule.id for rule in existing_rules}
            missing_ids = set(rule_ids) - found_ids
            raise ValueError(f"Rules not found: {missing_ids}")
        
        # Create the rule group with JSON rule_ids
        rule_group = RuleGroup(
            id=group_id,
            name=name,
            description=description,
            rule_ids=rule_ids,  # Store as JSON list
            is_active=True
        )
        
        session.add(rule_group)
        session.commit()
        session.refresh(rule_group)
        return rule_group


def add_rules_to_group(group_id: str, rule_ids: List[str]) -> bool:
    """
    Add rules to an existing rule group.
    
    Args:
        group_id: Rule group ID
        rule_ids: List of rule IDs to add
        
    Returns:
        True if successful, False if group not found
    """
    db_manager = get_db_manager()
    
    with db_manager.get_session() as session:
        group = session.query(RuleGroup).filter(
            RuleGroup.id == group_id
        ).first()
        
        if not group:
            return False
        
        # Get current rule IDs and add new ones
        current_rule_ids = group.rule_ids or []
        # Remove duplicates by converting to set and back to list
        new_rule_ids = list(set(current_rule_ids + rule_ids))
        
        group.rule_ids = new_rule_ids
        session.commit()
        return True


def remove_rules_from_group(group_id: str, rule_ids: List[str]) -> bool:
    """
    Remove rules from a rule group.
    
    Args:
        group_id: Rule group ID
        rule_ids: List of rule IDs to remove
        
    Returns:
        True if successful, False if group not found
    """
    db_manager = get_db_manager()
    
    with db_manager.get_session() as session:
        group = session.query(RuleGroup).filter(
            RuleGroup.id == group_id
        ).first()
        
        if not group:
            return False
        
        # Remove specified rule IDs
        current_rule_ids = group.rule_ids or []
        new_rule_ids = [rid for rid in current_rule_ids if rid not in rule_ids]
        
        group.rule_ids = new_rule_ids
        session.commit()
        return True


def get_rules_in_group(group_id: str) -> List[RuleRecord]:
    """
    Get all rules in a rule group.
    
    Args:
        group_id: Rule group ID
        
    Returns:
        List of RuleRecord objects
    """
    db_manager = get_db_manager()
    
    with db_manager.get_session() as session:
        group = session.query(RuleGroup).filter(
            RuleGroup.id == group_id
        ).first()
        
        if not group or not group.rule_ids:
            return []
        
        # Get rules by IDs
        return session.query(RuleRecord).filter(
            RuleRecord.id.in_(group.rule_ids)
        ).all()


def delete_rule_group(group_id: str) -> bool:
    """
    Delete a rule group.
    
    Args:
        group_id: Rule group ID to delete
        
    Returns:
        True if deleted, False if not found
    """
    db_manager = get_db_manager()
    
    with db_manager.get_session() as session:
        rule_group = session.query(RuleGroup).filter(
            RuleGroup.id == group_id
        ).first()
        
        if not rule_group:
            return False
        
        session.delete(rule_group)
        session.commit()
        return True 