-- lx-bundle:true

---@diagnostic disable: param-type-mismatch
-- lx bootstrapper

local function setup_paths()
	PATHSEP = package.config:sub(1, 1)
	EXE_DIR = EXE_DIR or "."
	CORE_DIR = false
	PLUGINS_DIR = false
	SYNTAX_DIR = false
	TESTS_DIR = false

	assert(type(EXE_FILE) == "string" and EXE_FILE ~= "", "EXE_FILE must be set")

	DATA_DIR = system.join_path(EXE_DIR, "data", true)
	USER_DIR = system.join_path(EXE_DIR, "user", true)
	HAVE_LOCAL_DATA = system.is_dir(DATA_DIR)

	CACHE_DIR = system.join_path(USER_DIR, "cache", true)
	STYLES_DIR = system.join_path(DATA_DIR, "styles", true)
	USER_SETTINGS_FILE = USER_DIR .. "settings.lua"

	if HAVE_LOCAL_DATA then
		local d = nil

		d = system.join_path(DATA_DIR, "core", true)
		if system.is_file(system.join_path(d, "init.lua")) then
			CORE_DIR = d
		end
		d = system.join_path(EXE_DIR, "cache", true)
		if system.is_dir(d) then
			CACHE_DIR = d
		end
		d = system.join_path(DATA_DIR, "syntax", true)
		if system.is_dir(d) then
			SYNTAX_DIR = d
		end
		d = system.join_path(DATA_DIR, "plugins", true)
		if system.is_dir(d) then
			PLUGINS_DIR = d
		end
		d = system.join_path(DATA_DIR, "tests", true)
		if system.is_dir(d) then
			TESTS_DIR = d
		end
		-- USER_DIR, STYLES_DIR, USER_SETTINGS_FILE remain stable path constants
	end

	FONTS_DIR = system.join_path(DATA_DIR, "fonts", true)
	OS_FONTS_DIR = system.join_path(
		(os.getenv("SystemRoot") or os.getenv("WINDIR") or "C:/Windows"), "Fonts", true)
end

local function setup_local_override_searcher()
	if BOOT_MODE == "local_lua" or not HAVE_LOCAL_DATA then
		return
	end

	local cache = {}
	local function path_exists(path)
		local hit = cache[path]
		if hit ~= nil then
			return hit
		end
		local ok = system.is_file(path)
		cache[path] = ok
		return ok
	end

	local function module_path(module)
		local rel = module:gsub("%.", "/")
		if module == "core" then
			return CORE_DIR and system.join_path(CORE_DIR, "init.lua") or nil
		end
		if module:match("^core%.") then
			return CORE_DIR and system.join_path(DATA_DIR, rel .. ".lua") or nil
		end
		if module:match("^syntax%.") then
			return SYNTAX_DIR and system.join_path(DATA_DIR, rel .. ".lua") or nil
		end
		if module:match("^plugins%.") then
			if not PLUGINS_DIR then
				return nil
			end

			local flat_path = system.join_path(DATA_DIR, rel .. ".lua")
			if path_exists(flat_path) then
				return flat_path
			end

			local base = module:match("^plugins%.([%w_]+)$")
			if not base then
				return flat_path
			end

			-- Keep canonical plugin ids stable when the entry file lives in 'name/name.lua'
			local dir_path = system.join_path(PLUGINS_DIR, base)
			local nested_path = system.join_path(dir_path, base .. ".lua")
			if path_exists(nested_path) then
				return nested_path
			end

			return flat_path
		end
		if module:match("^tests%.") then
			return TESTS_DIR and system.join_path(DATA_DIR, rel .. ".lua") or nil
		end
		if module == "user" then
			local p1 = system.join_path(DATA_DIR, "user.lua")
			if path_exists(p1) then
				return p1
			end
			local p2 = USER_DIR and (USER_DIR .. "init.lua") or nil
			if path_exists(p2) then
				return p2
			end
		end
		return nil
	end

	local function local_override_searcher(module)
		local p = module_path(module)
		if not p or not path_exists(p) then
			return nil
		end
		local loader, err = loadfile(p)
		if not loader then
			return "\n\tlocal override load failed: " .. tostring(err)
		end
		return loader
	end

	table.insert(package.searchers, 2, local_override_searcher)
end

local function setup_external_package_path()
	if not HAVE_LOCAL_DATA then
		return
	end
	package.path = DATA_DIR .. "?.lua;" .. package.path
	package.path = DATA_DIR .. "?/init.lua;" .. package.path
end

local boot = {}

function boot.run()
	local function parse_scale(raw)
		if type(raw) ~= "string" or raw == "" then
			return nil
		end
		raw = raw:gsub("^%s+", ""):gsub("%s+$", ""):gsub(",", ".")
		local n = tonumber(raw)
		if n and n > 0 then
			return n
		end
		return nil
	end
	SCALE = parse_scale(os.getenv("LX_SCALE"))
		or parse_scale(os.getenv("LITE_SCALE"))
		or parse_scale(os.getenv("GDK_SCALE"))
		or parse_scale(os.getenv("QT_SCALE_FACTOR"))
		or SCALE
	setup_paths()
	setup_local_override_searcher()
	setup_external_package_path()

	local core = require("core")
	core.init()
	core.run()
	return core
end

return boot
