"""
Migration utilities for Socket.IO event schema migration.

WHY: This module provides utilities to help migrate from the old event
formats to the new normalized schema, ensuring backward compatibility
during the transition period.

DESIGN DECISION: Provide both transformation and validation utilities
to help identify and fix inconsistent event formats across the codebase.
"""

from datetime import datetime
from typing import Any, Dict, List, Optional, Tuple
import json

from ...core.logging_config import get_logger


class EventMigrationHelper:
    """Helper class for migrating events to the new schema.
    
    WHY: Provides utilities to identify old format events and
    transform them to the new normalized schema.
    """
    
    def __init__(self):
        self.logger = get_logger(self.__class__.__name__)
        self.migration_stats = {
            "old_format_detected": 0,
            "transformed": 0,
            "validation_failed": 0,
            "already_normalized": 0
        }
    
    def is_old_format(self, event_data: Any) -> bool:
        """Check if an event is in the old format.
        
        WHY: Need to identify which events need migration.
        """
        if not isinstance(event_data, dict):
            return True  # Non-dict events are definitely old format
        
        # Check for new format fields
        required_new_fields = {"event", "type", "subtype", "timestamp", "data"}
        has_all_new_fields = all(field in event_data for field in required_new_fields)
        
        if has_all_new_fields:
            self.migration_stats["already_normalized"] += 1
            return False
        
        # Old format indicators
        old_format_indicators = [
            # Hook format with "hook." prefix in type
            "type" in event_data and isinstance(event_data.get("type"), str) and event_data["type"].startswith("hook."),
            # Missing subtype field
            "type" in event_data and "subtype" not in event_data,
            # Event field used differently
            "event" in event_data and event_data.get("event") != "claude_event",
        ]
        
        if any(old_format_indicators):
            self.migration_stats["old_format_detected"] += 1
            return True
        
        return False
    
    def transform_to_new_format(self, event_data: Any) -> Dict[str, Any]:
        """Transform an old format event to the new schema.
        
        WHY: Provides a migration path from old to new format.
        """
        # Import here to avoid circular dependency
        from .event_normalizer import EventNormalizer
        
        normalizer = EventNormalizer()
        normalized = normalizer.normalize(event_data)
        
        self.migration_stats["transformed"] += 1
        return normalized.to_dict()
    
    def validate_event_schema(self, event_data: Dict[str, Any]) -> Tuple[bool, List[str]]:
        """Validate an event against the new schema.
        
        WHY: Ensures events conform to the expected structure
        before being sent to clients.
        
        Returns:
            Tuple of (is_valid, list_of_errors)
        """
        errors = []
        
        # Check required fields
        required_fields = {"event", "type", "subtype", "timestamp", "data"}
        missing_fields = required_fields - set(event_data.keys())
        if missing_fields:
            errors.append(f"Missing required fields: {missing_fields}")
        
        # Validate field types
        if "event" in event_data and event_data["event"] != "claude_event":
            errors.append(f"Invalid event name: {event_data['event']} (should be 'claude_event')")
        
        if "type" in event_data and not isinstance(event_data["type"], str):
            errors.append(f"Invalid type field: should be string, got {type(event_data['type'])}")
        
        if "subtype" in event_data and not isinstance(event_data["subtype"], str):
            errors.append(f"Invalid subtype field: should be string, got {type(event_data['subtype'])}")
        
        if "timestamp" in event_data:
            timestamp = event_data["timestamp"]
            if not isinstance(timestamp, str) or "T" not in timestamp:
                errors.append(f"Invalid timestamp format: {timestamp} (should be ISO format)")
        
        if "data" in event_data and not isinstance(event_data["data"], dict):
            errors.append(f"Invalid data field: should be dict, got {type(event_data['data'])}")
        
        if errors:
            self.migration_stats["validation_failed"] += 1
            return False, errors
        
        return True, []
    
    def get_migration_report(self) -> str:
        """Generate a report of migration statistics.
        
        WHY: Helps track migration progress and identify issues.
        """
        report = "Event Migration Report\n"
        report += "=" * 50 + "\n"
        report += f"Old format detected: {self.migration_stats['old_format_detected']}\n"
        report += f"Events transformed: {self.migration_stats['transformed']}\n"
        report += f"Validation failures: {self.migration_stats['validation_failed']}\n"
        report += f"Already normalized: {self.migration_stats['already_normalized']}\n"
        return report
    
    def reset_stats(self):
        """Reset migration statistics."""
        self.migration_stats = {
            "old_format_detected": 0,
            "transformed": 0,
            "validation_failed": 0,
            "already_normalized": 0
        }


