import csv
import xml.etree.ElementTree as ET
import os
import uuid  # Import the uuid module
from lxml import etree  # Import lxml for XML handling
from xml.dom import minidom
import msvcrt

# Function to convert timecode (HH:MM:SS:FF) to total frames based on the fps
def timecode_to_frames(timecode, fps=60):
    """Convert a timecode (HH:MM:SS:FF) to total frames based on the fps."""
    try:
        h, m, s, f = map(int, timecode.split(':'))  # Split into hours, minutes, seconds, and frames
        return (h * 3600 + m * 60 + s) * fps + f  # Convert to frames
    except ValueError:
        print(f"Invalid timecode: {timecode}")
        return 0  # Return 0 or handle error as appropriate

# Define marker colors
    # pproColor keys:
        # default/blank/invalid = Green 
        # "4281740498" # Red
        # "4289825711" # Purple
        # "4280578025" # Orange
        # "4281049552" # Yellow
        # "4294967295" # White
        # "4294741314" # Blue
        # "4292277273" # Turquoise 
marker_colors = {
    "FUNI": "4294741314",   # Blue
    "SEG": "4280578025",    # Orange
    "gamign": "4289825711", # Purple
    "env": "4289825711",    # Purple
    "AFK": "4281049552",    # Yellow
    "UNAFK": "4281049552",  # Yellow
    "BEGIN": "4281049552",  # Yellow
    "END": "4281049552"     # Yellow
}

# Get a list of all CSV files in the current directory
csv_files = [f for f in os.listdir('.') if f.endswith('.csv')]

