import bpy
import random

# Constants defining the range of random frames for camera switch
SWITCH_TIME_MIN = 12  # Minimum number of frames before changing the active camera
SWITCH_TIME_MAX = 24  # Maximum number of frames before changing the active camera

# Configuration constants
CAMERAS_COLLECTION = "Cameras"  # Default camera collection to use
DEFAULT_AUDIO_CHANNEL = 4  # Default channel for audio in Video Sequencer
SOUND_PATH = "/home/mike/Desktop/sound-synth/audio/click.wav"  # Path to the audio file


def remove_camera_markers(collection_name="Cameras"):
    """
    Removes markers related to cameras found in a specific collection.

    Args:
    - collection_name: The name of the collection from which cameras are considered (default "Cameras").
    """
    # Check if the collection exists
    if collection_name not in bpy.data.collections:
        print(f"Collection named {collection_name} not found.")
        return

    # Retrieve camera objects from the collection
    camera_objs = [obj for obj in bpy.data.collections[collection_name].objects if obj.type == 'CAMERA']

    # Filter out markers associated with these cameras
    markers_to_remove = [marker for marker in bpy.context.scene.timeline_markers if marker.camera in camera_objs]

    # Remove the filtered markers
    for marker in markers_to_remove:
        bpy.context.scene.timeline_markers.remove(marker)


def set_random_camera_marker(collection_name="Cameras", frame_number=10):
    """
    Sets a marker for a randomly selected camera from the given collection at the specified frame.

    Args:
    - collection_name: The name of the collection from which we want to select a camera (default "Cameras").
    - frame_number: The frame at which we want to place the marker (default 10).
    """
    # Check if the collection exists
    if collection_name in bpy.data.collections:
        # Retrieve camera objects from the collection
        cameras = [obj for obj in bpy.data.collections[collection_name].objects if obj.type == 'CAMERA']

        # If there are cameras in the collection
        if cameras:
            # If current scene's camera is in the list and there's more than one camera, remove it
            if bpy.context.scene.camera in cameras and len(cameras) > 1:
                cameras.remove(bpy.context.scene.camera)

            # Randomly select a camera
            chosen_camera = random.choice(cameras)
            # Set the chosen camera as the scene's active camera
            bpy.context.scene.camera = chosen_camera

            # Set the camera as the active object
            bpy.context.view_layer.objects.active = chosen_camera
            # Deselect all objects in the scene
            bpy.ops.object.select_all(action='DESELECT')
            # Select the chosen camera
            chosen_camera.select_set(True)

            # Create a new marker at the specified frame, associated with the chosen camera
            marker = bpy.context.scene.timeline_markers.new(name="CameraMarker", frame=frame_number)
            marker.camera = chosen_camera

            print(f"Set marker for camera {chosen_camera.name} at frame {frame_number}.")
        else:
            print("No cameras found in the collection.")
    else:
        print(f"Collection named {collection_name} not found.")


def add_sound_to_channel(sound_name, sound_path, channel_num, frame_num):
    """
    Adds a sound to the sequencer on a specified channel.

    Args:
    - sound_name: Name for the sound sequence.
    - sound_path: Path to the sound file.
    - channel_num: The channel number where the sound will be placed.
    - frame_num: The frame where the sound starts.
    """
    # Ensure the sequence editor exists in the current scene
    sequence_editor = bpy.context.scene.sequence_editor_create()

    # Add the sound to the specified channel and frame
    sequence = sequence_editor.sequences.new_sound(sound_name, sound_path, channel_num, frame_num)
    return sequence


def remove_sounds_from_channel(channel_num):
    """
    Remove all sound sequences from a specified channel in the sequencer.

    Args:
    - channel_num: The channel number from which to remove sound sequences.
    """
    sequence_editor = bpy.context.scene.sequence_editor
    if not sequence_editor:
        return

    # Filter out sound sequences in the specified channel
    sequences_to_remove = [seq for seq in sequence_editor.sequences if seq.type == 'SOUND' and seq.channel == channel_num]

    # Remove the filtered sound sequences
    for seq in sequences_to_remove:
        sequence_editor.sequences.remove(seq)


# Remove all camera markers from the specified collection
remove_camera_markers(CAMERAS_COLLECTION)

# Remove all sounds from the default audio channel
remove_sounds_from_channel(DEFAULT_AUDIO_CHANNEL)

# Main loop for camera switch and sound addition
current_frame = bpy.context.scene.frame_start

while current_frame <= bpy.context.scene.frame_end:
    # Set a new marker for the animation with a newly chosen camera
    set_random_camera_marker(CAMERAS_COLLECTION, current_frame)
    
    # Add a sound to signify the camera switch
    add_sound_to_channel("SoundClip", SOUND_PATH, DEFAULT_AUDIO_CHANNEL, current_frame)
    
    # Move to the next frame based on the randomized switch time
    current_frame += random.randint(SWITCH_TIME_MIN, SWITCH_TIME_MAX)
