#!/usr/bin/env python3
"""
Photo scanning, metadata extraction, and file operations for PunimTag
"""

import os
from pathlib import Path
from PIL import Image
from datetime import datetime
from typing import Optional, List, Tuple

from src.core.config import SUPPORTED_IMAGE_FORMATS
from src.core.database import DatabaseManager
from src.utils.path_utils import normalize_path, validate_path_exists


class PhotoManager:
    """Handles photo scanning, metadata extraction, and file operations"""
    
    def __init__(self, db_manager: DatabaseManager, verbose: int = 0):
        """Initialize photo manager"""
        self.db = db_manager
        self.verbose = verbose
    
    def extract_photo_date(self, photo_path: str) -> Optional[str]:
        """Extract date taken from photo with fallback to file modification time.
        
        Tries in order:
        1. EXIF date tags (DateTimeOriginal, DateTimeDigitized, DateTime)
        2. File modification time (as fallback)
        """
        # First try EXIF date extraction
        try:
            with Image.open(photo_path) as image:
                exifdata = image.getexif()
                
                # Look for date taken in EXIF tags
                date_tags = [
                    36867,  # DateTimeOriginal - when photo was actually taken (highest priority)
                    36868,  # DateTimeDigitized - when photo was digitized
                    306,  # DateTime - file modification date (lowest priority)
                ]
                
                for tag_id in date_tags:
                    if tag_id in exifdata:
                        date_str = exifdata[tag_id]
                        if date_str:
                            # Parse EXIF date format (YYYY:MM:DD HH:MM:SS)
                            try:
                                date_obj = datetime.strptime(date_str, '%Y:%m:%d %H:%M:%S')
                                return date_obj.strftime('%Y-%m-%d')
                            except ValueError:
                                # Try alternative format
                                try:
                                    date_obj = datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')
                                    return date_obj.strftime('%Y-%m-%d')
                                except ValueError:
                                    continue
        except Exception as e:
            if self.verbose >= 2:
                print(f"   ⚠️  Could not extract EXIF date from {os.path.basename(photo_path)}: {e}")
        
        # Fallback to file modification time
        try:
            if os.path.exists(photo_path):
                mtime = os.path.getmtime(photo_path)
                mtime_date = datetime.fromtimestamp(mtime)
                return mtime_date.strftime('%Y-%m-%d')
        except Exception as e:
            if self.verbose >= 2:
                print(f"   ⚠️  Could not get file modification time from {os.path.basename(photo_path)}: {e}")
        
        return None
    
    def scan_folder(self, folder_path: str, recursive: bool = True) -> int:
        """Scan folder for photos and add to database"""
        # Normalize path to absolute path
        try:
            folder_path = normalize_path(folder_path)
        except ValueError as e:
            print(f"❌ Invalid path: {e}")
            return 0
            
        if not validate_path_exists(folder_path):
            print(f"❌ Folder not found or not accessible: {folder_path}")
            return 0
        
        found_photos = []
        
        if recursive:
            for root, dirs, files in os.walk(folder_path):
                for file in files:
                    file_ext = Path(file).suffix.lower()
                    if file_ext in SUPPORTED_IMAGE_FORMATS:
                        photo_path = os.path.join(root, file)
                        found_photos.append((photo_path, file))
        else:
            for file in os.listdir(folder_path):
                file_ext = Path(file).suffix.lower()
                if file_ext in SUPPORTED_IMAGE_FORMATS:
                    photo_path = os.path.join(folder_path, file)
                    found_photos.append((photo_path, file))
        
        if not found_photos:
            print(f"📁 No photos found in {folder_path}")
            return 0
        
        # Add to database
        added_count = 0
        existing_count = 0
        
        for photo_path, filename in found_photos:
            try:
                # Ensure photo path is absolute
                photo_path = normalize_path(photo_path)
                
                # Extract date taken from EXIF data
                date_taken = self.extract_photo_date(photo_path)
                
                # Add photo to database (with absolute path)
                photo_id = self.db.add_photo(photo_path, filename, date_taken)
                if photo_id:
                    # New photo was added
                    added_count += 1
                    if self.verbose >= 2:
                        date_info = f" (taken: {date_taken})" if date_taken else " (no date)"
                        print(f"   📸 Added: {filename}{date_info}")
                else:
                    # Photo already exists
                    existing_count += 1
                    if self.verbose >= 2:
                        print(f"   📸 Already exists: {filename}")
            except Exception as e:
                print(f"⚠️  Error adding {filename}: {e}")
        
        # Print summary
        if added_count > 0 and existing_count > 0:
            print(f"📁 Found {len(found_photos)} photos: {added_count} new, {existing_count} already in database")
        elif added_count > 0:
            print(f"📁 Found {len(found_photos)} photos, added {added_count} new photos")
        elif existing_count > 0:
            print(f"📁 Found {len(found_photos)} photos, all already in database")
        else:
            print(f"📁 Found {len(found_photos)} photos, none could be added")
        
        return added_count
    
    def get_photo_info(self, photo_id: int) -> Optional[Tuple]:
        """Get photo information by ID"""
        photos = self.db.get_photos_by_pattern(limit=1000)  # Get all photos
        for photo in photos:
            if photo[0] == photo_id:  # photo[0] is the ID
                return photo
        return None
    
    def get_photo_path(self, photo_id: int) -> Optional[str]:
        """Get photo path by ID"""
        photo_info = self.get_photo_info(photo_id)
        return photo_info[1] if photo_info else None  # photo[1] is the path
    
    def get_photo_filename(self, photo_id: int) -> Optional[str]:
        """Get photo filename by ID"""
        photo_info = self.get_photo_info(photo_id)
        return photo_info[2] if photo_info else None  # photo[2] is the filename
    
    def is_photo_processed(self, photo_id: int) -> bool:
        """Check if photo has been processed for faces"""
        photo_info = self.get_photo_info(photo_id)
        return photo_info[4] if photo_info else False  # photo[4] is the processed flag
    
    def mark_photo_processed(self, photo_id: int):
        """Mark a photo as processed"""
        self.db.mark_photo_processed(photo_id)
    
    def get_photos_by_date_range(self, date_from: str = None, date_to: str = None) -> List[Tuple]:
        """Get photos within a date range"""
        # This would need to be implemented in the database module
        # For now, return all photos
        return self.db.get_photos_by_pattern()
    
    def get_photos_by_pattern(self, pattern: str = None, limit: int = 10) -> List[Tuple]:
        """Get photos matching a pattern"""
        return self.db.get_photos_by_pattern(pattern, limit)
    
    def validate_photo_file(self, photo_path: str) -> bool:
        """Validate that a photo file exists and is readable"""
        if not os.path.exists(photo_path):
            return False
        
        try:
            with Image.open(photo_path) as image:
                image.verify()
            return True
        except Exception:
            return False
    
    def get_photo_dimensions(self, photo_path: str) -> Optional[Tuple[int, int]]:
        """Get photo dimensions (width, height)"""
        try:
            with Image.open(photo_path) as image:
                return image.size
        except Exception:
            return None
    
    def get_photo_format(self, photo_path: str) -> Optional[str]:
        """Get photo format"""
        try:
            with Image.open(photo_path) as image:
                return image.format
        except Exception:
            return None
    
    def get_photo_exif_data(self, photo_path: str) -> dict:
        """Get EXIF data from photo"""
        try:
            with Image.open(photo_path) as image:
                exifdata = image.getexif()
                return dict(exifdata)
        except Exception:
            return {}
    
    def get_photo_file_size(self, photo_path: str) -> Optional[int]:
        """Get photo file size in bytes"""
        try:
            return os.path.getsize(photo_path)
        except Exception:
            return None
    
    def get_photo_creation_time(self, photo_path: str) -> Optional[datetime]:
        """Get photo file creation time"""
        try:
            timestamp = os.path.getctime(photo_path)
            return datetime.fromtimestamp(timestamp)
        except Exception:
            return None
    
    def get_photo_modification_time(self, photo_path: str) -> Optional[datetime]:
        """Get photo file modification time"""
        try:
            timestamp = os.path.getmtime(photo_path)
            return datetime.fromtimestamp(timestamp)
        except Exception:
            return None