class EventTypeMapper:
    """Maps old event types to new type/subtype categories.
    
    WHY: Provides a consistent mapping from legacy event names
    to the new categorized structure.
    """
    
    # Comprehensive mapping of old event formats to new categories
    TYPE_MAPPINGS = {
        # Hook events with "hook." prefix
        "hook.pre_tool": ("hook", "pre_tool"),
        "hook.post_tool": ("hook", "post_tool"),
        "hook.pre_response": ("hook", "pre_response"),
        "hook.post_response": ("hook", "post_response"),
        "hook.start": ("hook", "start"),
        "hook.stop": ("hook", "stop"),
        "hook.subagent_start": ("hook", "subagent_start"),
        "hook.subagent_stop": ("hook", "subagent_stop"),
        
        # Hook events without prefix
        "pre_tool": ("hook", "pre_tool"),
        "post_tool": ("hook", "post_tool"),
        "pre_response": ("hook", "pre_response"),
        "post_response": ("hook", "post_response"),
        
        # System events
        "system_heartbeat": ("system", "heartbeat"),
        "heartbeat": ("system", "heartbeat"),
        "system_status": ("system", "status"),
        
        # Session events
        "session_started": ("session", "started"),
        "session_ended": ("session", "ended"),
        
        # File events
        "file_changed": ("file", "changed"),
        "file_created": ("file", "created"),
        "file_deleted": ("file", "deleted"),
        
        # Connection events
        "client_connected": ("connection", "connected"),
        "client_disconnected": ("connection", "disconnected"),
        
        # Memory events
        "memory_loaded": ("memory", "loaded"),
        "memory_created": ("memory", "created"),
        "memory_updated": ("memory", "updated"),
        "memory_injected": ("memory", "injected"),
        
        # Git events
        "git_operation": ("git", "operation"),
        "git_commit": ("git", "commit"),
        "git_push": ("git", "push"),
        
        # Todo events
        "todo_updated": ("todo", "updated"),
        "todo_created": ("todo", "created"),
        
        # Ticket events
        "ticket_created": ("ticket", "created"),
        "ticket_updated": ("ticket", "updated"),
        
        # Agent events
        "agent_delegated": ("agent", "delegated"),
        "agent_completed": ("agent", "completed"),
        
        # Claude events
        "claude_status": ("claude", "status"),
        "claude_output": ("claude", "output"),
        
        # Error events
        "error": ("error", "general"),
        "error_occurred": ("error", "occurred"),
        
        # Performance events
        "performance": ("performance", "metric"),
        "performance_metric": ("performance", "metric"),
    }
    
    @classmethod
    def map_event_type(cls, old_type: str) -> Tuple[str, str]:
        """Map an old event type to new type/subtype.
        
        WHY: Provides consistent categorization for all events.
        
        Args:
            old_type: The old event type string
            
        Returns:
            Tuple of (type, subtype)
        """
        # Direct mapping
        if old_type in cls.TYPE_MAPPINGS:
            return cls.TYPE_MAPPINGS[old_type]
        
        # Try to infer from patterns
        old_lower = old_type.lower()
        
        # Hook events
        if "hook" in old_lower or old_lower.startswith("pre_") or old_lower.startswith("post_"):
            # Remove "hook." prefix if present
            clean_type = old_type.replace("hook.", "")
            return "hook", clean_type
        
        # System events
        if "system" in old_lower or "heartbeat" in old_lower:
            return "system", old_type.replace("system_", "")
        
        # Session events
        if "session" in old_lower:
            if "start" in old_lower:
                return "session", "started"
            elif "end" in old_lower:
                return "session", "ended"
            return "session", "generic"
        
        # File events
        if "file" in old_lower:
            if "create" in old_lower:
                return "file", "created"
            elif "delete" in old_lower:
                return "file", "deleted"
            elif "change" in old_lower or "modify" in old_lower:
                return "file", "changed"
            return "file", "generic"
        
        # Default mapping
        return "unknown", old_type
    
    @classmethod
    def get_event_category(cls, event_type: str, event_subtype: str) -> str:
        """Get a human-readable category for an event.
        
        WHY: Helps with filtering and display in UIs.
        """
        categories = {
            "hook": "Claude Hooks",
            "system": "System Status",
            "session": "Session Management",
            "file": "File Operations",
            "connection": "Client Connections",
            "memory": "Memory System",
            "git": "Git Operations",
            "todo": "Todo Management",
            "ticket": "Ticket System",
            "agent": "Agent Delegation",
            "claude": "Claude Process",
            "error": "Errors",
            "performance": "Performance Metrics",
            "unknown": "Uncategorized"
        }
        return categories.get(event_type, "Other")


def create_backward_compatible_event(normalized_event: Dict[str, Any]) -> Dict[str, Any]:
    """Create a backward-compatible version of a normalized event.
    
    WHY: During migration, some clients may still expect the old format.
    This creates an event that works with both old and new clients.
    
    Args:
        normalized_event: Event in the new normalized format
        
    Returns:
        Event that includes both old and new format fields
    """
    # Start with the normalized event
    compat_event = normalized_event.copy()
    
    # Add old format fields based on type/subtype
    event_type = normalized_event.get("type", "")
    event_subtype = normalized_event.get("subtype", "")
    
    # For hook events, add the old "hook." prefix format
    if event_type == "hook":
        compat_event["type_legacy"] = f"hook.{event_subtype}"
    
    # For other events, use the old naming convention
    elif event_type in ["session", "file", "memory", "git", "todo", "ticket", "agent", "claude"]:
        compat_event["type_legacy"] = f"{event_type}_{event_subtype}"
    
    # Add event_type field for really old clients
    compat_event["event_type"] = compat_event.get("type_legacy", f"{event_type}_{event_subtype}")
    
    return compat_event