-- mpv-lossless-cut MODIFIED - REVERSED MODE
-- Markierte Bereiche werden ENTFERNT (nicht behalten)

mp.msg = require("mp.msg")
mp.utils = require("mp.utils")
mp.options = require("mp.options")

local options = {
    output_dir = ".",
}

mp.options.read_options(options, "mpv-lossless-cut")

local cuts = {}
local os_name = package.config:sub(1, 1) == "\\" and "windows"
    or (io.popen("uname"):read("*a"):match("Darwin") and "mac" or "linux")

local function log(message)
    mp.msg.info(message)
    mp.osd_message(message, 4)
end

local function fmt_time(secs)
    local h = math.floor(secs / 3600)
    local m = math.floor((secs % 3600) / 60)
    local s = secs % 60
    return string.format('%02d:%02d:%05.2f', h, m, s)
end

local function fmt_time_raw(secs)
    return string.format("%.6f", secs)
end

local function write_timestamp_files()
    local outdir = mp.get_property("working-directory")
    if not outdir or outdir == "" then return end
    
    local file = io.open(join_paths(outdir, "cuts.txt"), "w")
    if file then
        for _, c in ipairs(cuts) do
            file:write(fmt_time_raw(c.start))
            if c["end"] then
                file:write(" " .. fmt_time_raw(c["end"]))
            end
            file:write("\n")
        end
        file:close()
        mp.msg.info("Timestamps gespeichert: cuts.txt")
    end
end

function join_paths(path1, path2)
    if not path1 or path1 == "" then return path2 or "" end
    if not path2 or path2 == "" then return path1 end
    local sep = os_name == "windows" and "\\" or "/"
    path1 = path1:gsub("[/\\]", sep):gsub(sep .. "+$", "")
    if path2:match("^[A-Za-z]:") or path2:match("^" .. sep) then return path2 end
    return path1 .. sep .. path2
end

local function ensure_dir(dir)
    local args = os_name == "windows" and { "cmd", "/c", "mkdir", dir } or { "mkdir", "-p", dir }
    return mp.utils.subprocess({ args = args, cancellable = false }).status == 0
end

local function run_ffmpeg(args)
    local base = { "ffmpeg", "-nostdin", "-loglevel", "error", "-y" }
    for _, a in ipairs(args) do table.insert(base, a) end
    print("FFMPEG: " .. table.concat(base, " "))
    return mp.utils.subprocess({ args = base, cancellable = false }).status == 0
end

local cut_overlay = nil
local overlay_visible = true

local function update_overlay()
    if not overlay_visible then
        if cut_overlay then
            cut_overlay:remove()
            cut_overlay = nil
        end
        return
    end
    
    if #cuts == 0 then
        if cut_overlay then
            cut_overlay:remove()
            cut_overlay = nil
        end
        return
    end
    
    local dur = mp.get_property_number("duration")
    if not dur or dur == 0 then return end
    
    table.sort(cuts, function(a, b) return a.start < b.start end)
    
    local tag = "{\\an9}{\\fs16}{\\cFFFFFF}{\\3c&H000000&}"
    local out = {}
    
    table.insert(out, tag .. "========= CUTS =========")
    
    local total = 0
    for i, c in ipairs(cuts) do
        local d = (c["end"] or c.start) - c.start
        total = total + d
        local line = tag .. "[" .. i .. "] " .. fmt_time(c.start)
        if c["end"] then
            line = line .. " -> " .. fmt_time(c["end"])
        else
            line = line .. " -> "
        end
        table.insert(out, line)
    end
    table.insert(out, tag .. "---------------")
    table.insert(out, tag .. fmt_time(dur) .. " - " .. string.format("%.0fs", total) .. " = " .. fmt_time(dur - total))
    
    local data = table.concat(out, "\\N")
    
    if not cut_overlay then
        cut_overlay = mp.create_osd_overlay("ass-events")
    end
    if cut_overlay then
        cut_overlay.data = data
        cut_overlay:update()
    end
end

mp.add_periodic_timer(5, update_overlay)

local function show_cuts()
    local dur = mp.get_property_number("duration") or 0
    table.sort(cuts, function(a, b) return a.start < b.start end)
    
    local msg = "=== CUTS (ENTFERNE) ===\n"
    msg = msg .. "Video: " .. fmt_time(dur) .. "\n"
    
    if #cuts == 0 then
        msg = msg .. "Keine Cuts"
    else
        local total = 0
        for i, c in ipairs(cuts) do
            local d = c["end"] - c.start
            total = total + d
            msg = msg .. i .. ": " .. fmt_time(c.start) .. " -> " .. fmt_time(c["end"]) .. "\n"
        end
        msg = msg .. "Entferne: " .. string.format("%.1fs", total) .. "\n"
        msg = msg .. "Ergebnis: " .. fmt_time(dur - total)
    end
    
    mp.osd_message(msg, 5)
