"""
Kurate Art Collection Manager - Python Implementation
Inspired by kurateart.com - Art curation and collection platform
This tool organizes, tags, and manages digital art collections
"""

import hashlib
import json
from dataclasses import dataclass, field, asdict
from datetime import datetime
from typing import Dict, List, Optional, Set
from pathlib import Path


@dataclass
class Artwork:
    """Represents a curated art piece with full metadata."""

    id: str
    title: str
    artist: str = ""
    year_created: Optional[int] = None
    period: str = ""
    style: str = ""
    medium: str = ""
    dimensions: str = ""
    location: str = ""
    file_path: str = ""
    tags: List[str] = field(default_factory=list)
    attributes: Dict[str, str] = field(default_factory=dict)
    cataloged_at: str = field(default_factory=lambda: datetime.now().isoformat())
    last_modified: str = ""

    def __post_init__(self):
        if not self.last_modified:
            self.last_modified = self.cataloged_at

    def apply_tags(self, new_tags: List[str]) -> 'Artwork':
        """Add tags to this artwork, avoiding duplicates."""
        for tag in new_tags:
            normalized = tag.lower().strip()
            if normalized and normalized not in self.tags:
                self.tags.append(normalized)
        self.last_modified = datetime.now().isoformat()
        return self

    def to_json(self) -> str:
        """Convert artwork to JSON string."""
        return json.dumps(asdict(self), indent=2)


@dataclass
class Collection:
    """Represents a curated set of artworks."""

    id: str
    name: str
    description: str = ""
    curator: str = ""
    artwork_ids: List[str] = field(default_factory=list)
    created_at: str = field(default_factory=lambda: datetime.now().isoformat())

    def get_artworks(self, catalog: Dict[str, Artwork]) -> List[Artwork]:
        """Get all artworks in this collection."""
        return [catalog.get(aid) for aid in self.artwork_ids if aid in catalog]


@dataclass
class ClassificationResult:
    """Contains style and period classification results."""

    style: str
    period: str
    confidence: float
    suggested_tags: List[str] = field(default_factory=list)


# Global catalog and index
artwork_catalog: Dict[str, Artwork] = {}
collection_index: Dict[str, Set[str]] = {}


def catalog_artwork(file_path: str, metadata: Dict = None) -> Artwork:
    """
    Create a new artwork entry with metadata.

    Args:
        file_path: Path to the artwork file
        metadata: Optional dictionary of artwork metadata

    Returns:
        New Artwork instance
    """
    if metadata is None:
        metadata = {}

    # Generate unique ID from file path
    hash_obj = hashlib.md5(file_path.encode())
    artwork_id = hash_obj.hexdigest()[:12]

    # Extract metadata fields
    title = metadata.get('title', Path(file_path).name)
    artist = metadata.get('artist', '')
    period = metadata.get('period', '')
    style = metadata.get('style', '')
    medium = metadata.get('medium', '')
    dimensions = metadata.get('dimensions', '')
    location = metadata.get('location', '')
    tags = metadata.get('tags', [])
    year_created = metadata.get('yearCreated')

    # Separate additional attributes
    reserved_keys = {'title', 'artist', 'yearCreated', 'period', 'style',
                     'medium', 'dimensions', 'location', 'tags'}
    attributes = {k: v for k, v in metadata.items() if k not in reserved_keys}

    return Artwork(
        id=artwork_id,
        title=title,
        artist=artist,
        year_created=year_created,
        period=period,
        style=style,
        medium=medium,
        dimensions=dimensions,
        location=location,
        file_path=file_path,
        tags=tags,
        attributes=attributes
    )


