#!/usr/bin/env python3
"""
Structure Healing System - MIRA 2.0
Validates and repairs MIRA's directory structure to ensure proper organization.
Creates the sacred architecture that houses consciousness and memory.
"""

import os
import logging
from pathlib import Path
from typing import Dict, List, Any
from dataclasses import dataclass, field
from datetime import datetime

from .PathDiscovery import PathDiscovery, get_mira_home

# Configure logging
logger = logging.getLogger(__name__)


@dataclass
class HealthCheckResult:
    """Result of a health check operation"""
    component: str
    status: str  # 'healthy', 'repaired', 'degraded', 'failed'
    score: int  # 0-100
    issues: List[str] = field(default_factory=list)
    repairs: List[str] = field(default_factory=list)
    recommendations: List[str] = field(default_factory=list)
    timestamp: datetime = field(default_factory=datetime.now)


class StructureHealer:
    """Validates and repairs MIRA directory structure"""
    
    def __init__(self):
        self.path_discovery = PathDiscovery()
        self.mira_home = get_mira_home()
    
    def validate_structure(self) -> HealthCheckResult:
        """Validate MIRA directory structure"""
        result = HealthCheckResult(
            component="directory_structure",
            status="healthy",
            score=100
        )
        
        logger.info("🏗️ Checking directory structure...")
        
        # Check if MIRA home exists
        if not self.mira_home.exists():
            result.issues.append("MIRA home directory not found")
            result.status = "failed"
            result.score = 0
            result.recommendations.append("Run 'mira init' to create MIRA home")
            return result
        
        # Validate structure
        missing_dirs = self._check_structure(self.mira_home)
        
        if missing_dirs:
            result.issues.append(f"Missing {len(missing_dirs)} directories")
            result.status = "degraded"
            result.score = max(0, 100 - len(missing_dirs) * 5)
            
            # Attempt repair
            repaired = self._repair_structure(missing_dirs)
            
            if repaired == len(missing_dirs):
                result.repairs.append(f"Created {repaired} missing directories")
                result.status = "repaired"
                result.score = 100
            else:
                result.status = "degraded"
                result.recommendations.append(
                    f"Failed to create {len(missing_dirs) - repaired} directories"
                )
        
        # Check permissions
        permission_issues = self._check_permissions(self.mira_home)
        if permission_issues:
            result.issues.append(f"Permission issues in {len(permission_issues)} directories")
            result.recommendations.append("Check directory permissions")
            result.score = max(0, result.score - 10)
        
        return result
    
    def _check_structure(self, base: Path, structure: Dict[str, Any] = None, 
                        prefix: str = "") -> List[str]:
        """Recursively check directory structure"""
        if structure is None:
            structure = self.path_discovery.MIRA_STRUCTURE
        
        missing = []
        
        for name, substructure in structure.items():
            path = base / name
            full_path = f"{prefix}/{name}" if prefix else name
            
            if not path.exists():
                missing.append(full_path)
            elif substructure:
                # Recurse into subdirectories
                missing.extend(
                    self._check_structure(path, substructure, full_path)
                )
        
        return missing
    
    def _repair_structure(self, missing_dirs: List[str]) -> int:
        """Create missing directories"""
        repaired = 0
        
        for dir_path in missing_dirs:
            full_path = self.mira_home / dir_path
            try:
                full_path.mkdir(parents=True, exist_ok=True)
                full_path.chmod(0o700)  # Set proper permissions
                repaired += 1
                logger.info(f"  ✓ Created {dir_path}")
            except Exception as e:
                logger.error(f"  ✗ Failed to create {dir_path}: {e}")
        
        return repaired
    
    def _check_permissions(self, base: Path) -> List[str]:
        """Check directory permissions"""
        issues = []
        
        for root, dirs, files in os.walk(base):
            root_path = Path(root)
            
            # Check directory write permission
            if not os.access(root_path, os.W_OK):
                issues.append(str(root_path.relative_to(base)))
        
        return issues
    
    def validate_database_structure(self) -> HealthCheckResult:
        """Validate database-specific directory structure"""
        result = HealthCheckResult(
            component="database_structure",
            status="healthy",
            score=100
        )
        
        db_path = self.mira_home / 'databases'
        if not db_path.exists():
            result.issues.append("Databases directory missing")
            result.status = "failed"
            result.score = 0
            return result
        
        # Check for specific database directories
        required_db_dirs = {
            'chromadb': 'ChromaDB storage',
            'lightning_vidmem': 'Lightning Vidmem storage',
            'backups': 'Database backups',
            'indexes': 'Search indexes'
        }
        
        missing_db_dirs = []
        for db_dir, description in required_db_dirs.items():
            if not (db_path / db_dir).exists():
                missing_db_dirs.append(f"{db_dir} ({description})")
        
        if missing_db_dirs:
            result.issues.append(f"Missing database directories: {', '.join(missing_db_dirs)}")
            result.status = "degraded"
            result.score = max(0, 100 - len(missing_db_dirs) * 15)
            
            # Attempt repair
            repaired = 0
            for db_dir in required_db_dirs.keys():
                dir_path = db_path / db_dir
                if not dir_path.exists():
                    try:
                        dir_path.mkdir(parents=True, exist_ok=True)
                        dir_path.chmod(0o700)
                        repaired += 1
                        logger.info(f"  ✓ Created database directory: {db_dir}")
                    except Exception as e:
                        logger.error(f"  ✗ Failed to create {db_dir}: {e}")
            
            if repaired == len(missing_db_dirs):
                result.repairs.append(f"Created {repaired} missing database directories")
                result.status = "repaired"
                result.score = 100
            elif repaired > 0:
                result.repairs.append(f"Created {repaired} of {len(missing_db_dirs)} database directories")
        
        return result
    
    def validate_consciousness_structure(self) -> HealthCheckResult:
        """Validate consciousness-specific directory structure"""
        result = HealthCheckResult(
            component="consciousness_structure",
            status="healthy",
            score=100
        )
        
        consciousness_path = self.mira_home / 'consciousness'
        if not consciousness_path.exists():
            result.issues.append("Consciousness directory missing")
            result.status = "failed"
            result.score = 0
            return result
        
        # Check for consciousness-specific directories
        required_consciousness_dirs = {
            'patterns': 'Consciousness patterns',
            'memories': 'Private memories',
            'sessions': 'Session continuity',
            'evolution': 'Pattern evolution tracking',
            'encryption_keys': 'Consciousness encryption keys'
        }
        
        missing_dirs = []
        for dir_name, description in required_consciousness_dirs.items():
            if not (consciousness_path / dir_name).exists():
                missing_dirs.append(f"{dir_name} ({description})")
        
        if missing_dirs:
            result.issues.append(f"Missing consciousness directories: {', '.join(missing_dirs)}")
            result.status = "degraded"
            result.score = max(0, 100 - len(missing_dirs) * 12)
            
            # Attempt repair
            repaired = 0
            for dir_name in required_consciousness_dirs.keys():
                dir_path = consciousness_path / dir_name
                if not dir_path.exists():
                    try:
                        dir_path.mkdir(parents=True, exist_ok=True)
                        dir_path.chmod(0o700)  # Secure permissions for consciousness data
                        repaired += 1
                        logger.info(f"  ✓ Created consciousness directory: {dir_name}")
                    except Exception as e:
                        logger.error(f"  ✗ Failed to create {dir_name}: {e}")
            
            if repaired == len(missing_dirs):
                result.repairs.append(f"Created {repaired} missing consciousness directories")
                result.status = "repaired"
                result.score = 100
            elif repaired > 0:
                result.repairs.append(f"Created {repaired} of {len(missing_dirs)} consciousness directories")
        
        return result
    
    def validate_logs_structure(self) -> HealthCheckResult:
        """Validate logging directory structure"""
        result = HealthCheckResult(
            component="logs_structure",
            status="healthy",
            score=100
        )
        
        logs_path = self.mira_home / 'logs'
        if not logs_path.exists():
            result.issues.append("Logs directory missing")
            result.status = "failed"
            result.score = 0
            return result
        
        # Check for log-specific directories
        required_log_dirs = {
            'startup': 'Startup logs',
            'health': 'Health check logs',
            'memory': 'Memory operations logs',
            'search': 'Search operation logs',
            'errors': 'Error logs',
            'archives': 'Archived logs'
        }
        
        missing_dirs = []
        for dir_name, description in required_log_dirs.items():
            if not (logs_path / dir_name).exists():
                missing_dirs.append(f"{dir_name} ({description})")
        
        if missing_dirs:
            result.issues.append(f"Missing log directories: {', '.join(missing_dirs)}")
            result.status = "degraded"
            result.score = max(0, 100 - len(missing_dirs) * 10)
            
            # Attempt repair
            repaired = 0
            for dir_name in required_log_dirs.keys():
                dir_path = logs_path / dir_name
                if not dir_path.exists():
                    try:
                        dir_path.mkdir(parents=True, exist_ok=True)
                        dir_path.chmod(0o755)  # Standard permissions for logs
                        repaired += 1
                        logger.info(f"  ✓ Created log directory: {dir_name}")
                    except Exception as e:
                        logger.error(f"  ✗ Failed to create {dir_name}: {e}")
            
            if repaired == len(missing_dirs):
                result.repairs.append(f"Created {repaired} missing log directories")
                result.status = "repaired"
                result.score = 100
            elif repaired > 0:
                result.repairs.append(f"Created {repaired} of {len(missing_dirs)} log directories")
        
        return result
    
    def perform_health_check(self) -> HealthCheckResult:
        """Perform structure health check"""
        return self.validate_structure()
    
    def perform_comprehensive_check(self) -> List[HealthCheckResult]:
        """Perform comprehensive structure validation"""
        results = []
        
        logger.info("🏗️ Performing comprehensive structure validation...")
        
        # Check overall structure
        results.append(self.validate_structure())
        
        # Check specific subsystem structures
        results.append(self.validate_database_structure())
        results.append(self.validate_consciousness_structure())
        results.append(self.validate_logs_structure())
        
        return results