-- Rykord - ImGUI Media Explorer
-- Currently supports: wav, aiff, mp3, png, rpp and mp4

-- Drag And Drop Functionality
-- set focus to main window -- done
-- add a new track -- done
-- insert item to new track -- done
-- move item to position under mouse cursor -- done
-- move item to track under mouse cursor -- done
-- delete created track -- done
-- change "reaproject" variable to the current project

-- notes:
-- see if i need to focus on the main window
-- check if i can snap the items to the grid -- done

-- TODO:
-- "elseif directory_contains_matching_files(full_path) and enter_pressed then create_directory_tree(full_path, depth + 1)" is slowing down the script a lot. i want it to work


local current_preview = nil
local search_query = ""
local last_search_query = ""
local search_cache = {}
local debounce_timer = 0
local drop_file = 0
local filter_enabled = {
    wav = true, mp3 = true, mp4 = true, png = true, rpp = true, aiff = true,
    vst2 = false, vst3 = false, clap = false, jsfx = false, midi = false
}

function directory_contains_matching_files(path)
    if search_cache[path] ~= nil then
        return search_cache[path]
    end

    local idx = 0
    local contains_matches = false
    while true do
        local file = reaper.EnumerateFiles(path, idx)
        if not file then break end

        if not file:match("^%.") then
            local ext = file:match("^.+(%..+)$")
            if ext then
                ext = ext:sub(2)
                if filter_enabled[ext] and (search_query == "" or file:lower():find(search_query:lower(), 1, true)) then
                    contains_matches = true
                    break
                end
            end
        end

        idx = idx + 1
    end

    if not contains_matches then
        idx = 0
        while true do
            local subdir = reaper.EnumerateSubdirectories(path, idx)
            if not subdir then break end

            if not subdir:match("^%.") then
                local full_path = path .. "/" .. subdir
                if directory_contains_matching_files(full_path) then
                    contains_matches = true
                    break
                end
            end

            idx = idx + 1
        end
    end

    search_cache[path] = contains_matches
    return contains_matches
end

function create_directory_tree(path, depth)
    if depth > 10 then return end

    local idx = 0
    while true do
        local subdir = reaper.EnumerateSubdirectories(path, idx)
        if not subdir then break end

        if not subdir:match("^%.") then
            local full_path = path .. "/" .. subdir

            if directory_contains_matching_files(full_path) and not enter_pressed then
                reaper.ImGui_Image(ctx, folder_image, letter_size_files, letter_size_files)
                reaper.ImGui_SameLine(ctx)
                if reaper.ImGui_TreeNode(ctx, subdir) then
                    create_directory_tree(full_path, depth + 1)
                    reaper.ImGui_TreePop(ctx)
                end
            elseif directory_contains_matching_files(full_path) and enter_pressed then
                create_directory_tree(full_path, depth + 1)
            end
        end

        idx = idx + 1
    end

    idx = 0
    while true do
        local file = reaper.EnumerateFiles(path, idx)
        if not file then break end

        if not file:match("^%.") then
            local ext = file:match("^.+(%..+)$")
            if ext then
                ext = ext:sub(2)
                if filter_enabled[ext] and (search_query == "" or file:lower():find(search_query:lower(), 1, true)) then
                    local file_with_image = file
                    if file:match("%.mp3$") then
                        reaper.ImGui_Image(ctx, mp3_image, letter_size_files, letter_size_files)
                        reaper.ImGui_SameLine(ctx)
                    elseif file:match("%.wav$") then
                        reaper.ImGui_Image(ctx, wav_image, letter_size_files, letter_size_files)
                        reaper.ImGui_SameLine(ctx)
                    end

                    if reaper.ImGui_Selectable(ctx, file_with_image) then
                        preview_file(path .. "/" .. file)
                    end

                    if reaper.ImGui_BeginDragDropSource(ctx) then
                        reaper.ImGui_SetDragDropPayload(ctx, "DND_FILENAME", path .. "/" .. file)
                        _, _, drop_file = reaper.ImGui_GetDragDropPayload(ctx)
                        reaper.ImGui_Text(ctx, file)
                        reaper.ImGui_EndDragDropSource(ctx)
                    elseif not reaper.ImGui_IsMouseDown(ctx, 0) and drop_file ~= 0 then
                        add_file_to_timeline(drop_file)
                        drop_file = 0
                    end
                end
            end
        end

        idx = idx + 1
    end
