-- original by Wanakachi
-- suitable for Windows operating systems

-- picture-in-picture (PiP) mode for mpv

local options = require "mp.options"

local o = {
    autofit = "25%x25%",
    autofit_restore_larger = "100%x100%",
    autofit_restore_smaller = "40%x30%",
    geometry = "100%:100%",        -- pip position, bottom-right: 100%:100%
    geometry_restore = "50%:50%",  -- restore position, center: 50%:50%
    geometry_delay = 0.05          -- delay to avoid geometry race on state change
}

options.read_options(o, _, function() end)

local pip_enabled = false
local geometry_timer = nil
local original_options = {}

-- save original window properties
local function save_original_options()
    original_options.fullscreen   = mp.get_property_bool("fullscreen")
    original_options.window_maximized = mp.get_property_bool("window-maximized")
    original_options.force_window_position = mp.get_property_bool("force-window-position")
    original_options.keepaspect_window = mp.get_property_bool("keepaspect-window")
    original_options.border        = mp.get_property_bool("border")
    original_options.ontop         = mp.get_property_bool("ontop")
    original_options.window_scale  = mp.get_property("window_scale")
    original_options.autofit       = mp.get_property("autofit")
    original_options.autofit_larger = mp.get_property("autofit-larger") ~= "" and mp.get_property("autofit-larger") or o.autofit_restore_larger
    original_options.autofit_smaller = mp.get_property("autofit-smaller") ~= "" and mp.get_property("autofit-smaller") or o.autofit_restore_smaller
    original_options.geometry    = mp.get_property("geometry") ~= "" and mp.get_property("geometry") or o.geometry_restore
end

-- restore original window properties
local function restore_original_options()
    if original_options.fullscreen    ~= nil then mp.set_property_bool("fullscreen",    original_options.fullscreen)    end
    if original_options.window_maximized ~= nil then mp.set_property_bool("window-maximized", original_options.window_maximized) end
    if original_options.force_window_position ~= nil then mp.set_property_bool("force-window-position", original_options.force_window_position) end
    if original_options.border        ~= nil then mp.set_property_bool("border",        original_options.border)        end
    if original_options.ontop         ~= nil then mp.set_property_bool("ontop",         original_options.ontop)         end
    if original_options.keepaspect_window ~= nil then mp.set_property_bool("keepaspect-window", original_options.keepaspect_window) end
    if original_options.window_scale  ~= nil then mp.set_property("window_scale", original_options.window_scale) end
    if original_options.autofit       ~= nil then mp.set_property("autofit", original_options.autofit) end
    if original_options.autofit_larger ~= nil then mp.set_property("autofit-larger", original_options.autofit_larger) end
    if original_options.autofit_smaller ~= nil then mp.set_property("autofit-smaller", original_options.autofit_smaller) end
    if original_options.geometry ~= nil then mp.set_property("geometry", original_options.geometry) end
end

local function cancel_geometry_timer()
    if geometry_timer then
        geometry_timer:kill()
        geometry_timer = nil
    end
end

local function set_geometry_delay(value)
    cancel_geometry_timer()
    geometry_timer = mp.add_timeout(o.geometry_delay, function()
        geometry_timer = nil
        mp.set_property("geometry", value)
    end)
end

-- enter PiP mode
local function enable_pip()
    if pip_enabled then return end

    save_original_options()

    mp.set_property_bool("fullscreen",   false)   -- exit fullscreen if necessary
    mp.set_property_bool("window-minimized", false)
    mp.set_property_bool("force-window-position", false)
    mp.set_property_bool("border",       false)   -- remove decorations
    mp.set_property_bool("ontop",        true)    -- keep above other windows
    mp.set_property_bool("keepaspect-window", true)
    mp.set_property("autofit", o.autofit)
    mp.set_property("autofit-larger", "")
    mp.set_property("autofit-smaller", "")
    mp.set_property("window_scale", "")
    set_geometry_delay(o.geometry)

    pip_enabled = true
    mp.osd_message("PiP enabled")
end

-- leave PiP mode
local function disable_pip()
    if not pip_enabled then return end

    cancel_geometry_timer()
    restore_original_options()
    pip_enabled = false
    mp.osd_message("PiP disabled")
end

-- toggle PiP on/off
local function toggle_pip()
    if pip_enabled then
        disable_pip()
    else
        enable_pip()
    end
end

-- monitor fullscreen state changes and exit PiP first
mp.observe_property("fullscreen", "bool", function(_, value)
    if value and pip_enabled then
        disable_pip()
        mp.set_property_bool("fullscreen", true)
    end
end)

-- monitor window-maximized state changes (on some systems maximize and fullscreen are separate)
mp.observe_property("window-maximized", "bool", function(_, value)
    if value and pip_enabled then
        disable_pip()
        mp.set_property_bool("window-maximized", true)
    end
end)

-- binding
mp.add_key_binding(nil, "toggle-pip", toggle_pip)