end

local function cut_start()
    local t = mp.get_property_number("time-pos")
    if t then
        table.insert(cuts, {start = t})
        log("[START: " .. fmt_time(t) .. "]")
        update_overlay()
        write_timestamp_files()
    end
end

local function cut_end()
    if #cuts == 0 or cuts[#cuts]["end"] then
        log("Kein Start gesetzt!")
        return
    end
    cuts[#cuts]["end"] = mp.get_property_number("time-pos")
    log("CUT: " .. fmt_time(cuts[#cuts].start) .. " - " .. fmt_time(cuts[#cuts]["end"]))
    update_overlay()
    write_timestamp_files()
end

local function cut_delete()
    if #cuts > 0 then
        local c = table.remove(cuts)
        log("Geloescht: " .. fmt_time(c.start))
    else
        log("Nichts zu loeschen")
    end
    update_overlay()
    write_timestamp_files()
end

local function cut_render()
    if #cuts == 0 or not cuts[#cuts]["end"] then
        log("Keine gueltigen Cuts!")
        return
    end
    
    local input = mp.get_property("path")
    local filename = mp.get_property("filename")
    local dur = mp.get_property_number("duration") or 0
    local outdir = mp.get_property("working-directory")
    
    log("=== ENTFERNE MARKIERTE BEREICHE ===")
    log("Input: " .. input)
    
    table.sort(cuts, function(a, b) return a.start < b.start end)
    
    -- Segmente berechnen die BEHALTEN werden
    local keep = {}
    local last = 0
    
    for _, c in ipairs(cuts) do
        if c.start > last then
            table.insert(keep, {start = last, ["end"] = c.start})
            log("Behalte: " .. fmt_time(last) .. " - " .. fmt_time(c.start))
        end
        last = c["end"]
    end
    
    if last < dur then
        table.insert(keep, {start = last, ["end"] = dur})
        log("Behalte: " .. fmt_time(last) .. " - " .. fmt_time(dur))
    end
    
    log("Segmente: " .. #keep)
    
    if #keep == 0 then
        log("Nichts zu behalten!")
        return
    end
    
    local tmp = os.getenv("HOME") .. "/mpv_rev_" .. os.time()
    ensure_dir(tmp)
    
    -- Segmente exportieren
    for i, k in ipairs(keep) do
        local seg_file = tmp .. "/seg_" .. i .. ".mp4"
        local duration = k["end"] - k.start
        
        mp.osd_message(string.format("Segment %d/%d...", i, #keep), 999)
        
        run_ffmpeg({
            "-i", input,
            "-ss", tostring(k.start),
            "-t", tostring(duration),
            "-c:v", "libx264", "-preset", "fast", "-crf", "18",
            "-c:a", "aac", "-b:a", "192k",
            "-movflags", "+faststart",
            seg_file
        })
    end
    
    -- Concat
    local list_file = tmp .. "/list.txt"
    local f = io.open(list_file, "w")
    if f then
        for i = 1, #keep do
            f:write("file '" .. tmp .. "/seg_" .. i .. ".mp4'\n")
        end
        f:close()
    end
    
    local filename_noext = filename:match("^(.-)%.[^%.]+$") or filename
    local out_file = join_paths(outdir, filename_noext .. "_cut.mp4")
    
    mp.osd_message("Verbinde...", 999)
    
    run_ffmpeg({
        "-f", "concat", "-safe", "0", "-i", list_file,
        "-c", "copy", out_file
    })
    
    os.execute("rm -rf " .. tmp)
    
    log("Fertig: " .. out_file)
end

-- Key bindings
mp.add_key_binding("c", "cut_start", cut_start)
mp.add_key_binding("x", "cut_end", cut_end)
mp.add_key_binding("p", "cut_show", show_cuts)
mp.add_key_binding("d", "cut_delete", cut_delete)
mp.add_key_binding("z", "cut_render", cut_render)

mp.set_property("keep-open", "yes")

log("C=Start, X=Ende, P=Show, D=Delete, Z=Export")

mp.register_event("file-loaded", function()
    cuts = {}
    update_overlay()
end)