def classify_by_style(artwork: Artwork) -> ClassificationResult:
    """
    Analyze artwork metadata to determine style and period.

    Args:
        artwork: Artwork to classify

    Returns:
        ClassificationResult with style, period, and suggested tags
    """
    result = ClassificationResult(
        style='Unclassified',
        period='Unknown',
        confidence=0.0,
        suggested_tags=[]
    )

    period_lower = (artwork.period or '').lower()
    medium_lower = (artwork.medium or '').lower()

    if 'renaissance' in period_lower:
        result.style = 'Classical'
        result.period = 'Renaissance'
        result.confidence = 0.85
        result.suggested_tags = ['classical', 'renaissance', 'masterpiece']

    elif 'baroque' in period_lower:
        result.style = 'Baroque'
        result.period = 'Baroque'
        result.confidence = 0.88
        result.suggested_tags = ['baroque', 'dramatic', 'chiaroscuro']

    elif 'impressionist' in period_lower:
        result.style = 'Impressionism'
        result.period = '19th Century'
        result.confidence = 0.90
        result.suggested_tags = ['impressionism', 'light', 'color']

    elif 'modern' in period_lower or 'contemporary' in period_lower:
        result.style = 'Modern'
        result.period = 'Modern/Contemporary'
        result.confidence = 0.75
        result.suggested_tags = ['modern', 'abstract', 'contemporary']

    elif 'oil' in medium_lower:
        result.style = 'Traditional'
        result.period = 'Classical'
        result.confidence = 0.60
        result.suggested_tags = ['painting', 'oil', 'traditional']

    elif 'watercolor' in medium_lower:
        result.style = 'Watercolor'
        result.period = 'Various'
        result.confidence = 0.70
        result.suggested_tags = ['watercolor', 'painting', 'delicate']

    elif 'digital' in medium_lower:
        result.style = 'Digital Art'
        result.period = 'Contemporary'
        result.confidence = 0.95
        result.suggested_tags = ['digital', 'contemporary', 'computer-generated']

    return result


def index_artwork(artwork: Artwork) -> None:
    """
    Add artwork to the searchable index.

    Args:
        artwork: Artwork to index
    """
    # Store in catalog
    artwork_catalog[artwork.id] = artwork

    # Index by artist
    if artwork.artist:
        key = f"artist:{artwork.artist.lower()}"
        if key not in collection_index:
            collection_index[key] = set()
        collection_index[key].add(artwork.id)

    # Index by style
    if artwork.style:
        key = f"style:{artwork.style.lower()}"
        if key not in collection_index:
            collection_index[key] = set()
        collection_index[key].add(artwork.id)

    # Index by period
    if artwork.period:
        key = f"period:{artwork.period.lower()}"
        if key not in collection_index:
            collection_index[key] = set()
        collection_index[key].add(artwork.id)

    # Index by tags
    for tag in artwork.tags:
        key = f"tag:{tag}"
        if key not in collection_index:
            collection_index[key] = set()
        collection_index[key].add(artwork.id)


def search_by_artist(artist_name: str) -> List[Artwork]:
    """Find all artworks by a specific artist."""
    key = f"artist:{artist_name.lower()}"
    ids = collection_index.get(key, set())
    return [artwork_catalog.get(aid) for aid in ids if aid in artwork_catalog]


def search_by_style(style: str) -> List[Artwork]:
    """Find all artworks in a specific style."""
    key = f"style:{style.lower()}"
    ids = collection_index.get(key, set())
    return [artwork_catalog.get(aid) for aid in ids if aid in artwork_catalog]


def search_by_period(period: str) -> List[Artwork]:
    """Find all artworks from a specific period."""
    key = f"period:{period.lower()}"
    ids = collection_index.get(key, set())
    return [artwork_catalog.get(aid) for aid in ids if aid in artwork_catalog]


def search_by_tag(tag: str) -> List[Artwork]:
    """Find all artworks with a specific tag."""
    key = f"tag:{tag.lower()}"
    ids = collection_index.get(key, set())
    return [artwork_catalog.get(aid) for aid in ids if aid in artwork_catalog]


def create_collection(name: str, description: str, curator: str,
                      artwork_ids: List[str]) -> Collection:
    """
    Organize artworks into a named collection.

    Args:
        name: Collection name
        description: Collection description
        curator: Name of the curator
        artwork_ids: List of artwork IDs to include

    Returns:
        New Collection instance
    """
    hash_input = name + datetime.now().isoformat()
    collection_id = f"col-{hashlib.md5(hash_input.encode()).hexdigest()[:10]}"

    return Collection(
        id=collection_id,
        name=name,
        description=description,
        curator=curator,
        artwork_ids=artwork_ids
    )


