#!/usr/bin/env python3
"""
Tag management functionality for PunimTag
"""

from typing import List, Dict, Tuple, Optional

from src.core.config import DEFAULT_BATCH_SIZE
from src.core.database import DatabaseManager


class TagManager:
    """Handles photo tagging and tag management operations"""
    
    def __init__(self, db_manager: DatabaseManager, verbose: int = 0):
        """Initialize tag manager"""
        self.db = db_manager
        self.verbose = verbose
    
    def deduplicate_tags(self, tag_list: List[str]) -> List[str]:
        """Remove duplicate tags from a list while preserving order (case insensitive)"""
        seen = set()
        unique_tags = []
        for tag in tag_list:
            if tag.lower() not in seen:
                seen.add(tag.lower())
                unique_tags.append(tag)
        return unique_tags
    
    def parse_tags_string(self, tags_string: str) -> List[str]:
        """Parse a comma-separated tags string into a list, handling empty strings and whitespace"""
        if not tags_string or tags_string.strip() == "":
            return []
        # Split by comma and strip whitespace from each tag
        tags = [tag.strip() for tag in tags_string.split(",")]
        # Remove empty strings that might result from splitting
        return [tag for tag in tags if tag]
    
    def add_tags_to_photos(self, photo_pattern: str = None, batch_size: int = DEFAULT_BATCH_SIZE) -> int:
        """Add custom tags to photos via command line interface"""
        if photo_pattern:
            photos = self.db.get_photos_by_pattern(photo_pattern, batch_size)
        else:
            photos = self.db.get_photos_by_pattern(limit=batch_size)
        
        if not photos:
            print("No photos found")
            return 0
        
        print(f"🏷️  Tagging {len(photos)} photos (enter comma-separated tags)")
        tagged_count = 0
        
        for photo_id, photo_path, filename, date_taken, processed in photos:
            print(f"\n📸 {filename}")
            tags_input = input("🏷️  Tags: ").strip()
            
            if tags_input.lower() == 'q':
                break
            
            if tags_input:
                tags = self.parse_tags_string(tags_input)
                tags = self.deduplicate_tags(tags)
                
                for tag_name in tags:
                    # Add tag to database and get its ID
                    tag_id = self.db.add_tag(tag_name)
                    if tag_id:
                        # Link photo to tag
                        self.db.link_photo_tag(photo_id, tag_id)
                
                print(f"   ✅ Added {len(tags)} tags")
                tagged_count += 1
        
        print(f"✅ Tagged {tagged_count} photos")
        return tagged_count
    
    def add_tags_to_photo(self, photo_id: int, tags: List[str]) -> int:
        """Add tags to a specific photo"""
        if not tags:
            return 0
        
        tags = self.deduplicate_tags(tags)
        added_count = 0
        
        for tag_name in tags:
            # Add tag to database and get its ID
            tag_id = self.db.add_tag(tag_name)
            if tag_id:
                # Link photo to tag
                self.db.link_photo_tag(photo_id, tag_id)
                added_count += 1
        
        return added_count
    
    def remove_tags_from_photo(self, photo_id: int, tags: List[str]) -> int:
        """Remove tags from a specific photo"""
        if not tags:
            return 0
        
        removed_count = 0
        tag_id_to_name, tag_name_to_id = self.db.load_tag_mappings()
        
        for tag_name in tags:
            if tag_name in tag_name_to_id:
                tag_id = tag_name_to_id[tag_name]
                self.db.unlink_photo_tag(photo_id, tag_id)
                removed_count += 1
        
        return removed_count
    
    def get_photo_tags(self, photo_id: int) -> List[str]:
        """Get all tags for a specific photo"""
        tag_ids = self.db.get_existing_tag_ids_for_photo(photo_id)
        tag_id_to_name, _ = self.db.load_tag_mappings()
        
        tags = []
        for tag_id in tag_ids:
            tag_name = self.db.get_tag_name_by_id(tag_id, tag_id_to_name)
            tags.append(tag_name)
        
        return tags
    
    def get_all_tags(self) -> List[Tuple[int, str]]:
        """Get all tags in the database"""
        tag_id_to_name, _ = self.db.load_tag_mappings()
        return [(tag_id, tag_name) for tag_id, tag_name in tag_id_to_name.items()]
    
    def get_photos_with_tag(self, tag_name: str) -> List[Tuple]:
        """Get all photos that have a specific tag"""
        tag_id_to_name, tag_name_to_id = self.db.load_tag_mappings()
        
        if tag_name not in tag_name_to_id:
            return []
        
        tag_id = tag_name_to_id[tag_name]
        
        # This would need to be implemented in the database module
        # For now, return empty list
        return []
    
    def get_tag_statistics(self) -> Dict:
        """Get tag usage statistics"""
        tag_id_to_name, _ = self.db.load_tag_mappings()
        stats = {
            'total_tags': len(tag_id_to_name),
            'tag_usage': {}
        }
        
        # Count usage for each tag
        for tag_id, tag_name in tag_id_to_name.items():
            # This would need to be implemented in the database module
            # For now, set usage to 0
            stats['tag_usage'][tag_name] = 0
        
        return stats
    
    def delete_tag(self, tag_name: str) -> bool:
        """Delete a tag from the database (and all its linkages)"""
        tag_id_to_name, tag_name_to_id = self.db.load_tag_mappings()
        
        if tag_name not in tag_name_to_id:
            return False
        
        tag_id = tag_name_to_id[tag_name]
        
        # This would need to be implemented in the database module
        # For now, return False
        return False
    
    def rename_tag(self, old_name: str, new_name: str) -> bool:
        """Rename a tag"""
        tag_id_to_name, tag_name_to_id = self.db.load_tag_mappings()
        
        if old_name not in tag_name_to_id:
            return False
        
        if new_name in tag_name_to_id:
            return False  # New name already exists
        
        tag_id = tag_name_to_id[old_name]
        
        # This would need to be implemented in the database module
        # For now, return False
        return False
    
    def merge_tags(self, source_tag: str, target_tag: str) -> bool:
        """Merge one tag into another (move all linkages from source to target)"""
        tag_id_to_name, tag_name_to_id = self.db.load_tag_mappings()
        
        if source_tag not in tag_name_to_id or target_tag not in tag_name_to_id:
            return False
        
        source_tag_id = tag_name_to_id[source_tag]
        target_tag_id = tag_name_to_id[target_tag]
        
        # This would need to be implemented in the database module
        # For now, return False
        return False
    
    def get_photos_by_tags(self, tags: List[str], match_all: bool = False) -> List[Tuple]:
        """Get photos that have any (or all) of the specified tags"""
        if not tags:
            return []
        
        tag_id_to_name, tag_name_to_id = self.db.load_tag_mappings()
        tag_ids = []
        
        for tag_name in tags:
            # Convert to lowercase for case-insensitive lookup
            normalized_tag_name = tag_name.lower().strip()
            if normalized_tag_name in tag_name_to_id:
                tag_ids.append(tag_name_to_id[normalized_tag_name])
        
        if not tag_ids:
            return []
        
        # This would need to be implemented in the database module
        # For now, return empty list
        return []
    
    def get_common_tags(self, photo_ids: List[int]) -> List[str]:
        """Get tags that are common to all specified photos"""
        if not photo_ids:
            return []
        
        # Get tags for each photo
        all_photo_tags = []
        for photo_id in photo_ids:
            tags = self.get_photo_tags(photo_id)
            all_photo_tags.append(set(tags))
        
        if not all_photo_tags:
            return []
        
        # Find intersection of all tag sets
        common_tags = set.intersection(*all_photo_tags)
        return list(common_tags)
    
    def get_suggested_tags(self, photo_id: int, limit: int = 5) -> List[str]:
        """Get suggested tags based on similar photos"""
        # This is a placeholder for tag suggestion logic
        # Could be implemented based on:
        # - Tags from photos in the same folder
        # - Tags from photos taken on the same date
        # - Most commonly used tags
        # - Machine learning based suggestions
        
        return []
    
    def validate_tag_name(self, tag_name: str) -> Tuple[bool, str]:
        """Validate a tag name and return (is_valid, error_message)"""
        if not tag_name or not tag_name.strip():
            return False, "Tag name cannot be empty"
        
        tag_name = tag_name.strip()
        
        if len(tag_name) > 50:
            return False, "Tag name is too long (max 50 characters)"
        
        if ',' in tag_name:
            return False, "Tag name cannot contain commas"
        
        if tag_name.lower() in ['all', 'none', 'untagged']:
            return False, "Tag name is reserved"
        
        return True, ""
