"""Utility functions for speaker profile operations."""

import json
import logging
from pathlib import Path
from typing import Dict, List

from .diarization_types import SpeakerProfile, ProfileMatch
from .diarization_utils import find_similar_speakers, validate_speaker_profile

logger = logging.getLogger(__name__)


def load_existing_profiles(storage_dir: Path, profiles: Dict[str, SpeakerProfile], embeddings_cache: Dict[str, any]):
    """Load existing profiles from storage directory."""
    try:
        profile_files = list(storage_dir.glob("*.json"))
        
        for profile_file in profile_files:
            try:
                from .diarization_utils import load_profile_from_disk
                profile = load_profile_from_disk(profile_file)
                profiles[profile.speaker_id] = profile
                
                # Cache embedding for faster similarity search
                if profile.embedding is not None:
                    embeddings_cache[profile.speaker_id] = profile.embedding
                
            except Exception as e:
                logger.warning(f"Failed to load profile from {profile_file}: {e}")
        
        logger.info(f"Loaded {len(profiles)} existing speaker profiles")
        
    except Exception as e:
        logger.error(f"Failed to load existing profiles: {e}")


def add_speaker_profile(
    speaker_id: str,
    embedding: any,
    profiles: Dict[str, SpeakerProfile],
    embeddings_cache: Dict[str, any],
    storage_dir: Path,
    max_profiles: int,
    **kwargs
) -> SpeakerProfile:
    """Add a new speaker profile with validation and cleanup."""
    validate_speaker_profile(speaker_id, embedding)
    
    # Check if profile already exists
    if speaker_id in profiles:
        logger.warning(f"Speaker profile {speaker_id} already exists, updating instead")
        return update_speaker_profile(speaker_id, embedding, profiles, embeddings_cache, storage_dir, **kwargs)
    
    # Check memory limits
    if len(profiles) >= max_profiles:
        cleanup_old_profiles(profiles, embeddings_cache, storage_dir, max_profiles)
    
    # Create new profile
    profile = SpeakerProfile(speaker_id=speaker_id, embedding=embedding, **kwargs)
    
    # Store profile
    profiles[speaker_id] = profile
    embeddings_cache[speaker_id] = embedding
    
    # Save to disk
    from .diarization_utils import save_profile_to_disk
    save_profile_to_disk(profile, storage_dir)
    
    logger.info(f"Added speaker profile: {speaker_id}")
    return profile


def update_speaker_profile(
    speaker_id: str,
    embedding: any,
    profiles: Dict[str, SpeakerProfile],
    embeddings_cache: Dict[str, any],
    storage_dir: Path,
    **kwargs
) -> SpeakerProfile:
    """Update an existing speaker profile."""
    if speaker_id not in profiles:
        from .diarization_types import ProfileNotFoundError
        raise ProfileNotFoundError(f"Speaker profile {speaker_id} not found")
    
    profile = profiles[speaker_id]
    
    # Update profile fields
    profile.embedding = embedding
    from datetime import datetime, timezone
    profile.updated_at = datetime.now(timezone.utc)
    
    # Update additional fields
    for key, value in kwargs.items():
        if hasattr(profile, key):
            setattr(profile, key, value)
    
    # Update cache
    embeddings_cache[speaker_id] = embedding
    
    # Save to disk
    from .diarization_utils import save_profile_to_disk
    save_profile_to_disk(profile, storage_dir)
    
    logger.info(f"Updated speaker profile: {speaker_id}")
    return profile


def remove_speaker_profile(
    speaker_id: str,
    profiles: Dict[str, SpeakerProfile],
    embeddings_cache: Dict[str, any],
    storage_dir: Path
) -> bool:
    """Remove a speaker profile."""
    if speaker_id not in profiles:
        return False
    
    # Remove from memory
    del profiles[speaker_id]
    if speaker_id in embeddings_cache:
        del embeddings_cache[speaker_id]
    
    # Remove from disk
    profile_file = storage_dir / f"{speaker_id}.json"
    if profile_file.exists():
        profile_file.unlink()
    
    logger.info(f"Removed speaker profile: {speaker_id}")
    return True


def cleanup_old_profiles(
    profiles: Dict[str, SpeakerProfile],
    embeddings_cache: Dict[str, any],
    storage_dir: Path,
    max_profiles: int
):
    """Remove old profiles to free memory."""
    if len(profiles) < max_profiles:
        return
    
    # Sort profiles by last update time (oldest first)
    sorted_profiles = sorted(
        profiles.items(),
        key=lambda x: x[1].updated_at
    )
    
    # Remove oldest 10% of profiles
    remove_count = max(1, len(sorted_profiles) // 10)
    
    for speaker_id, _ in sorted_profiles[:remove_count]:
        remove_speaker_profile(speaker_id, profiles, embeddings_cache, storage_dir)
    
    logger.info(f"Cleaned up {remove_count} old speaker profiles")


def save_all_profiles(
    profiles: Dict[str, SpeakerProfile],
    file_path: Path
) -> bool:
    """Save all profiles to a single file."""
    try:
        # Save all profiles to a single file
        profiles_data = {
            speaker_id: profile.to_dict()
            for speaker_id, profile in profiles.items()
        }
        
        with open(file_path, 'w') as f:
            json.dump(profiles_data, f, indent=2)
        
        logger.info(f"Saved {len(profiles)} profiles to {file_path}")
        return True
        
    except Exception as e:
        logger.error(f"Failed to save profiles: {e}")
        return False


def load_all_profiles(
    file_path: Path,
    profiles: Dict[str, SpeakerProfile],
    embeddings_cache: Dict[str, any]
) -> bool:
    """Load all profiles from a single file."""
    try:
        if not file_path.exists():
            logger.warning(f"Profile file not found: {file_path}")
            return False
        
        with open(file_path, 'r') as f:
            profiles_data = json.load(f)
        
        # Clear existing profiles
        profiles.clear()
        embeddings_cache.clear()
        
        # Load profiles
        for speaker_id, data in profiles_data.items():
            profile = SpeakerProfile.from_dict(data)
            profiles[speaker_id] = profile
            
            if profile.embedding is not None:
                embeddings_cache[speaker_id] = profile.embedding
        
        logger.info(f"Loaded {len(profiles)} profiles from {file_path}")
        return True
        
    except Exception as e:
        logger.error(f"Failed to load profiles: {e}")
        return False


def get_profile_statistics(profiles: Dict[str, SpeakerProfile]) -> Dict[str, any]:
    """Get statistics about stored profiles."""
    if not profiles:
        return {
            "total_profiles": 0,
            "profiles_with_embeddings": 0,
            "oldest_profile": None,
            "newest_profile": None
        }
    
    profiles_with_embeddings = sum(
        1 for profile in profiles.values()
        if profile.embedding is not None
    )
    
    dates = [profile.updated_at for profile in profiles.values()]
    oldest = min(dates)
    newest = max(dates)
    
    return {
        "total_profiles": len(profiles),
        "profiles_with_embeddings": profiles_with_embeddings,
        "oldest_profile": oldest.isoformat(),
        "newest_profile": newest.isoformat()
    }
