"""
MTG Card Profile Extractor

Extracts structured profiles from MTGJSON card data.
Identifies mechanics, archetypes, mana costs, targets, and other game-relevant attributes.
"""
import re
from typing import List, Dict, Optional, Set
from dataclasses import dataclass


@dataclass
class CardProfile:
    """
    Structured profile of a card for interaction analysis.
    
    Contains all relevant game attributes extracted from MTGJSON data.
    """
    # Basic info
    id: int
    name: str
    mana_cost: Optional[str]
    type_line: Optional[str]
    oracle_text: Optional[str]
    subtypes: Optional[str]
    supertypes: Optional[str]
    set_code: Optional[str]
    
    # Extracted attributes
    colors: List[str] = None  # ['W', 'U', 'B', 'R', 'G']
    color_identity: List[str] = None
    mechanics: List[str] = None
    archetypes: List[str] = None
    targets: List[str] = None  # ['creature', 'artifact', 'player', etc.]
    triggers: List[str] = None
    effects: List[str] = None
    themes: List[str] = None  # ['storm', 'tokens', 'draw', etc.]
    
    def __post_init__(self):
        """Initialize lists if None."""
        if self.colors is None:
            self.colors = []
        if self.color_identity is None:
            self.color_identity = []
        if self.mechanics is None:
            self.mechanics = []
        if self.archetypes is None:
            self.archetypes = []
        if self.targets is None:
            self.targets = []
        if self.triggers is None:
            self.triggers = []
        if self.effects is None:
            self.effects = []
        if self.themes is None:
            self.themes = []
    
    def to_dict(self) -> Dict:
        """Convert profile to dictionary."""
        return {
            'id': self.id,
            'name': self.name,
            'mana_cost': self.mana_cost,
            'type_line': self.type_line,
            'oracle_text': self.oracle_text,
            'subtypes': self.subtypes,
            'supertypes': self.supertypes,
            'set_code': self.set_code,
            'colors': self.colors,
            'color_identity': self.color_identity,
            'mechanics': self.mechanics,
            'archetypes': self.archetypes,
            'targets': self.targets,
            'triggers': self.triggers,
            'effects': self.effects,
            'themes': self.themes,
        }


