import re from .models import Card, CardListing, Order, OrderItem, VaultItem from django.db.models import Min def add_to_vault(user, card, quantity=1): """ Adds a card to the user's vault. """ vault_item, created = VaultItem.objects.get_or_create(user=user, card=card) if not created: vault_item.quantity += quantity else: vault_item.quantity = quantity vault_item.save() def parse_deck_list(deck_text): """ Parses a deck list string and returns a list of dictionaries with 'quantity' and 'name'. Format expected: "4 Lightning Bolt" or "1x Lightning Bolt" """ lines = deck_text.strip().split('\n') parsed_cards = [] for line in lines: line = line.strip() if not line: continue match = re.match(r'^(\d+)[xX]?\s+(.+)$', line) if match: quantity = int(match.group(1)) name = match.group(2).strip() parsed_cards.append({'quantity': quantity, 'name': name}) else: # Maybe just name? assume 1 parsed_cards.append({'quantity': 1, 'name': line}) return parsed_cards def find_best_listings_for_deck(parsed_cards): """ Finds cheapest listings for the parsed cards. Returns: - found_items: list of {listing, quantity_needed, total_cost, card_name} - missing_items: list of {name, quantity} """ found_items = [] missing_items = [] for item in parsed_cards: name = item['name'] qty_needed = item['quantity'] # Find card (simple name match) cards = Card.objects.filter(name__iexact=name) if not cards.exists(): # Try contains cards = Card.objects.filter(name__icontains=name) if not cards.exists(): missing_items.append(item) continue # Find cheapest listing with stock # We try to fill the quantity from multiple listings if needed listings = CardListing.objects.filter( card__in=cards, quantity__gt=0 ).order_by('price') qty_remaining = qty_needed for listing in listings: if qty_remaining <= 0: break qty_to_take = min(listing.quantity, qty_remaining) found_items.append({ 'listing': listing, 'quantity': qty_to_take, 'card_name': listing.card.name, 'price': listing.price, 'total': listing.price * qty_to_take }) qty_remaining -= qty_to_take if qty_remaining > 0: missing_items.append({'name': name, 'quantity': qty_remaining}) return found_items, missing_items def get_user_collection(user): """ Returns a dict {card_name: quantity} of cards in user's vault. """ owned = {} if not user.is_authenticated: return owned vault_items = VaultItem.objects.filter(user=user).select_related('card') for item in vault_items: owned[item.card.name] = item.quantity return owned def filter_deck_by_collection(parsed_cards, owned_cards): """ Subtracts owned quantities from parsed_cards. Returns new list of parsed_cards. """ filtered = [] for item in parsed_cards: name = item['name'] needed = item['quantity'] # Simple name match owned_qty = 0 # Try exact match first if name in owned_cards: owned_qty = owned_cards[name] else: # Try case insensitive fallback for key in owned_cards: if key.lower() == name.lower(): owned_qty = owned_cards[key] break remaining = needed - owned_qty if remaining > 0: filtered.append({'name': name, 'quantity': remaining}) return filtered