#!/usr/bin/env python3
"""
MTG Card Search Script

Searches for Magic: The Gathering cards in the mtgdata database.
Supports searching by card name, partial name, and filters by set.
"""
import sys
from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker


def create_connection(db_url: str):
    """Create database connection."""
    engine = create_engine(db_url)
    session_factory = sessionmaker(bind=engine)
    return engine, session_factory


def search_cards_by_name(session, card_name: str, set_code: str = None, limit: int = 10) -> list:
    """
    Search for cards by name.
    
    Args:
        session: Database session
        card_name: Card name to search for (partial matches supported)
        set_code: Optional set code to filter by
        limit: Maximum number of results
        
    Returns:
        List of card dictionaries
    """
    # Build query based on whether set_code is provided
    if set_code:
        query = """
            SELECT 
                c.id,
                c.name,
                c.type_line,
                c.mana_cost,
                c.oracle_text,
                c.power,
                c.toughness,
                c.rarity,
                c.layout,
                c.artist,
                c.flavor_text,
                s.code as set_code,
                s.name as set_name,
                s.release_date as set_release_date
            FROM mtg_cards c
            JOIN mtg_sets s ON c.set_id = s.id
            WHERE c.name LIKE :name
                AND s.code = :set_code
            ORDER BY c.name
            LIMIT :limit
        """
        params = {
            "name": f"%{card_name}%",
            "set_code": set_code.upper(),
            "limit": limit
        }
    else:
        query = """
            SELECT 
                c.id,
                c.name,
                c.type_line,
                c.mana_cost,
                c.oracle_text,
                c.power,
                c.toughness,
                c.rarity,
                c.layout,
                c.artist,
                c.flavor_text,
                s.code as set_code,
                s.name as set_name,
                s.release_date as set_release_date
            FROM mtg_cards c
            JOIN mtg_sets s ON c.set_id = s.id
            WHERE c.name LIKE :name
            ORDER BY c.name
            LIMIT :limit
        """
        params = {
            "name": f"%{card_name}%",
            "limit": limit
        }
    
    result = session.execute(text(query), params)
    
    cards = []
    for row in result:
        card = {
            "id": row[0],
            "name": row[1],
            "type_line": row[2],
            "mana_cost": row[3],
            "oracle_text": row[4],
            "power": row[5],
            "toughness": row[6],
            "rarity": row[7],
            "layout": row[8],
            "artist": row[9],
            "flavor_text": row[10],
            "set_code": row[11],
            "set_name": row[12],
            "set_release_date": row[13]
        }
        cards.append(card)
    
    return cards


def search_cards_by_set(session, set_code: str, limit: int = 100) -> list:
    """
    Get all cards from a specific set.
    
    Args:
        session: Database session
        set_code: Set code (e.g., '10E', '2ED')
        limit: Maximum number of cards to return
        
    Returns:
        List of card dictionaries
    """
    query = """
        SELECT 
            c.id,
            c.name,
            c.type_line,
            c.mana_cost,
            c.oracle_text,
            c.power,
            c.toughness,
            c.rarity,
            c.layout,
            c.artist,
            c.flavor_text,
            s.code as set_code,
            s.name as set_name,
            s.release_date as set_release_date
        FROM mtg_cards c
        JOIN mtg_sets s ON c.set_id = s.id
        WHERE s.code = :set_code
        ORDER BY c.name
        LIMIT :limit
    """
    
    params = {
        "set_code": set_code.upper(),
        "limit": limit
    }
    
    result = session.execute(text(query), params)
    
    cards = []
    for row in result:
        card = {
            "id": row[0],
            "name": row[1],
            "type_line": row[2],
            "mana_cost": row[3],
            "oracle_text": row[4],
            "power": row[5],
            "toughness": row[6],
            "rarity": row[7],
            "layout": row[8],
            "artist": row[9],
            "flavor_text": row[10],
            "set_code": row[11],
            "set_name": row[12],
            "set_release_date": row[13]
        }
        cards.append(card)
    
    return cards