end

function enter_key_press()
    if reaper.ImGui_IsKeyPressed(ctx, reaper.ImGui_Key_Enter(), optional_repeatIn) then
        enter_pressed = not enter_pressed
    end
end

function preview_file(file)
    if current_preview then
        reaper.CF_Preview_StopAll()
        current_preview = nil
    end

    local source = reaper.PCM_Source_CreateFromFile(file)
    current_preview = reaper.CF_CreatePreview(source)
    local play_success = reaper.CF_Preview_Play(current_preview)
    reaper.CF_Preview_SetValue(current_preview, "D_VOLUME", slider_value)
    if not play_success then
        reaper.ShowMessageBox("Failed to play preview: " .. file, "Error", 0)
    end
end

function add_file_to_timeline(file)
    reaper.PreventUIRefresh(1)
    local main_window = reaper.GetMainHwnd()
    reaper.JS_Window_SetFocus(main_window)
    reaper.BR_GetMouseCursorContext()

    local tracks_number = reaper.CountTracks(0)
    reaper.InsertTrackAtIndex(tracks_number, true)
    local track = reaper.GetTrack(0, tracks_number)

    local item = reaper.AddMediaItemToTrack(track)
    local take = reaper.AddTakeToMediaItem(item)
    local source = reaper.PCM_Source_CreateFromFile(file)

    reaper.PCM_Source_BuildPeaks(source, 0)

    reaper.SetMediaItemTake_Source(take, source)
    local sourceLength = reaper.GetMediaSourceLength(source)
    reaper.SetMediaItemLength(item, sourceLength, false)

    local reaproject = reaper.EnumProjects(-1, "")
    local item_position = reaper.SnapToGrid(reaproject, reaper.BR_GetMouseCursorContext_Position())

    reaper.SetMediaItemPosition(item, item_position, false)

    if reaper.BR_TrackAtMouseCursor() then
        reaper.MoveMediaItemToTrack(item, reaper.BR_TrackAtMouseCursor())
        reaper.DeleteTrack(track)
    end

    reaper.PreventUIRefresh(-1)
end

