from typing import List, Optional
from datetime import datetime

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


def get_rule(rule_id: str) -> Optional[RuleRecord]:
    """
    Get a specific rule by ID.
    
    Args:
        rule_id: The ID of the rule to retrieve
        
    Returns:
        RuleRecord if found, None otherwise
    """
    db_manager = get_db_manager()
    
    with db_manager.get_session() as session:
        return session.query(RuleRecord).filter(
            RuleRecord.id == rule_id
        ).first()


def list_rules(
    active_only: bool = True,
    include_archived: bool = False,
    limit: int = 100
) -> List[RuleRecord]:
    """
    List redaction rules with filtering options.
    
    Args:
        active_only: Only return active rules (default: True)
        include_archived: Include archived rules (default: False)
        limit: Maximum number of rules to return
        
    Returns:
        List of RuleRecord objects
    """
    db_manager = get_db_manager()
    
    with db_manager.get_session() as session:
        query = session.query(RuleRecord)
        
        if active_only:
            query = query.filter(RuleRecord.is_active is True)
        
        if not include_archived:
            query = query.filter(RuleRecord.is_archived is False)
        
        return query.order_by(RuleRecord.created_at.desc()).limit(limit).all()


def insert_rule(name: str, description: str, data_type: str) -> RuleRecord:
    """
    Insert a new redaction rule.
    
    Args:
        name: Name/description of what the rule does
        description: Detailed description of the rule
        data_type: Type of data this rule targets (e.g., EMAIL, PHONE, etc.)
        
    Returns:
        The created RuleRecord
    """
    import hashlib
    
    db_manager = get_db_manager()
    
    # Generate hash ID from rule content with prefix
    rule_content = f"{name}|{description}|{data_type}"
    rule_hash = hashlib.sha256(rule_content.encode()).hexdigest()
    rule_id = f"rule_{rule_hash[:8]}"  # Use first 8 chars with prefix
    
    with db_manager.get_session() as session:
        # Check if rule with this ID already exists
        existing_rule = session.query(RuleRecord).filter(
            RuleRecord.id == rule_id
        ).first()
        
        if existing_rule:
            raise ValueError(
                f"Rule with similar content already exists (ID: {rule_id})"
            )
        
        rule = RuleRecord(
            id=rule_id,
            name=name,
            description=description,
            data_type=data_type,
            is_active=True,
            is_archived=False
        )
        
        session.add(rule)
        session.commit()
        session.refresh(rule)
        return rule


def update_rule(
    rule_id: str,
    name: Optional[str] = None,
    description: Optional[str] = None,
    is_active: Optional[bool] = None
) -> Optional[RuleRecord]:
    """
    Update an existing rule.
    
    Args:
        rule_id: ID of the rule to update
        name: New name for the rule (optional)
        description: New description for the rule (optional)  
        is_active: New active status for the rule (optional)
        
    Returns:
        Updated RuleRecord if found, None otherwise
    """
    db_manager = get_db_manager()
    
    with db_manager.get_session() as session:
        rule = session.query(RuleRecord).filter(
            RuleRecord.id == rule_id
        ).first()
        
        if not rule:
            return None
        
        # Update fields if provided
        if name is not None:
            rule.name = name
        if description is not None:
            rule.description = description
        if is_active is not None:
            rule.is_active = is_active
            
        # Always update the updated_at timestamp
        rule.updated_at = datetime.now()
        
        session.commit()
        session.refresh(rule)
        return rule


def archive_rule(rule_id: str) -> Optional[RuleRecord]:
    """
    Archive a rule (sets is_archived=True, is_active=False).
    
    Args:
        rule_id: ID of the rule to archive
        
    Returns:
        Archived RuleRecord if found, None otherwise
    """
    db_manager = get_db_manager()
    
    with db_manager.get_session() as session:
        rule = session.query(RuleRecord).filter(
            RuleRecord.id == rule_id
        ).first()
        
        if not rule:
            return None
        
        rule.is_archived = True
        rule.is_active = False
        rule.updated_at = datetime.now()
        
        session.commit()
        session.refresh(rule)
        return rule 