import os
import re
from collections import defaultdict

# made by Awesome

# Get the main directory path where the tools folder is located
main_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
qsrc_dir = os.path.join(main_dir, "locations")
text_path = main_dir


image_directory = input('Enter the game directory: ')

custom_keywords = input('Enter custom keywords to exclude (separated by comma), or press Enter to skip: ')

# Ensure image_directory ends with a '/'
if not image_directory.endswith('/'):
    image_directory += '/'

# Check if the user entered the images folder path instead of the game directory
if image_directory.lower().endswith('images/'):
    image_directory = os.path.dirname(os.path.dirname(image_directory))

# Remove the 'images' subfolder from image_directory only if it's there
if os.path.basename(image_directory.rstrip('/')).lower() == 'images':
    image_directory = os.path.dirname(image_directory.rstrip('/'))

# Define keywords to exclude from media paths
keywords_to_exclude = ['$pcs_haircol', 'FUNC(', '<<pirs', '$ARGS', '+iif']

if custom_keywords:
    custom_keywords = custom_keywords.split(',')
    keywords_to_exclude += [keyword.strip() for keyword in custom_keywords]

ignore_file = os.path.join(main_dir, 'ignoremedialinks.txt')
ignore_paths = []

# Check if the ignore file exists
if os.path.exists(ignore_file):
    with open(ignore_file, 'r') as f:
        ignore_paths = [line.strip() for line in f]


# Create a list to store missing media (images and videos)
missing_media = []

# Function to evaluate and replace random expressions while preserving existing single quotes or '+' operators
def evaluate_and_replace_random(expression):
    media_paths = []

    # Define a regular expression pattern to find expressions like ' + rand(...) + ' or "'+rand(...)+'" or '<<rand(...)>>'
    rand_pattern = r'(["\']?)\s*([\+\-]?)\s*(<<)?rand\s*\(\s*(\d+)\s*,\s*(\d+)\s*\)(>>)?\s*([\+\-]?)\s*(["\']?)'

    # Find all matching expressions in the input string
    matches = re.finditer(rand_pattern, expression)

    # Initialize the modified expression
    modified_expression = expression

    # Iterate through the matches and replace them
    for match in matches:
        start_quote, start_operator, _, min_value, max_value, _, end_operator, end_quote = match.groups()
        min_value = int(min_value)
        max_value = int(max_value)

        if min_value <= max_value:
            # Generate media paths for each number in the range
            for num in range(min_value, max_value + 1):
                # Create a copy of the modified expression
                temp_expression = modified_expression

                # Replace the 'rand' expression with the current number
                replacement = (start_operator if start_operator else '') + str(num) + (end_operator if end_operator else '')
                if start_quote and start_quote == end_quote:
                    replacement = replacement.strip("'")
                    replacement = replacement.strip("+")

                temp_expression = temp_expression[:match.start()] + replacement + temp_expression[match.end():]
                media_paths.append(temp_expression)

    # If no random evaluations were found, return the original expression
    if not media_paths:
        media_paths = [modified_expression]

    return media_paths

#
def evaluate_and_replace_variables(expression, variables):
    variable_matches = re.findall(r'\'\s*\+\s*(\$?[a-zA-Z_][a-zA-Z0-9_]*)\s*\+\s*\'|<<(\$?[a-zA-Z_][a-zA-Z0-9_]*)>>', expression)
    for variable_match in variable_matches:
        for variable_name in variable_match:
            variable_value = None  # Initialize variable_value to None
            if variable_name:  # Check if the group actually matched something
                if variable_name.startswith("$"):
                    variable_value = variables.get(variable_name[1:], None)
                else:
                    variable_value = variables.get(variable_name, None)
            if isinstance(variable_value, str) and 'rand(' in variable_value:
                # Evaluate the 'rand' function
                variable_value = evaluate_and_replace_random(variable_value)[0]
        if variable_value is None:
            return None
        expression = expression.replace(f"<<{variable_name}>>", str(variable_value))
    return [expression]

# Initialize an empty dictionary to store variable values
variables = {}

