"""
Hit Damage Enhancer Module
Provides functionality to enhance damage multipliers for different body parts in games.
"""

import pymem
import pymem.process
import time


class HitDamageEnhancer:
    """
    A class to enhance hit damage for different body parts in games through memory manipulation.
    
    Attributes:
        pm: Pymem instance for memory operations
        game_module: Game module reference
        client_dll: Base address of client DLL
        is_running: Enhancement status flag
        damage_multipliers: Damage multipliers for body parts
        hit_groups: Hit group identifiers
    """
    
    def __init__(self):
        """Initialize the HitDamageEnhancer with default settings."""
        self.pm = None
        self.game_module = None
        self.client_dll = None
        self.is_running = False
        
        # Damage enhancement configuration
        self.damage_multipliers = {
            'head': 4.0,      # Head damage multiplier
            'chest': 1.2,     # Chest damage multiplier
            'stomach': 1.1,   # Stomach damage multiplier
            'left_arm': 1.3,  # Left arm damage multiplier
            'right_arm': 1.3, # Right arm damage multiplier
            'left_leg': 1.2,  # Left leg damage multiplier
            'right_leg': 1.2  # Right leg damage multiplier
        }
        
        # Hit group constants (adjust according to game)
        self.hit_groups = {
            'head': 1,
            'chest': 2,
            'stomach': 3,
            'left_arm': 4,
            'right_arm': 5,
            'left_leg': 6,
            'right_leg': 7
        }

    def initialize(self, process_name="csgo.exe", module_name="client.dll"):
        """
        Initialize memory read/write operations.
        
        Args:
            process_name (str): Name of the target process
            module_name (str): Name of the target module
            
        Returns:
            bool: True if initialization successful, False otherwise
        """
        try:
            self.pm = pymem.Pymem(process_name)
            self.game_module = pymem.process.module_from_name(
                self.pm.process_handle, 
                module_name
            )
            self.client_dll = self.game_module.lpBaseOfDll
            print(f"Successfully connected to {process_name}")
            return True
        except Exception as e:
            print(f"Initialization failed: {e}")
            return False

    def read_memory(self, address, data_type='int'):
        """
        Read data from memory.
        
        Args:
            address: Memory address to read from
            data_type (str): Type of data to read ('int', 'float', 'bytes')
            
        Returns:
            Data read from memory or None if failed
        """
        try:
            if data_type == 'int':
                return self.pm.read_int(address)
            elif data_type == 'float':
                return self.pm.read_float(address)
            elif data_type == 'bytes':
                return self.pm.read_bytes(address, 4)
            return None
        except Exception as e:
            print(f"Memory read failed: {e}")
            return None

    def write_memory(self, address, value, data_type='float'):
        """
        Write data to memory.
        
        Args:
            address: Memory address to write to
            value: Value to write
            data_type (str): Type of data to write ('float', 'int')
            
        Returns:
            bool: True if write successful, False otherwise
        """
        try:
            if data_type == 'float':
                self.pm.write_float(address, value)
            elif data_type == 'int':
                self.pm.write_int(address, value)
            return True
        except Exception as e:
            print(f"Memory write failed: {e}")
            return False

    def get_hitgroup_multiplier(self, hitgroup):
        """
        Get damage multiplier based on hit group.
        
        Args:
            hitgroup (int): Hit group identifier
            
        Returns:
            float: Damage multiplier for the hit group
        """
        for part, group_id in self.hit_groups.items():
            if group_id == hitgroup:
                return self.damage_multipliers.get(part, 1.0)
        return 1.0

    def enhance_damage(self, damage_address, hitgroup_address):
        """
        Process damage enhancement for hit detection.
        
        Args:
            damage_address: Memory address of damage value
            hitgroup_address: Memory address of hit group
        """
        try:
            # Read original damage value and hit group
            original_damage = self.read_memory(damage_address, 'float')
            hitgroup = self.read_memory(hitgroup_address, 'int')
            
            if original_damage is None or hitgroup is None:
                return
            
            # Get damage multiplier
            multiplier = self.get_hitgroup_multiplier(hitgroup)
            
            # Calculate enhanced damage
            enhanced_damage = original_damage * multiplier
            
            # Write enhanced damage value
            self.write_memory(damage_address, enhanced_damage, 'float')
            
            # Print debug information
            hitgroup_name = [
                k for k, v in self.hit_groups.items() 
                if v == hitgroup
            ]
            hitgroup_name = hitgroup_name[0] if hitgroup_name else f"Unknown({hitgroup})"
            print(
                f"Hit location: {hitgroup_name}, "
                f"Original damage: {original_damage:.1f}, "
                f"Enhanced: {enhanced_damage:.1f} (x{multiplier})"
            )
            
        except Exception as e:
            print(f"Damage enhancement processing failed: {e}")

    def find_damage_address(self):
        """
        Find memory addresses for damage values.
        
        Note: This method needs to be adjusted according to the specific game's memory structure.
        
        Returns:
            tuple: (damage_address, hitgroup_address) or (None, None) if failed
        """
        try:
            # Example: Assuming damage values at fixed offsets
            # Replace with actual base address and offsets
            base_address = self.client_dll + 0x123456  # Replace with actual base address
            damage_offset = 0x123  # Replace with actual damage offset
            hitgroup_offset = 0x124  # Replace with actual hitgroup offset
            
            return base_address + damage_offset, base_address + hitgroup_offset
        except Exception as e:
            print(f"Failed to find damage addresses: {e}")
            return None, None

    def start_enhancement(self):
        """Start the damage enhancement process."""
        if not self.pm:
            print("Please initialize connection first")
            return
        
        damage_address, hitgroup_address = self.find_damage_address()
        if not damage_address or not hitgroup_address:
            print("Unable to find damage addresses")
            return
        
        self.is_running = True
        print("Starting damage enhancement...")
        print("Current damage multiplier configuration:")
        for part, multiplier in self.damage_multipliers.items():
            print(f"  {part}: x{multiplier}")
        
        try:
            while self.is_running:
                self.enhance_damage(damage_address, hitgroup_address)
                time.sleep(0.01)  # 10ms interval to avoid high CPU usage
        except KeyboardInterrupt:
            print("\nEnhancement stopped by user")
        except Exception as e:
            print(f"Enhancement process error: {e}")

    def stop_enhancement(self):
        """Stop the damage enhancement process."""
        self.is_running = False
        print("Damage enhancement stopped")

    def update_multiplier(self, body_part, multiplier):
        """
        Update damage multiplier for specific body part.
        
        Args:
            body_part (str): Body part to update
            multiplier (float): New damage multiplier
        """
        if body_part in self.damage_multipliers:
            self.damage_multipliers[body_part] = multiplier
            print(f"Updated {body_part} damage multiplier to: x{multiplier}")
        else:
            print(f"Unknown body part: {body_part}")

    def show_status(self):
        """Display current enhancement status and configuration."""
        print("Current damage enhancement status:")
        print(f"Running: {'Yes' if self.is_running else 'No'}")
        print("Damage multiplier configuration:")
        for part, multiplier in self.damage_multipliers.items():
            print(f"  {part}: x{multiplier}")


def main():
    """Main function to run the damage enhancement system."""
    enhancer = HitDamageEnhancer()
    
    # Initialize connection
    if not enhancer.initialize():
        return
    
    # Interactive menu
    while True:
        print("\n=== Damage Enhancement System ===")
        print("1. Start damage enhancement")
        print("2. Stop damage enhancement")
        print("3. Modify damage multipliers")
        print("4. Show status")
        print("5. Exit")
        
        choice = input("Please select an option: ").strip()
        
        if choice == '1':
            enhancer.start_enhancement()
        elif choice == '2':
            enhancer.stop_enhancement()
        elif choice == '3':
            print("\nAvailable body parts:")
            for part in enhancer.damage_multipliers.keys():
                print(f"  - {part}")
            body_part = input("Enter body part to modify: ").strip()
            try:
                multiplier = float(input("Enter new damage multiplier: "))
                enhancer.update_multiplier(body_part, multiplier)
            except ValueError:
                print("Please enter a valid number")
        elif choice == '4':
            enhancer.show_status()
        elif choice == '5':
            enhancer.stop_enhancement()
            break
        else:
            print("Invalid selection")


if __name__ == "__main__":
    main()