"""
Photo model definition
"""
from sqlalchemy import Column, String, Integer, Float, Boolean, DateTime, ForeignKey, Text, Index
from sqlalchemy.sql import func
from datetime import datetime
import uuid

from app.database import Base

class Photo(Base):
    __tablename__ = 'photos'
    
    # Primary key
    id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()))
    
    # Owner
    user_id = Column(String, ForeignKey('users.id'), nullable=True, index=True)

    # File information
    filepath = Column(String, unique=True, nullable=False)
    filename = Column(String, nullable=False)
    folder_id = Column(String, ForeignKey('folders.id'))
    file_hash = Column(String, index=True)  # SHA-256 hash for duplicate detection
    
    # Media information
    media_type = Column(String, nullable=False)  # 'photo' | 'video' | 'raw' | 'heic'
    original_format = Column(String)  # 'CR3', 'NEF', 'HEIC', 'MP4', 'JPEG', etc.
    width = Column(Integer)
    height = Column(Integer)
    file_size = Column(Integer)
    
    # Timestamps
    taken_at = Column(DateTime)  # from EXIF DateTimeOriginal, fallback to file mtime
    taken_at_source = Column(String)  # 'exif' | 'filesystem' | 'manual'
    added_at = Column(DateTime, server_default=func.now())
    updated_at = Column(DateTime, onupdate=func.now())
    
    # Discard status. The DB column names stay is_trashed/trashed_at to avoid
    # a migration; only the Python attribute name reflects the rename.
    is_discarded = Column('is_trashed', Boolean, default=False)
    discarded_at = Column('trashed_at', DateTime)

    # "Hidden from views" — materialized from Folder.is_hidden walking
    # the ancestry chain. True iff any ancestor folder (including the
    # photo's direct folder) is hidden. Cross-cutting queries filter
    # `AND NOT is_hidden`; per-folder browses ignore the flag so the
    # user can still open a hidden folder and see its contents. The
    # column is maintained by two places: the scanner sets it on new
    # rows, and POST /folders/{id}/hide recomputes it on toggle.
    is_hidden = Column(Boolean, nullable=False, default=False, server_default='false', index=True)

    # "Needs review" — set by the content classifier when a photo is
    # classified as 'other' (screenshot, document, meme, scan, etc.) so
    # the user can page through non-photographs in the UI and triage them.
    needs_review = Column(Boolean, nullable=False, default=False, server_default='false', index=True)

    # "Capture date is probably wrong" — denormalized from the folder/filename
    # date-guesser. Set at scan time and recomputed on every taken_at edit so
    # the filter bar can query it directly. See services/date_guess.py for
    # the heuristic; kept as a stored column because recomputing on every
    # list query would mean running the regex stack across thousands of rows.
    has_date_warning = Column(Boolean, nullable=False, default=False, server_default='false', index=True)
    
    # Thumbnail paths
    thumb_small = Column(String)  # path to 240px thumb
    thumb_medium = Column(String)  # path to 640px thumb
    thumb_large = Column(String)  # path to 1280px thumb
    
    # Processing status
    processing_status = Column(String, default='pending')  # 'pending' | 'processing' | 'completed' | 'failed'
    processing_error = Column(Text)
    
    # Metadata
    exif_json = Column(Text)  # full EXIF/XMP blob as JSON

    # GPS coordinates extracted from EXIF, in signed decimal degrees
    # (S latitude / W longitude are negative). Stored as first-class columns
    # so the Map view and any future location filters can query/index them
    # without parsing exif_json on every request.
    latitude = Column(Float)
    longitude = Column(Float)
    
    # User-editable fields
    user_title = Column(String)
    user_notes = Column(Text)
    rating = Column(Integer, default=0)  # 0-5 stars
    color_label = Column(String)  # 'red'|'orange'|'yellow'|'green'|'blue'|'purple'|NULL
    # Note: is_rejected was merged into is_discarded (a single soft "discarded"
    # concept). is_picked was unified with active-heap membership — picking a
    # photo just means adding it to the active heap. Both DB columns may still
    # exist on legacy installs but are no longer read or written.
    
    # Duplicate detection.
    #
    #   - file_hash (above): SHA-256 of the raw bytes. Catches byte-identical
    #     copies but not visually-identical re-encodes / resizes / screenshots.
    #   - phash: 16-char hex of a 64-bit perceptual hash, computed by the
    #     thumbs worker from the decoded original frame. Robust to resize and
    #     re-compression — this is what actually identifies "the same photo
    #     saved twice with different JPEG quality".
    #   - duplicate_group_id: shared by every photo in the same duplicate
    #     cluster. Maintained by app.services.duplicates.regroup_duplicates,
    #     not on individual writes — recomputed in batches after scans / on
    #     demand from the Settings panel.
    #   - is_duplicate: derived boolean (group_id IS NOT NULL). Kept as a real
    #     column so the existing PhotoThumbnail badge and /library/stats
    #     duplicates count don't have to change.
    is_duplicate = Column(Boolean, default=False)
    phash = Column(String(16), index=True)
    duplicate_group_id = Column(String, index=True)
    
    # Live photo support
    live_photo_video_id = Column(String, ForeignKey('photos.id'))
    
    # Indexes for performance
    __table_args__ = (
        Index('ix_photos_taken_at', 'taken_at'),
        Index('ix_photos_folder_id', 'folder_id'),
        Index('ix_photos_is_trashed', 'is_trashed'),
        Index('ix_photos_rating', 'rating'),
        Index('ix_photos_color_label', 'color_label'),
        Index('ix_photos_media_type', 'media_type'),
        Index('ix_photos_processing_status', 'processing_status'),
        Index('ix_photos_lat_lon', 'latitude', 'longitude'),
        Index('ix_photos_needs_review', 'needs_review'),
    )