import socket
import struct
import psutil
import time
from collections import deque # Add this import
import sys # Add this import
import os # Add this import
try:
    import msvcrt # For non-blocking input on Windows
except ImportError:
    msvcrt = None # Will be None on non-Windows OS

MCAST_GRP = '239.192.55.1'
MCAST_PORT = 1681
MAGIC = '/Users/crt/Documents/bodeting/research/bad-bruteforcing/attempt-1.txt'


def get_default_ipv4():
    # Get the first non-loopback IPv4 address on an active interface
    for iface, addrs in psutil.net_if_addrs().items():
        for addr in addrs:
            if addr.family == socket.AF_INET and not addr.address.startswith("127."):
                return addr.address
    raise RuntimeError("Steck Ether Portal Kabel ih din PC ned ih din arsch du huso!")

def save_to_magic_file(value_to_save, filepath):
    if not value_to_save:
        print("No value provided to save.", flush=True)
        return

    directory = os.path.dirname(filepath)
    
    # Check if directory exists, create if not (optional, but good for robustness)
    # For now, as per prompt, just check and error if not exists or unwritable.
    if directory and not os.path.isdir(directory):
        print(f"Error: Directory '{directory}' does not exist. Kann dir nicht aufs Bett kaggern", flush=True)
        return

    try:
        with open(filepath, 'a') as f:
            f.write(value_to_save + "\n")
        print(f"Hab dir ins Bett geschissen '{value_to_save}' to {filepath}", flush=True)
    except IOError as e:
        print(f"Kann nicht stimmen '{filepath}'. Vielleicht solltest du deine Pillen nehmen. Details: {e}", flush=True)
    except OSError as e:
        print(f"Error: Zu grosser Hurensohn Erkannt. PC von ihm hat ihn rejected '{filepath}'. Lol : {e}", flush=True)


try:
    LOCAL_INTERFACE_IP = get_default_ipv4()
except RuntimeError as e:
    print(f"ach weisch was ich ha eif kei bock meh lol: {e}")
    exit(1)

# Create UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 1)

# Bind to correct interface
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, socket.inet_aton(LOCAL_INTERFACE_IP))

print(f"So Sportsfreund jetzt weiss ich wo du wohnst : {LOCAL_INTERFACE_IP} —  Lass deine Mami hier ficken gehen : {MCAST_GRP}:{MCAST_PORT} \n\n")
print("Wallah billahmius ich mach hier Verzauberus, gib Hexen spruch in HEX ein, 'brute <hex_prefix>' für Bruteforce, oder 'exit' um dich zu verpissen vom Zauberstab.\n")