function main()
    reaper.ImGui_SetNextWindowDockID(ctx, -7)
    reaper.ImGui_PushStyleColor(ctx, reaper.ImGui_Col_Button(), 0x2C2C2CFF)
    reaper.ImGui_PushStyleColor(ctx, reaper.ImGui_Col_ButtonActive(), 0x2C2C2CFF)
    reaper.ImGui_PushStyleColor(ctx, reaper.ImGui_Col_WindowBg(), 0x2C2C2CFF)
    reaper.ImGui_PushStyleColor(ctx, reaper.ImGui_Col_ChildBg(), 0x1C1C1CFF)
    reaper.ImGui_PushStyleColor(ctx, reaper.ImGui_Col_FrameBg(), 0x1C1C1CFF)
    local retval, is_open = reaper.ImGui_Begin(ctx, "Media Explorer", true)

    local main_wnd_x, main_wnd_y = reaper.ImGui_GetWindowPos(ctx)

    if is_open then
        reaper.ImGui_SetNextItemWidth(ctx, 427)
        reaper.ImGui_PushFont(ctx, font3)
        local changed, text = reaper.ImGui_InputTextWithHint(ctx, "##1", "search", search_query, 256)
        reaper.ImGui_PopFont(ctx)
        if changed then
            search_query = text
            debounce_timer = reaper.time_precise() + 0.5
        end

        if reaper.time_precise() > debounce_timer then
            if search_query ~= last_search_query then
                search_cache = {}
                last_search_query = search_query
            end

            enter_key_press()

            reaper.ImGui_SetNextWindowPos(ctx, main_wnd_x + 340, main_wnd_y + 40)
            local is_dir_window_open = reaper.ImGui_BeginChild(ctx, "directory window", directory_window_width, directory_window_height, reaper.ImGui_ChildFlags_Border())

            reaper.ImGui_PushFont(ctx, font1)
            local _, plugins_selected = reaper.ImGui_Selectable(ctx, " \n   PLUG-INS \n ", false)
            local _, midi_selected = reaper.ImGui_Selectable(ctx, " \n        MIDI \n    EFFECTS \n ", false)
            local _, directory1_selected = reaper.ImGui_Selectable(ctx, " \n    BOUNCES \n ", true)
            reaper.ImGui_Selectable(ctx, "           +")
            reaper.ImGui_PopFont(ctx)

            if is_dir_window_open then
                reaper.ImGui_EndChild(ctx)
            end

            reaper.ImGui_SetNextWindowPos(ctx, main_wnd_x + 8, main_wnd_y + 40)
            reaper.ImGui_PushFont(ctx, font2)
            local is_file_window_open = reaper.ImGui_BeginChild(ctx, "files window", 330, 650, reaper.ImGui_ChildFlags_Border())

            if is_file_window_open then
                if plugins_selected then
                    create_directory_tree("C:\\Program Files\\Common Files\\VST3", 0)
                elseif midi_selected then
                    create_directory_tree("C:\\Users\\franc\\Desktop\\REAPER LEGIT PORTABLE MAIN RYKORD\\Effects\\midi", 0)
                elseif directory1_selected then
                    create_directory_tree("E:\\Sample Packs\\COLLECTION", 0)
                end
                reaper.ImGui_EndChild(ctx)
            end
            reaper.ImGui_PopFont(ctx)

            reaper.ImGui_Button(ctx, " ", 24, 24)
            reaper.ImGui_SameLine(ctx)
            _, slider_value = reaper.ImGui_SliderDouble(ctx, "##volume slider", slider_init, 0, 2)
            if slider_value ~= slider_init then
                slider_init = slider_value
            end

            reaper.ImGui_Button(ctx, "Filter", 50, 24)
            reaper.ImGui_SameLine(ctx)
            if reaper.ImGui_BeginPopup(ctx, "Filter") then
                for ext, enabled in pairs(filter_enabled) do
                    local _, state = reaper.ImGui_Checkbox(ctx, ext, enabled)
                    if state ~= enabled then
                        filter_enabled[ext] = state
                    end
                end
                reaper.ImGui_EndPopup(ctx)
            end

            if reaper.ImGui_IsItemClicked(ctx) then
                reaper.ImGui_OpenPopup(ctx, "Filter")
            end
        end

        reaper.defer(main)
    end
    reaper.ImGui_PopStyleColor(ctx, 5)
    reaper.ImGui_End(ctx)
end

directory_window_width = 95
directory_window_height = 650

letter_size_files = 16

font1 = reaper.ImGui_CreateFont("Arial", 12)
font2 = reaper.ImGui_CreateFont("Arial", letter_size_files)
font3 = reaper.ImGui_CreateFont("Arial", 18)
wav_image = reaper.ImGui_CreateImage("C:\\Users\\franc\\Desktop\\Desktop (A organizar)\\RYKORD\\Design\\wav_image.png")
mp3_image = reaper.ImGui_CreateImage("C:\\Users\\franc\\Desktop\\Desktop (A organizar)\\RYKORD\\Design\\mp3_image.png")
folder_image = reaper.ImGui_CreateImage("C:\\Users\\franc\\Desktop\\Desktop (A organizar)\\RYKORD\\Design\\tree_image.png")
ctx = reaper.ImGui_CreateContext("ctx")
reaper.ImGui_Attach(ctx, folder_image)
reaper.ImGui_Attach(ctx, wav_image)
reaper.ImGui_Attach(ctx, mp3_image)
reaper.ImGui_Attach(ctx, font1)
reaper.ImGui_Attach(ctx, font2)
reaper.ImGui_Attach(ctx, font3)
main()