class CardProfileExtractor:
    """
    Extracts card profiles from MTGJSON data.
    
    Uses regex patterns and curated dictionaries to identify:
    - Mana costs and color identity
    - Game mechanics (flying, first strike, etc.)
    - Archetypes (goblin, elf, vampire, etc.)
    - Targets (creature, artifact, player, etc.)
    - Triggers (enters battlefield, dies, attacks, etc.)
    - Effects (gain flying, draw card, etc.)
    - Themes (storm, tokens, mill, etc.)
    """
    
    # Color symbols in mana costs
    COLOR_SYMBOLS = {
        '{W}': 'W',
        '{U}': 'U',
        '{B}': 'B',
        '{R}': 'R',
        '{G}': 'G',
    }
    
    # Known mechanics and their patterns
    MECHANICS = {
        'flying': r'Flying',
        'first_strike': r'First strike',
        'double_strike': r'Double strike',
        'deathtouch': r'Death touch',
        'lifelink': r'Lifelink',
        'haste': r'Haste',
        'trample': r'Trample',
        'menace': r'Menace',
        'vigilance': r'Vegilance',
        'reach': r'Reach',
        'indestructible': r'Indestructible',
        'hexproof': r'Hexproof',
        'shroud': r'Shroud',
        'defender': r'Defender',
        'landfall': r'Landfall',
        'delve': r'Delve',
        'suspend': r'Suspend',
        'convoke': r'Convoke',
        'rampage': r'Rampage',
        'toxic': r'Toxic',
        'crew': r'Crew',
        'equip': r'Equip',
        'annihilator': r'Annihilator',
        'spectacle': r'Spectacle',
        'prowess': r'Prowess',
        'aftermath': r'Aftermath',
        'adapt': r'Adapt',
        'amplify': r'Amplify',
        'awaken': r'Awaken',
        'kicker': r'Kicker',
        'morph': r'Morph',
        'evolve': r'Evolve',
        'exalted': r'Exalted',
        'storm': r'Storm',
        'madness': r'Madness',
        'manifest': r'Manifest',
        'modular': r'Modular',
        'mutate': r'Mutate',
        'transform': r'Transform',
        'unearth': r'Unearth',
        'persist': r'Persist',
        'rebound': r'Rebound',
        'replicate': r'Replicate',
        'soulshift': r'Soulshift',
        'dredge': r'Dredge',
        'devour': r'Devour',
        'banding': r'Band with',
        'bestow': r'Bestow',
        'channel': r'Channel',
        'clash': r'Clash',
        'curse': r'Curse',
        'dwell': r'Dwell',
        'evoke': r'Evoke',
        'exploit': r'Exploit',
        'extort': r'Extort',
        'flash': r'Flash',
        'foretell': r'Foretell',
        'frenzy': r'Frenzy',
        'grudge': r'Grudge',
        'heroic': r'Heroic',
        'hideaway': r'Hideaway',
        'horrify': r'Horrify',
        'impetus': r'Impetus',
        'infect': r'Infect',
        'journey': r'Journey',
        'kicker': r'Kicker',
        'landfall': r'Landfall',
        'meld': r'Meld',
        'miracle': r'Miracle',
        'monstrosity': r'Monstrosity',
        'morph': r'Morph',
        'mutate': r'Mutate',
        'ninja': r'Ninja',
        'pact': r'Pact',
        'persist': r'Persist',
        'provoke': r'Provoke',
        'quest': r'Quest',
        'raid': r'Raid',
        'rebound': r'Rebound',
        'replicate': r'Replicate',
        'revolt': r'Revolt',
        'shroud': r'Shroud',
        'skulk': r'Skulk',
        'snow': r'Snow',
        'splice': r'Splice',
        'staunch': r'Staunch',
        'storm': r'Storm',
        'suspend': r'Suspend',
        'surge': r'Surge',
        'swarm': r'Swarm',
        'thorn': r'Thorn',
        'toxic': r'Toxic',
        'transfigure': r'Transfigure',
        'transform': r'Transform',
        'unearth': r'Unearth',
        'unleash': r'Unleash',
        'vampiric': r'Vampiric',
        'ward': r'Ward',
        'willow': r'Willow',
        'winter': r'Winter',
        'wither': r'Wither',
        'wurm': r'Wurm',
    }
    
    # Known archetypes and their patterns
    ARCHETYPES = {
        'goblin': r'Goblin',
        'elf': r'Elf',
        'vampire': r'Veampire',
        'angel': r'Angel',
        'dragon': r'Dragon',
        'human': r'Human',
        'zombie': r'Zombie',
        'soldier': r'Soldier',
        'knight': r'Knight',
        'wizard': r'Wizard',
        'spirit': r'Spirit',
        'demon': r'Demon',
        'snake': r'Snake',
        'cat': r'Cat',
        'wolf': r'Wolf',
        'bear': r'Bear',
        'bird': r'Bird',
        'insect': r'Insect',
        'horror': r'Horror',
        'goat': r'Goat',
        'ox': r'Ox',
        'elephant': r'Elephant',
        'whale': r'Whale',
        'shark': r'Shark',
        'fish': r'Fish',
        'serpent': r'Serpent',
        'lizard': r'Lizard',
        'scorpion': r'Scorpion',
        'spider': r'Spider',
        'rat': r'Rat',
        'drake': r'Drake',
        'wyvern': r'Wyvern',
        'phoenix': r'Phoenix',
        'lynx': r'Lynx',
        'jaguar': r'Jaguar',
        'hydra': r'Hydra',
        'leviathan': r'Leviathan',
        'kraken': r'Kraken',
        'cyclops': r'Cyclops',
        'golem': r'Golem',
        'homunculus': r'Homunculus',
        'clay': r'Clay',
        'construct': r'Construct',
        'myr': r'Myr',
        'pirate': r'Pirate',
        'pegasus': r'Pegasus',
        'unicorn': r'Unicorn',
        'centaur': r'Centaur',
        'merfolk': r'Merfolk',
        'mermaid': r'Mermaid',
        'naga': r'Naga',
        'satyr': r'Satyr',
        'dryad': r'Dryad',
        'treant': r'Treant',
        'elemental': r'Elemental',
        'fiend': r'Fiend',
        'imp': r'Imp',
        'faerie': r'Faerie',
        'minion': r'Minion',
        'abomination': r'Abomination',
        'beast': r'Beast',
        'demigod': r'Demigod',
        'god': r'God',
        'avatar': r'Avatar',
        'guardian': r'Guardian',
        'warrior': r'Warrior',
        'rogue': r'Rogue',
        'artificer': r'Artificer',
        'bard': r'Bard',
        'monk': r'Monk',
        'ninja': r'Ninja',
        'samurai': r'Samurai',
        'assassin': r'Assassin',
        'thief': r'Thief',
        'acrobat': r'Acrobat',
        'explorer': r'Explorer',
        'myth': r'Myth',
        'illusion': r'Illusion',
        'mirror': r'Mirror',
        'phantom': r'Phantom',
        'shapeshifter': r'Shapeshifter',
        'shaman': r'Shaman',
        'skeleton': r'Skeleton',
        'slime': r'Slime',
        'squirrel': r'Squirrel',
        'troll': r'Troll',
        'tyrannosaur': r'Tyrannosaur',
        'wraith': r'Wraith',
        'wurm': r'Wurm',
    }
    
    # Target types and their patterns
    TARGET_TYPES = {
        'creature': r'creature',
        'artifact': r'artifact',
        'enchantment': r'enchantment',
        'instant': r'instant',
        'sorcery': r'sorcery',
        'planeswalker': r'planeswalker',
        'land': r'land',
        'player': r'player',
        'spell': r'spell',
        'permanent': r'permanent',
        'creature card': r'creature [Cc]ard',
    }
    
    # Trigger conditions and their patterns
    TRIGGERS = {
        'enters_battlefield': r'when [~|this] enters the battlefield',
        'leaves_battlefield': r'when [~|this] leaves the battlefield',
        'attacks': r'whenever [~|this] attacks',
        'blocks': r'whenever [~|this] blocks',
        'dies': r'when [~|this] dies',
        'damage': r'deals [0-9]+ damage',
        'draws_card': r'draw a card|draw two cards',
        'gains_life': r'gain [0-9]+ life',
        'creates_token': r'create a token',
        'taps': r'tap: add',
        'untaps': r'untap: add',
        'destroys': r'destroy target',
        'exiles': r'exile target',
        'counters_spell': r'counter target spell',
    }
    
    # Game effects and their patterns
    EFFECTS = {
        'gain_flying': r'gain flying',
        'gain_first_strike': r'gain first strike',
        'gain_double_strike': r'gain double strike',
        'gain_deathtouch': r'gain deathtouch',
        'gain_lifelink': r'gain lifelink',
        'gain_haste': r'gain haste',
        'gain_trample': r'gain trample',
        'gain_vigilance': r'gain vigilance',
        'gain_indestructible': r'gain indestructible',
        'gain_hexproof': r'gain hexproof',
        'until_end_of_turn': r'until end of turn',
        'until_next_turn': r'until your next turn',
        'deal_damage': r'deal [0-9]+ damage',
        'gain_life': r'gain [0-9]+ life',
        'draw_card': r'draw [0-9]+ card',
        'create_token': r'create [0-9]+ token',
        'destroy': r'destroy target',
        'exile': r'exile target',
        'counter_spell': r'counter target spell',
    }
    
    # Theme keywords and their patterns
    THEMES = {
        'storm': r'Storm',
        'tokens': r'create a token',
        'draw': r'draw a card',
        'life_gain': r'gain life',
        'board_wipe': r'destroy all',
        'reanimate': r'put from grave',
        'countermagic': r'counter target spell',
        'card_advantage': r'draw',
        'mana_acceleration': r'tap: add',
        'combat_tricks': r'gain [A-Za-z]+ until end of turn',
        'etb_effects': r'enters the battlefield',
        'ltb_effects': r'leaves the battlefield',
        'mill': r'put on bottom of library',
        'draw_go': r'draw a card',
        'aggro': r'deal [0-9]+ damage',
        'control': r'counter target spell',
        'midrange': r'creature',
    }
    
    def __init__(self):
        """Initialize the profile extractor."""
        pass
    
    def extract_colors(self, mana_cost: Optional[str]) -> List[str]:
        """
        Extract colors from mana cost.
        
        Args:
            mana_cost: Mana cost string (e.g., '{1}{R}')
            
        Returns:
            List of color symbols (e.g., ['R'])
        """
        if not mana_cost:
            return []
        
        colors = []
        for symbol, color in self.COLOR_SYMBOLS.items():
            if symbol in mana_cost:
                if color not in colors:
                    colors.append(color)
        
        return colors
    
    def extract_mechanics(self, card_type_line: Optional[str], card_oracle: Optional[str]) -> List[str]:
        """
        Extract game mechanics from card text.
        
        Args:
            card_type_line: Card type line (e.g., 'Creature - Goblin Warrior')
            card_oracle: Card oracle text
            
        Returns:
            List of mechanic names (e.g., ['haste', 'trample'])
        """
        mechanics = []
        
        # Combine type line and oracle text for checking
        text_to_check = f"{card_type_line or ''} {card_oracle or ''}".upper()
        
        for mechanic, pattern in self.MECHANICS.items():
            if re.search(pattern, text_to_check, re.IGNORECASE):
                if mechanic not in mechanics:
                    mechanics.append(mechanic)
        
        return mechanics
    
    def extract_archetypes(self, card_subtypes: Optional[str]) -> List[str]:
        """
        Extract archetypes from card subtypes.
        
        Args:
            card_subtypes: Card subtypes (e.g., 'Goblin, Warrior')
            
        Returns:
            List of archetype names (e.g., ['goblin'])
        """
        if not card_subtypes:
            return []
        
        archetypes = []
        
        for archetype, pattern in self.ARCHETYPES.items():
            if re.search(pattern, card_subtypes, re.IGNORECASE):
                if archetype not in archetypes:
                    archetypes.append(archetype)
        
        return archetypes
    
    def extract_targets(self, card_oracle: Optional[str]) -> List[str]:
        """
        Extract target types from oracle text.
        
        Args:
            card_oracle: Card oracle text
            
        Returns:
            List of target types (e.g., ['creature', 'player'])
        """
        if not card_oracle:
            return []
        
        targets = []
        
        for target, pattern in self.TARGET_TYPES.items():
            if re.search(pattern, card_oracle, re.IGNORECASE):
                if target not in targets:
                    targets.append(target)
        
        return targets
    
    def extract_triggers(self, card_oracle: Optional[str]) -> List[str]:
        """
        Extract trigger conditions from oracle text.
        
        Args:
            card_oracle: Card oracle text
            
        Returns:
            List of trigger names (e.g., ['enters_battlefield', 'dies'])
        """
        if not card_oracle:
            return []
        
        triggers = []
        
        for trigger, pattern in self.TRIGGERS.items():
            if re.search(pattern, card_oracle, re.IGNORECASE):
                if trigger not in triggers:
                    triggers.append(trigger)
        
        return triggers
    
    def extract_effects(self, card_oracle: Optional[str]) -> List[str]:
        """
        Extract game effects from oracle text.
        
        Args:
            card_oracle: Card oracle text
            
        Returns:
            List of effect names (e.g., ['gain_flying', 'draw_card'])
        """
        if not card_oracle:
            return []
        
        effects = []
        
        for effect, pattern in self.EFFECTS.items():
            if re.search(pattern, card_oracle, re.IGNORECASE):
                if effect not in effects:
                    effects.append(effect)
        
        return effects
    
    def extract_themes(self, card_mechanics: List[str], card_triggers: List[str], 
                      card_effects: List[str], card_targets: List[str]) -> List[str]:
        """
        Extract card themes based on characteristics.
        
        Args:
            card_mechanics: List of mechanics
            card_triggers: List of triggers
            card_effects: List of effects
            card_targets: List of targets
            
        Returns:
            List of theme names (e.g., ['storm', 'tokens'])
        """
        themes = []
        
        # Storm theme
        if 'storm' in card_mechanics or 'storm' in card_targets:
            themes.append('storm')
        
        # Token theme
        if any(e in card_effects for e in ['create_token', 'draw_card']):
            themes.append('tokens')
        
        # Mill theme
        if any(t in card_triggers for t in ['draws_card']):
            themes.append('mill')
        
        # Life gain theme
        if any(e in card_effects for e in ['gain_life', 'draw_card']):
            themes.append('life_gain')
        
        # Board wipe theme
        if any(t in card_triggers for t in ['dies']):
            themes.append('board_wipe')
        
        # Reanimate theme
        if any(t in card_triggers for t in ['leaves_battlefield']):
            themes.append('reanimate')
        
        # Countermagic theme
        if any(e in card_effects for e in ['counter_spell']):
            themes.append('countermagic')
        
        # Card advantage theme
        if any(t in card_triggers for t in ['draws_card']):
            themes.append('card_advantage')
        
        # Mana acceleration theme
        if any(t in card_triggers for t in ['taps']):
            themes.append('mana_acceleration')
        
        # Combat tricks theme
        if any(e in card_effects for e in ['gain_flying', 'gain_first_strike', 
                                           'gain_double_strike', 'gain_deathtouch',
                                           'gain_lifelink', 'gain_vigilance']):
            themes.append('combat_tricks')
        
        # ETB effects theme
        if any(t in card_triggers for t in ['enters_battlefield']):
            themes.append('etb_effects')
        
        # LTB effects theme
        if any(t in card_triggers for t in ['leaves_battlefield']):
            themes.append('ltb_effects')
        
        # Aggro theme
        if any(e in card_effects for e in ['deal_damage']):
            themes.append('aggro')
        
        # Control theme
        if any(e in card_effects for e in ['counter_spell']):
            themes.append('control')
        
        # Midrange theme
        if any(t in card_targets for t in ['creature']):
            themes.append('midrange')
        
        return themes
    
    def extract_profile(self, card_data: Dict) -> CardProfile:
        """
        Extract a complete card profile from MTGJSON data.
        
        Args:
            card_data: MTGJSON card dictionary
            
        Returns:
            CardProfile object with all extracted attributes
        """
        # Parse subtypes
        subtypes = None
        if card_data.get('subtypes'):
            subtypes = ', '.join(card_data['subtypes'])
        
        # Parse supertypes
        supertypes = None
        if card_data.get('supertypes'):
            supertypes = ', '.join(card_data['supertypes'])
        
        # Extract colors from mana cost
        colors = self.extract_colors(card_data.get('manaCost'))
        
        # Extract mechanics
        mechanics = self.extract_mechanics(
            card_data.get('typeLine'),
            card_data.get('oracleText')
        )
        
        # Extract archetypes
        archetypes = self.extract_archetypes(subtypes)
        
        # Extract targets
        targets = self.extract_targets(card_data.get('oracleText'))
        
        # Extract triggers
        triggers = self.extract_triggers(card_data.get('oracleText'))
        
        # Extract effects
        effects = self.extract_effects(card_data.get('oracleText'))
        
        # Extract themes
        themes = self.extract_themes(mechanics, triggers, effects, targets)
        
        # Create profile
        profile = CardProfile(
            id=card_data.get('id', 0),
            name=card_data.get('name', ''),
            mana_cost=card_data.get('manaCost'),
            type_line=card_data.get('typeLine'),
            oracle_text=card_data.get('oracleText'),
            subtypes=subtypes,
            supertypes=supertypes,
            set_code=card_data.get('set', {}).get('code') if card_data.get('set') else None,
            colors=colors,
            color_identity=card_data.get('colorIdentity'),
            mechanics=mechanics,
            archetypes=archetypes,
            targets=targets,
            triggers=triggers,
            effects=effects,
            themes=themes,
        )
        
        return profile
    
    def extract_profiles_batch(self, cards: List[Dict]) -> List[CardProfile]:
        """
        Extract profiles for a batch of cards.
        
        Args:
            cards: List of MTGJSON card dictionaries
            
        Returns:
            List of CardProfile objects
        """
        return [self.extract_profile(card) for card in cards]