# Iterate through .qsrc files in the specified directory and its subdirectories
for file in os.listdir(qsrc_dir):
    if file.endswith(".qsrc"):
        qsrc_file = os.path.join(qsrc_dir, file)

        # Read the .qsrc file
        with open(qsrc_file, "r", encoding="utf-8", errors="ignore") as script_file:
            script_content = script_file.readlines()

        # Initialize a dictionary to store the 'rand' variables and their expressions
        rand_variables = {}

        # Define a regular expression pattern to find 'rand' variable assignments
        rand_assignment_pattern = r'(\$?[a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(rand\(\d+,\s*\d+\))'

        # Iterate through the script content to find and store 'rand' variable assignments
        for line_number, line in enumerate(script_content, start=1):
            matches = re.findall(rand_assignment_pattern, line)
            for match in matches:
                variable_name, rand_expression = match
                rand_variables[variable_name.strip()] = rand_expression.strip()

        # Iterate through each line in the .qsrc file
        for line_number, line in enumerate(script_content, start=1):
            # Check if the line contains a variable assignment
            if "=" in line and "<<" in line and ">>" in line:
                # Find all matches of the regular expression in the line
                matches = re.findall(r'<<(\$?[a-zA-Z_][a-zAZ0-9_]*)>>\s*=\s*([\'"]?[^\'"]+[\'"]?)', line)
                # Check if there are any matches
                if matches:
                    # Split the line into a variable name and value
                    variable_name, variable_value = matches[0]
                    # Check if the variable value contains a 'rand' function
                    if "rand(" in variable_value:
                        # Evaluate the 'rand' function
                        variable_value = evaluate_and_replace_random(variable_value)[0]
                    # Store the variable value in the dictionary with the filename and line number as the key
                    variables[(qsrc_file, line_number)] = {variable_name.strip(): variable_value.strip("'\"")}

            # Use regular expressions to find media references in the script
            if line.strip().startswith('!') or '<<FUNC' in line:
                continue
            media_references = re.findall(r'<(?:img.*?|video.*?)src="([^"]+)"', line)

            for media_reference in media_references:
                if any(keyword in media_reference for keyword in keywords_to_exclude):
                    continue

                # Special rules
                media_reference = media_reference.replace("lover_picrand", 'rand(1, 30)')
                media_reference = media_reference.replace("modelfoto[''debut_image'']+1", 'rand(1, 9)')
                media_reference = media_reference.replace("modelfoto[''debut_image'']+2", 'rand(1, 9)')
                media_reference = media_reference.replace("modelfoto[''debut_image'']", 'rand(1, 9)')
                media_reference = media_reference.replace("VKWoods", 'rand(1, 8)')
                media_reference = media_reference.replace("metrorand['rand']", 'rand(1, 2)')
                media_reference = media_reference.replace("picpRand", 'rand(1, 20)')
                media_reference = media_reference.replace("Doublerand", 'rand(14, 15)')

                # Find the variable assignment that is closest to (but above) the media reference
                relevant_variables = max(((k, v) for k, v in variables.items() if k[0] == qsrc_file and k[1] < line_number), key=lambda item: item[0][1], default=({}, {}))[1]

                # Evaluate variables first
                media_reference = evaluate_and_replace_variables(media_reference, relevant_variables)
                if media_reference is None:
                    continue
                media_reference = media_reference[0]

                # Use regular expression to identify and replace variables set with rand in the image path
                variable_references = re.findall(r'<<(\$?[a-zA-Z_][a-zAZ0-9_]*)>>', media_reference)
                for variable_reference in variable_references:
                    if variable_reference in rand_variables:
                        rand_expression = rand_variables[variable_reference]
                        media_reference = media_reference.replace(f"<<{variable_reference}>>", str(eval(rand_expression)))

                media_paths = evaluate_and_replace_random(media_reference)

                for path in media_paths:
                    if any(keyword in path for keyword in keywords_to_exclude) or path in ignore_paths:
                        continue
                    absolute_path = os.path.join(image_directory, path)

                    # Check if the path is a directory
                    if os.path.isdir(absolute_path) and not os.listdir(absolute_path):
                        missing_media.append((os.path.basename(qsrc_file), path, line_number))

                    elif not os.path.exists(absolute_path):
                        missing_media.append((os.path.basename(qsrc_file), path, line_number))


# Specify the path to the "missing_media.txt" output file
missing_media_file = os.path.join(text_path, "missing_media.txt")

# Convert the list to a set to remove duplicates, then convert it back to a list
missing_media = [i for n, i in enumerate(missing_media) if i not in missing_media[n + 1:]]

# Create a dictionary to store the file name, media path and line numbers
missing_media_dict = defaultdict(list)

for qsrc_file, media_path, line_number in missing_media:
    # Use the file name and media path as the key, and append the line number to the list of values
    missing_media_dict[(qsrc_file, media_path)].append(line_number)

# Write the dictionary to the "missing_media.txt" file
with open(missing_media_file, "w", encoding="utf-8") as file:
    for (qsrc_file, media_path), line_numbers in missing_media_dict.items():
        # Join the line numbers with commas
        line_numbers_str = ", ".join(map(str, line_numbers))
        file.write(f"From file: {qsrc_file}, lines: {line_numbers_str}\n")  # Write the .qsrc filename and line numbers
        file.write(f"{media_path}\n\n")  # Write the full media path and start a new line
    file.write(f"\nTotal missing media files: {len(missing_media_dict)}\n")  # Write the count of missing media files at the end of the file
    file.write(f"this amazing script was made by Awesome (with help from chatGPT)\n")  # Bragging

print(f"{len(missing_media_dict)} Missing media files have been saved to 'missing_media.txt'.")
pause = input("Press Enter to exit.")