def organize_gallery_layout(artworks: List[Artwork]) -> List[List[Optional[str]]]:
    """
    Suggest a gallery layout based on artworks.

    Returns a 3x3 grid layout with artwork IDs.
    """
    grid_size = 3
    layout = [[None for _ in range(grid_size)] for _ in range(grid_size)]

    for i, artwork in enumerate(artworks):
        if i >= grid_size * grid_size:
            break
        row = i // grid_size
        col = i % grid_size
        layout[row][col] = artwork.id

    return layout


def print_artwork_summary(artwork: Artwork) -> None:
    """Display artwork information."""
    print("=== Artwork Summary ===")
    print(f"ID:          {artwork.id}")
    print(f"Title:       {artwork.title}")
    print(f"Artist:      {artwork.artist}")
    print(f"Period:      {artwork.period}")
    print(f"Style:       {artwork.style}")
    print(f"Medium:      {artwork.medium}")
    print(f"Dimensions:  {artwork.dimensions}")
    print(f"Location:    {artwork.location}")
    print(f"File:        {artwork.file_path}")

    if artwork.tags:
        print(f"Tags:        {', '.join(artwork.tags)}")

    if artwork.attributes:
        print("\nAttributes:")
        for key, value in artwork.attributes.items():
            print(f"  {key}: {value}")

    cataloged = datetime.fromisoformat(artwork.cataloged_at)
    print(f"\nCataloged:   {cataloged.strftime('%Y-%m-%d %H:%M:%S')}")


def export_catalog_as_json() -> str:
    """Export the artwork catalog as JSON."""
    artworks = [asdict(a) for a in artwork_catalog.values()]
    return json.dumps(artworks, indent=2)


def main() -> None:
    """Main demo function."""
    print("Kurate Art Collection Manager - Python Implementation")
    print("Inspired by kurateart.com\n")

    # Catalog artworks
    artwork1 = catalog_artwork('/art/mona-lisa.jpg', {
        'title': 'Mona Lisa',
        'artist': 'Leonardo da Vinci',
        'period': 'Renaissance',
        'style': 'Classical',
        'medium': 'Oil on poplar panel',
        'dimensions': '77cm x 53cm',
        'location': 'Louvre Museum'
    })

    classification1 = classify_by_style(artwork1)
    artwork1.apply_tags(classification1.suggested_tags)
    index_artwork(artwork1)

    artwork2 = catalog_artwork('/art/starry-night.jpg', {
        'title': 'Starry Night',
        'artist': 'Vincent van Gogh',
        'period': 'Post-Impressionism',
        'style': 'Impressionism',
        'medium': 'Oil on canvas',
        'dimensions': '73.7cm x 92.1cm',
        'location': 'Museum of Modern Art'
    })

    classification2 = classify_by_style(artwork2)
    artwork2.apply_tags(classification2.suggested_tags)
    index_artwork(artwork2)

    # Print summaries
    print_artwork_summary(artwork1)
    print()
    print_artwork_summary(artwork2)

    # Search examples
    print("\n=== Search Results ===")
    da_vinci_works = search_by_artist('Leonardo da Vinci')
    print(f"\nWorks by Leonardo da Vinci: {len(da_vinci_works)} found")

    impressionist_works = search_by_style('Impressionism')
    print(f"Impressionism artworks: {len(impressionist_works)} found")

    # Create a collection
    collection = create_collection(
        'Masterpieces Collection',
        'A curated collection of world-renowned artworks',
        'AI Curator',
        [artwork1.id, artwork2.id]
    )

    print(f"\n=== Collection: {collection.name} ===")
    print(f"Artworks: {len(collection.artwork_ids)}")
    for art in collection.get_artworks(artwork_catalog):
        print(f"  - {art.title} by {art.artist}")

    # Export as JSON
    print("\n=== JSON Export ===")
    print(export_catalog_as_json())


if __name__ == "__main__":
    main()