for csv_file in csv_files:
    print(f"Processing '{csv_file}'...")

    # Extract base name for sequence name
    video_base = os.path.splitext(csv_file)[0]
    sequence_name = f"{video_base}"

    # Function to generate the XML structure
    def generate_xml(markers, duration, sequence_name):
        # Create the root <xmeml> element
        xmeml = ET.Element("xmeml", version="4")

        # Create the <sequence> element
        sequence = ET.SubElement(xmeml, "sequence", id="sequence")
        # Manually add the attributes with dots
        sequence.set("TL.SQAudioVisibleBase", "0")
        sequence.set("TL.SQVideoVisibleBase", "0")
        sequence.set("TL.SQVisibleBaseTime", "0")
        sequence.set("TL.SQAVDividerPosition", "0.5")
        sequence.set("TL.SQHideShyTracks", "0")
        sequence.set("TL.SQHeaderWidth", "292")
        sequence.set("Monitor.ProgramZoomOut", "0")
        sequence.set("Monitor.ProgramZoomIn", "0")
        sequence.set("TL.SQTimePerPixel", "0.19999999999999998")
        sequence.set("MZ.EditLine", "0")
        sequence.set("MZ.Sequence.PreviewFrameSizeHeight", "1080")
        sequence.set("MZ.Sequence.PreviewFrameSizeWidth", "1920")
        sequence.set("MZ.Sequence.AudioTimeDisplayFormat", "200")
        sequence.set("MZ.Sequence.PreviewRenderingClassID", "1061109567")
        sequence.set("MZ.Sequence.PreviewRenderingPresetCodec", "1634755439")
        sequence.set("MZ.Sequence.PreviewRenderingPresetPath", "EncoderPresets/SequencePreview/795454d9-d3c2-429d-9474-923ab13b7018/QuickTime.epr")
        sequence.set("MZ.Sequence.PreviewUseMaxRenderQuality", "false")
        sequence.set("MZ.Sequence.PreviewUseMaxBitDepth", "false")
        sequence.set("MZ.Sequence.EditingModeGUID", "795454d9-d3c2-429d-9474-923ab13b7018")
        sequence.set("MZ.Sequence.VideoTimeDisplayFormat", "101")
        sequence.set("MZ.WorkOutPoint", "4612930560000")
        sequence.set("MZ.WorkInPoint", "0")
        sequence.set("explodedTracks", "true")

        # Generate a unique UUID and set it in the sequence element
        uuid_val = str(uuid.uuid4()).replace('-', '')  # Generate a unique UUID without dashes
        ET.SubElement(sequence, "uuid").text = uuid_val
        
        # Set the duration right after the UUID
        duration_tag = ET.SubElement(sequence, "duration")
        duration_tag.text = str(duration)

        # Add rate (timebase and ntsc)
        rate = ET.SubElement(sequence, "rate")
        timebase = ET.SubElement(rate, "timebase")
        timebase.text = "60"
        ntsc = ET.SubElement(rate, "ntsc")
        ntsc.text = "FALSE"
        
        # Set sequence name
        name = ET.SubElement(sequence, "name")
        name.text = sequence_name
        
        # Create media section
        media = ET.SubElement(sequence, "media")
        video = ET.SubElement(media, "video")
        format_tag = ET.SubElement(video, "format")
        samplecharacteristics = ET.SubElement(format_tag, "samplecharacteristics")

        # Now let's add a rate and other information under samplecharacteristics (to make it meaningful)
        rate = ET.SubElement(samplecharacteristics, "rate")
        timebase = ET.SubElement(rate, "timebase")
        timebase.text = "60"
        ntsc = ET.SubElement(rate, "ntsc")
        ntsc.text = "FALSE"

        # Add codec information
        codec = ET.SubElement(samplecharacteristics, "codec")
        name = ET.SubElement(codec, "name")
        name.text = "Apple ProRes 422"
        appspecificdata = ET.SubElement(codec, "appspecificdata")
        appname = ET.SubElement(appspecificdata, "appname")
        appname.text = "Final Cut Pro"
        appmanufacturer = ET.SubElement(appspecificdata, "appmanufacturer")
        appmanufacturer.text = "Apple Inc."
        appversion = ET.SubElement(appspecificdata, "appversion")
        appversion.text = "7.0"
        data = ET.SubElement(appspecificdata, "data")
        qtcodec = ET.SubElement(data, "qtcodec")
        codecname1 = ET.SubElement(qtcodec, "codecname")
        codecname1.text = "Apple ProRes 422"
        codectypename = ET.SubElement(qtcodec, "codectypename")
        codectypename.text = "Apple ProRes 422"
        codecname2 = ET.SubElement(qtcodec, "codecname")
        codecname2.text = "Apple ProRes 422"
        codectypecode = ET.SubElement(qtcodec, "codectypecode")
        codectypecode.text = "apcn"
        codecvendorcode = ET.SubElement(qtcodec, "codecvendorcode")
        codecvendorcode.text = "appl"
        spatialquality = ET.SubElement(qtcodec, "spatialquality")
        spatialquality.text = "1024"
        temporalquality = ET.SubElement(qtcodec, "temporalquality")
        temporalquality.text = "0"
        keyframerate = ET.SubElement(qtcodec, "keyframerate")
        keyframerate.text = "0"
        datarate = ET.SubElement(qtcodec, "datarate")
        datarate.text = "0"
        
        # Add dimension info
        width = ET.SubElement(samplecharacteristics, "width")
        width.text = "1920"
        height = ET.SubElement(samplecharacteristics, "height")
        height.text = "1080"
        anamorphic = ET.SubElement(samplecharacteristics, "anamorphic")
        anamorphic.text = "FALSE"
        pixelaspectratio = ET.SubElement(samplecharacteristics, "pixelaspectratio")
        pixelaspectratio.text = "square"
        fielddominance = ET.SubElement(samplecharacteristics, "fielddominance")
        fielddominance.text = "none"
        colordepth = ET.SubElement(samplecharacteristics, "colordepth")
        colordepth.text = "24"

        # Create the <track> element
        track = ET.SubElement(video, "track")
        track.set("TL.SQTrackShy", "0")
        track.set("TL.SQTrackExpandedHeight", "25")
        track.set("TL.SQTrackExpanded", "0")
        track.set("MZ.TrackTargeted", "0")
        
        #Add track modifiers
        enabled = ET.SubElement(track, "enabled")
        enabled.text = "TRUE"
        locked = ET.SubElement(track, "locked")
        locked.text = "FALSE"

        # Add generator item (matte)
        generatoritem = ET.SubElement(track, "generatoritem", id="clipitem-1")
        item_name = ET.SubElement(generatoritem, "name")
        item_name.text = f"Marker Color Matte ({markers[0]['time']})"
        enabled = ET.SubElement(generatoritem, "enabled")
        enabled.text = "TRUE"
        generatoritem_duration = ET.SubElement(generatoritem, "duration")
        generatoritem_duration.text = str(duration)
        rate = ET.SubElement(generatoritem, "rate")
        timebase = ET.SubElement(rate, "timebase")
        timebase.text = "60"
        ntsc = ET.SubElement(rate, "ntsc")
        ntsc.text = "FALSE"
        start = ET.SubElement(generatoritem, "start")
        start.text = "0"
        end = ET.SubElement(generatoritem, "end")
        end.text = str(duration)
        in_time = ET.SubElement(generatoritem, "in")
        in_time.text = "0"
        out_time = ET.SubElement(generatoritem, "out")
        out_time.text = str(duration)
        alphatype = ET.SubElement(generatoritem, "alphatype")
        alphatype.text = "none"
        effect = ET.SubElement(generatoritem, "effect")
        effect_name = ET.SubElement(effect, "name")
        effect_name.text = "Color"
        effectid = ET.SubElement(effect, "effectid")
        effectid.text = "Color"
        effectcategory = ET.SubElement(effect, "effectcategory")
        effectcategory.text = "Matte"
        effecttype = ET.SubElement(effect, "effecttype")
        effecttype.text = "generator"
        mediatype = ET.SubElement(effect, "mediatype")
        mediatype.text = "video"
        parameter = ET.SubElement(effect, "parameter", authoringApp="PremierePro")
        parameterid = ET.SubElement(parameter, "parameterid")
        parameterid.text = "fillcolor"
        param_name = ET.SubElement(parameter, "name")
        param_name.text = "Color"
        value = ET.SubElement(parameter, "value")
        alpha = ET.SubElement(value, "alpha")
        alpha.text = "0"
        red = ET.SubElement(value, "red")
        red.text = "0"
        green = ET.SubElement(value, "green")
        green.text = "0"
        blue = ET.SubElement(value, "blue")
        blue.text = "0"
        filter_tag = ET.SubElement(generatoritem, "filter")
        filter_effect = ET.SubElement(filter_tag, "effect")
        filter_effect_name = ET.SubElement(filter_effect, "name")
        filter_effect_name.text = "Opacity"
        filter_effectid = ET.SubElement(filter_effect, "effectid")
        filter_effectid.text = "opacity"
        filter_effectcategory = ET.SubElement(filter_effect, "effectcategory")
        filter_effectcategory.text = "motion"
        filter_effecttype = ET.SubElement(filter_effect, "effecttype")
        filter_effecttype.text = "motion"
        filter_mediatype = ET.SubElement(filter_effect, "mediatype")
        filter_mediatype.text = "video"
        pproBypass = ET.SubElement(filter_effect, "pproBypass")
        pproBypass.text = "false"
        filter_parameter = ET.SubElement(filter_effect, "parameter", authoringApp="PremierePro")
        filter_parameterid = ET.SubElement(filter_parameter, "parameterid")
        filter_parameterid.text = "opacity"
        filter_param_name = ET.SubElement(filter_parameter, "name")
        filter_param_name.text = "opacity"
        filter_valuemin = ET.SubElement(filter_parameter, "valuemin")
        filter_valuemin.text = "0"
        filter_valuemax = ET.SubElement(filter_parameter, "valuemax")
        filter_valuemax.text = "100"
        filter_value = ET.SubElement(filter_parameter, "value")
        filter_value.text = "0"

        # Create the <audio> element and its children
        audio = ET.SubElement(media, "audio")
        ET.SubElement(audio, "numOutputChannels").text = "2"
        format_elem = ET.SubElement(audio, "format")
        samplecharacteristics = ET.SubElement(format_elem, "samplecharacteristics")
        ET.SubElement(samplecharacteristics, "depth").text = "16"
        ET.SubElement(samplecharacteristics, "samplerate").text = "48000"
        outputs = ET.SubElement(audio, "outputs")
        for i in range(1, 3):
            group = ET.SubElement(outputs, "groups")
            ET.SubElement(group, "index").text = str(i)
            ET.SubElement(group, "numchannels").text = "1"
            ET.SubElement(group, "downmix").text = "0"
            channel = ET.SubElement(group, "channel")
            ET.SubElement(channel, "index").text = str(i)
        for i in range(1, 9):
            track = ET.SubElement(audio, "track")
            track.set("TL.SQTrackAudioKeyframeStyle", "0")
            track.set("TL.SQTrackShy", "0")
            track.set("TL.SQTrackExpandedHeight", "25")
            track.set("TL.SQTrackExpanded", "0")
            track.set("MZ.TrackTargeted", "1")     
            track.set("PannerCurrentValue", "0.5")
            track.set("PannerIsInverted", "true")
            track.set("PannerStartKeyframe", "-91445760000000000,0.5,0,0,0,0,0,0")
            track.set("PannerName", "Balance")
            track.set("currentExplodedTrackIndex", "0")
            track.set("totalExplodedTrackCount", "2")
            track.set("premiereTrackType", "Stereo")                        
            ET.SubElement(track, "enabled").text = "TRUE"
            ET.SubElement(track, "locked").text = "FALSE"
            ET.SubElement(track, "outputchannelindex").text = str((i-1) % 2 + 1)

        # Create the timecode section under sequence
        timecode = ET.SubElement(sequence, "timecode")
        rate = ET.SubElement(timecode, "rate")
        ET.SubElement(rate, "timebase").text = "60"
        ET.SubElement(rate, "ntsc").text = "FALSE"
        ET.SubElement(timecode, "string").text = "00:00:00:00"
        ET.SubElement(timecode, "frame").text = "0"
        ET.SubElement(timecode, "displayformat").text = "NDF"

        # Create the labels section under sequence
        labels = ET.SubElement(sequence, "labels")
        ET.SubElement(labels, "label2").text = "Iris"

        # Create the logginginfo section under sequence
        logginginfo = ET.SubElement(sequence, "logginginfo")
        ET.SubElement(logginginfo, "description")
        ET.SubElement(logginginfo, "scene")
        ET.SubElement(logginginfo, "shottake")
        ET.SubElement(logginginfo, "lognote")
        ET.SubElement(logginginfo, "good")
        ET.SubElement(logginginfo, "originalvideofilename")
        ET.SubElement(logginginfo, "originalaudiofilename")

        # Add markers again but under sequence
        for marker in markers:
            marker_element = ET.SubElement(sequence, "marker")
            ET.SubElement(marker_element, "comment")
            ET.SubElement(marker_element, "name").text = marker['name']
            # Set the in and out time as the frame count
            in_frame = str(timecode_to_frames(marker['time']))
            ET.SubElement(marker_element, "in").text = in_frame
            ET.SubElement(marker_element, "out").text = "-1"
            # Set color based on marker name
            color_code = marker_colors.get(marker['name'])
            if color_code:
                ppro_color = ET.SubElement(marker_element, "pproColor")
                ppro_color.text = color_code
                print(f"Set color for marker '{marker['name']}' to '{color_code}'")
            else:
                print(f"Default color (Green) used for marker '{marker['name']}'")

        # Create the labels section under sequence
        labels = ET.SubElement(sequence, "labels")
        ET.SubElement(labels, "label2").text = "Forest"

        # Write to XML file
        output_file = csv_file.replace('.csv', '.xml')
        tree = ET.ElementTree(xmeml)
        tree.write(output_file, encoding="UTF-8", xml_declaration=True)

        print(f"XML file '{output_file}' has been created successfully.")


    # Read the CSV file and process the data
    markers = []  # List to store markers

    with open(csv_file, newline='', encoding='utf-8') as csvfile:
        csv_reader = csv.DictReader(csvfile, delimiter='\t')
        marker_count = 0

        for row in csv_reader:
            marker_name = row['Marker Name']
            in_point = row['In']
            out_point = row['Out']

            print(f"Adding marker: Name='{marker_name}', In='{in_point}', Out='{out_point}'")

            # Add marker to list
            markers.append({'name': marker_name, 'time': in_point})
            marker_count += 1

        print(f"Total markers added for '{csv_file}': {marker_count}")

        # Calculate the duration using the final marker's timecode
        final_marker = markers[-1] if markers else None
        duration = 0
        if final_marker:
            duration = timecode_to_frames(final_marker['time'], fps=60)

        generate_xml(markers, duration, sequence_name)  # Pass sequence_name

    print("------------------------------------------------------------")

print("All files have been processed.")
print("Press any key to exit...")
msvcrt.getch()