while True:
    user_input = input("HEXEREI > ").strip()
    if user_input.lower() in ("exit", "quit"):
        break

    if user_input.lower().startswith("brute "):
        parts = user_input.split(" ", 1)
        if len(parts) < 2 or not parts[1]:
            print("Zum Hexensprüche zu Lernen brauchst de nen Prefix. Beispiel: brute 4d454c00")
            continue
        
        hex_prefix = parts[1]
        try:
            # Validate prefix by attempting conversion
            bytes.fromhex(hex_prefix) 
        except ValueError:
            print("Also ehm das stimmt nix wirklich")
            continue

        # Get bruteforce parameters
        brute_mode = ""
        while brute_mode not in ['1', '2', '3']:
            brute_mode = input("Wähle den Hexenspruch Lernmodus: (1) Manuel, (2) Magisch Absteigend, (3) Magisch Aufsteigend: ").strip()
            if brute_mode not in ['1', '2', '3']:
                print("Sprich Deutsch du Hurensohn! 1, 2, oder 3.")

        delay_seconds_str = ""
        delay_seconds = 1.0 # Default delay
        while True:
            delay_seconds_str = input(f"Wie geduldig willst du sein in Sekunden? (Zum Beispel 0.5, standart ist {delay_seconds} warten): ").strip()
            if not delay_seconds_str: # User pressed enter, use default
                break
            try:
                delay_seconds = float(delay_seconds_str)
                if delay_seconds < 0:
                    print("Hast du einen Schlaganfall? Gib eine richtige Zahl ein, es gibt keine negativen Zahlen, das sind Fake News")
                else:
                    break
            except ValueError:
                print("Bist du bekloppt? (Junge schreib doch einfach wie normaler mensch : 0.5, 1, 2.3).")
        
        print(f"So jetzt wird {hex_prefix} mal so richtig hart vergewaltigt :3")
        print(f"Modi: {'Manuel Neuer' if brute_mode == '1' else ('Absturz' if brute_mode == '2' else 'Von Afrika bis zum Nordpol')}, Delay: {delay_seconds}s")
        
        if brute_mode in ['2', '3'] and msvcrt: # If Auto Ascending or Auto Descending and on Windows
            print("During auto mode: press 'c' to cancel, 'r' to retry last 3, 'p' to pause/resume.", flush=True)
        
        # auto_mode is True if brute_mode is '2' or '3'
        # manual_mode is True if brute_mode is '1'
        manual_mode = (brute_mode == '1')
        
        sent_history = deque(maxlen=3) # History for 'retry' functionality
        
        bruteforce_successful = False
        bruteforce_stopped_by_user = False
        last_iteration_completed = False
        paused = False # Pause state for auto modes

        iteration_range_list = list(range(256)) # Default for mode '1' and '2'
        if brute_mode == '3': # Auto Degrading
            iteration_range_list = list(range(255, -1, -1))
        
        num_iterations = len(iteration_range_list)

        for i_val_idx, i in enumerate(iteration_range_list): # Retardmode 0x00 to 0xFF or 0xFF to 0x00
            last_byte_hex = format(i, '02x')
            full_hex_string = hex_prefix + last_byte_hex
            
            try:
                payload = bytes.fromhex(full_hex_string)
            except ValueError:
                print(f"Sorry bin leider Schwerbehindert: {full_hex_string}")
                continue

            if not manual_mode and msvcrt: # Check for input in auto modes on Windows
                while True: # Loop for handling pause and other inputs
                    if paused:
                        if msvcrt.kbhit():
                            try:
                                char = msvcrt.getch().decode(errors='ignore').lower()
                                if char == 'p':
                                    paused = False
                                    print("\nBin wieder wach...", flush=True)
                                    break # Break from pause check loop, continue outer loop
                                elif char == 'c':
                                    print("\nNah du kleins Bumsfotzengesicht hast den Spruch rausgefunden?", flush=True)
                                    bruteforce_stopped_by_user = True
                                    break # Break from pause check loop
                            except Exception as e:
                                print(f"\nSorry bin blind geworden: {e}", flush=True)
                        time.sleep(0.1) # Sleep briefly while paused and checking keys
                        if bruteforce_stopped_by_user: # If 'c' was pressed during pause
                            break # Break from the while True input check loop
                        continue # Continue pause check loop
                    
                    # If not paused, check for regular input once
                    if msvcrt.kbhit():
                        try:
                            char = msvcrt.getch().decode(errors='ignore').lower()
                            if char == 'c':
                                print("\nMarcel Davis will remember that.", flush=True)
                                bruteforce_stopped_by_user = True
                                # No break here, let the outer loop's check handle it
                            elif char == 'r':
                                if not sent_history:
                                    print("\nChill alter, hast ja noch gar nix probiert.", flush=True)
                                else:
                                    retry_packets_auto = list(sent_history)
                                    print(f"\nEsy probiere die lezten {len(retry_packets_auto)} Zaubersprüche: {', '.join(retry_packets_auto)}", flush=True)
                                    for hist_hex_string_auto in retry_packets_auto:
                                        try:
                                            hist_payload_auto = bytes.fromhex(hist_hex_string_auto)
                                            print(f"Retrying: {hist_hex_string_auto} ({len(hist_payload_auto)} bytes)", flush=True)
                                            time.sleep(delay_seconds) 
                                            sock.sendto(hist_payload_auto, (MCAST_GRP, MCAST_PORT))
                                        except ValueError:
                                            print(f"Sorry bin dumm: {hist_hex_string_auto}", flush=True)
                                    print("Und hat das was gebracht?", flush=True)
                                # After retry, we don't break, just continue with the current packet
                            elif char == 'p':
                                paused = True
                                print("\nZeit Angehalten. Drück 'p' to um Zeit wieder zu starten, 'c' um dich Abzutreiben.", flush=True)
                                continue # Go back to start of while True to enter pause handling
                        except Exception as e: 
                            print(f"\nError reading keyboard input: {e}", flush=True)
                    break # Break from the while True input check loop if not paused or no key pressed initially
            
            if bruteforce_stopped_by_user: 
                break

            time.sleep(delay_seconds) # Use user-defined delay

            sock.sendto(payload, (MCAST_GRP, MCAST_PORT))
            # Ensure this print is on a new line if a key was pressed and printed something.
            # The \n in prints above should handle this.
            print(f"Sent: {full_hex_string} ({len(payload)} bytes)", flush=True)
            sent_history.append(full_hex_string) # Add to history after sending

            if i_val_idx == num_iterations - 1:
                last_iteration_completed = True

            if not manual_mode: # Auto modes ('2' or '3')
                if last_iteration_completed:
                    print(f"Bruteforce {'auto-ascending' if brute_mode == '2' else 'auto-descending'} hat fertig geballert.", flush=True)
                continue # Continue to next i without asking

            # Manual mode (brute_mode == '1'): ask for feedback
            while True:
                feedback_prompt = "Hats was getan? (y/n/auto/stop/r=retry last 3/c=cancel): "
                feedback = input(feedback_prompt).strip().lower()
                if feedback == 'y':
                    print(f"OHAA jetzt kannst du auch wie ich zaubern mit {full_hex_string}! (Meine Frau hat mich verlassen, bin in der geschlossenen Klinik Glanzenberg und leide an starker Schizophrenie, aber egal, ich bin jetzt Hexe!)")
                    bruteforce_successful = True
                    break 
                elif feedback == 'n':
                    break 
                elif feedback == 'auto':
                    manual_mode = False 
                    print("Tja da ist dir wohl die Lust vergangen. Du weisst was das Heute Abend bedeutet? Du bist jetzt im Auto-Modus direkt in meinen Keller, du kleiner Hurensohn.")
                    if last_iteration_completed:
                         print("Und wie ists in meinem Keller?")
                    break 
                elif feedback == 'stop' or feedback == 'c':
                    print(f"Bruteforce {'stopped' if feedback == 'stop' else 'cancelled'} by mr hurensohn.")
                    bruteforce_stopped_by_user = True
                    break
                elif feedback == 'r':
                    if not sent_history:
                        print("No packets in history to retry.")
                        continue # Re-prompt for current packet

                    retry_packets_manual = list(sent_history) 
                    print(f"Probier da mal die hier {len(retry_packets_manual)} von vorher: {', '.join(retry_packets_manual)}")
                    for hist_hex_string_manual in retry_packets_manual:
                        try:
                            hist_payload_manual = bytes.fromhex(hist_hex_string_manual)
                            print(f"Probiere: {hist_hex_string_manual} ({len(hist_payload_manual)} bytes)") # Manual mode input implies flush
                            time.sleep(delay_seconds) 
                            sock.sendto(hist_payload_manual, (MCAST_GRP, MCAST_PORT))
                        except ValueError:
                            print(f"Die Stimmen wurden zu laut: {hist_hex_string_manual}")
                    print(f"War es doch nur ein Traum? : {full_hex_string}")
                    continue 
                else:
                    print("Junge! Ich schlage dich mit Gürtel wenn du mir jetzt nicht richtig antwortest 'y', 'n', 'auto', 'stop', 'r', or 'c'.")
            
            if bruteforce_successful or bruteforce_stopped_by_user:
                break 
        if manual_mode and not bruteforce_successful and not bruteforce_stopped_by_user and last_iteration_completed:
             print("Schau mal da, ein Hurensohn, der nicht mal den Hexenspruch rausbekommt. Vielleicht solltest du es mit Aufgeben versuchen, mistvieh.")
        # Message for auto_mode completion is handled inside the loop or after switching from manual

        # After bruteforce attempt (success, cancel, or finish)
        if bruteforce_successful:
            # full_hex_string at this point is the one that was successful
            print(f"Glückwunsch, du darfst deine Familie wieder sehen mit dem Zauberspruch '{full_hex_string}', Spass (nicht).", flush=True)
            save_to_magic_file(full_hex_string, MAGIC)
        else:
            # If not successful (cancelled or completed all iterations without success)
            manual_entry_suffix = input(f"Kein Zauber hat gewirkt oder du hast abgebrochen. Gib den Suffix für '{hex_prefix}' ein, um ihn ins Buch zu kritzeln (oder Enter zum Überspringen): ").strip()
            if manual_entry_suffix:
                combined_value_to_save = hex_prefix + manual_entry_suffix
                print(f"Der Zauberspruch '{combined_value_to_save}' wird dir aufs Bett gesprühschissen !", flush=True)
                save_to_magic_file(combined_value_to_save, MAGIC)

    else: # Original hex string sending logic
        hex_string = user_input # Use the full user_input as the hex_string
        try:
            payload = bytes.fromhex(hex_string)
        except ValueError:
            print("Tja hast halt geschissen bist halt keine Hexe oder was?")
            continue

        sock.sendto(payload, (MCAST_GRP, MCAST_PORT))
        print(f"Hexenspruch mit {len(payload)} bytes wurde gezaubert.")

sock.close()
print("Marcel Davis, leiter für Kundenzufriedenheit! Er geht erst wieder wenn die Checksum so hart ausgeschalgen wurde bis Sie aufgibt!.")