def get_card_count(session, card_name: str = None, set_code: str = None) -> int:
    """
    Get count of cards matching search criteria.
    
    Args:
        session: Database session
        card_name: Optional card name filter
        set_code: Optional set code filter
        
    Returns:
        Number of matching cards
    """
    if card_name and set_code:
        query = """
            SELECT COUNT(*)
            FROM mtg_cards c
            JOIN mtg_sets s ON c.set_id = s.id
            WHERE c.name LIKE :name
                AND s.code = :set_code
        """
        params = {
            "name": f"%{card_name}%",
            "set_code": set_code.upper()
        }
    elif card_name:
        query = """
            SELECT COUNT(*)
            FROM mtg_cards
            WHERE name LIKE :name
        """
        params = {
            "name": f"%{card_name}%"
        }
    elif set_code:
        query = """
            SELECT COUNT(*)
            FROM mtg_cards
            WHERE set_id = (SELECT id FROM mtg_sets WHERE code = :set_code)
        """
        params = {
            "set_code": set_code.upper()
        }
    else:
        query = "SELECT COUNT(*) FROM mtg_cards"
        params = {}
    
    result = session.execute(text(query), params)
    return result.fetchone()[0]


def format_card(card: dict) -> str:
    """Format a card dictionary for display."""
    lines = [
        f"Name: {card['name']}",
        f"Type: {card['type_line'] or 'Unknown'}",
        f"Mana Cost: {card['mana_cost'] or 'N/A'}",
        f"Rarity: {card['rarity'] or 'N/A'}",
        f"Set: {card['set_code']} - {card['set_name']}",
    ]
    
    if card['oracle_text']:
        lines.append(f"Oracle Text: {card['oracle_text']}")
    
    if card['power'] and card['toughness']:
        lines.append(f"Power/Toughness: {card['power']}/{card['toughness']}")
    
    if card['artist']:
        lines.append(f"Artist: {card['artist']}")
    
    return "\n".join(lines)


def main():
    """Main entry point."""
    # Database connection
    db_url = "postgresql+psycopg2://mtgonline:mtgonline_pass@172.18.0.2:5432/mtgdata"
    engine, session_factory = create_connection(db_url)
    session = session_factory()
    
    try:
        # Get search parameters from command line
        if len(sys.argv) < 2:
            print("Usage: python search_cards.py <card_name> [set_code]")
            print("       python search_cards.py --set <set_code>")
            print("       python search_cards.py --count [card_name] [set_code]")
            print("\nExamples:")
            print("  python search_cards.py Lightning Bolt")
            print("  python search_cards.py Lightning Bolt 10E")
            print("  python search_cards.py --set 10E")
            print("  python search_cards.py --count Lightning")
            print("  python search_cards.py --count Lightning 10E")
            return
        
        # Parse arguments
        if sys.argv[1] == "--set":
            if len(sys.argv) < 3:
                print("Error: --set requires a set code")
                return
            set_code = sys.argv[2]
            print(f"Searching cards in set: {set_code}")
            cards = search_cards_by_set(session, set_code)
            print(f"\nFound {len(cards)} cards:\n")
            for card in cards:
                print(format_card(card))
                print("-" * 60)
        
        elif sys.argv[1] == "--count":
            card_name = sys.argv[2] if len(sys.argv) > 2 else None
            set_code = sys.argv[3] if len(sys.argv) > 3 else None
            
            count = get_card_count(session, card_name, set_code)
            print(f"Total cards matching criteria: {count}")
        
        else:
            card_name = sys.argv[1]
            set_code = sys.argv[2] if len(sys.argv) > 2 else None
            
            if set_code:
                print(f"Searching for '{card_name}' in set {set_code}")
            else:
                print(f"Searching for '{card_name}'")
            
            cards = search_cards_by_name(session, card_name, set_code)
            
            if not cards:
                print("No cards found.")
                return
            
            print(f"\nFound {len(cards)} card(s):\n")
            for card in cards:
                print(format_card(card))
                print("-" * 60)
    
    finally:
        session.close()
        engine.dispose()


if __name__ == "__main__":
    main()
