from test/more import *;

requires_capability( "fs" );

from std/data/json import JSON;
from std/io import Path;
from std/zuzuzoo import Zuzuzoo;

function ensure_dir ( path ) {
	return true if path.exists();
	let parent := path.parent();
	ensure_dir(parent) if not parent.exists();
	path.mkdir();
	return true;
}

function root () {
	let dir := Path.tempdir();
	let lib := dir.child("lib");
	let bin := dir.child("bin");
	let meta := dir.child("meta");
	ensure_dir(lib);
	ensure_dir(bin);
	ensure_dir(meta);
	return {
		dir_obj: dir,
		lib_obj: lib,
		bin_obj: bin,
		meta_obj: meta,
		lib_dir: lib.to_String(),
		bin_dir: bin.to_String(),
		meta_dir: meta.to_String(),
	};
}

function module_entry ( install_as ) {
	return {
		source: "modules/" _ install_as,
		install_as: install_as,
		sha256: "old",
	};
}

function write_installed ( target, name, version, modules ) {
	( new JSON( pretty: true ) ).dump(
		target{meta_obj}.child( name _ "-" _ version _ ".json" ),
		{
			name: name,
			version: version,
			author: "Example",
			license: "MIT",
			status: "stable",
			dependencies: {},
			installed: {
				zdf: "ZDF-1",
				lib_dir: target{lib_dir},
				bin_dir: target{bin_dir},
				meta_dir: target{meta_dir},
				modules: modules,
				scripts: [],
			},
		},
	);
}

let target := root();
ensure_dir( target{lib_obj}.child("shared") );
target{lib_obj}.child("shared").child("file.zzm").spew_utf8("// shared\n");
write_installed(
	target,
	"owner-a",
	"1.0.0",
	[ module_entry("shared/file.zzm") ],
);
write_installed(
	target,
	"owner-b",
	"1.0.0",
	[ module_entry("shared/file.zzm") ],
);

let zoo := new Zuzuzoo(
	lib_dir: target{lib_dir},
	bin_dir: target{bin_dir},
	meta_dir: target{meta_dir},
	home: Path.tempdir().to_String(),
);
let ambiguous := zoo.plan_remove("shared/file");
is( ambiguous{ok}, false, "module target with multiple owners is not ok" );
is(
	ambiguous{errors}[0]{code},
	"ambiguous-target",
	"ambiguous module target records an error",
);

let blocked := zoo.plan_remove(
	{ type: "distribution", value: "owner-a" },
);
is( blocked{ok}, false, "kept shared owner blocks removal" );
is(
	blocked{shared_file_conflicts}.length(),
	1,
	"shared conflict is recorded",
);
is(
	blocked{shared_file_conflicts}[0]{kept_owners}[0]{name},
	"owner-b",
	"kept owner is reported",
);

let blocked_result := zoo.remove(
	{ type: "distribution", value: "owner-a" },
);
is( blocked_result{ok}, false, "blocked remove does not mutate" );
is(
	target{lib_obj}.child("shared").child("file.zzm").exists(),
	true,
	"shared file remains after blocked remove",
);
is(
	target{meta_obj}.child("owner-a-1.0.0.json").exists(),
	true,
	"metadata remains after blocked remove",
);

let allowed := zoo.plan_remove(
	[
		{ type: "distribution", value: "owner-a" },
		{ type: "distribution", value: "owner-b" },
	],
);
ok( allowed{ok}, "removing all owners is allowed" );
is( allowed{files}.length(), 3, "shared file is removed once" );
is( allowed{files}[0]{owners}.length(), 2, "both owners are recorded" );
is( allowed{files}[0]{blocked}, false, "shared file is not blocked" );

let allowed_result := zoo.remove(
	[
		{ type: "distribution", value: "owner-a" },
		{ type: "distribution", value: "owner-b" },
	],
);
ok( allowed_result{ok}, "removing all shared owners succeeds" );
is(
	target{lib_obj}.child("shared").child("file.zzm").exists(),
	false,
	"shared file is removed once all owners are planned",
);
is(
	target{meta_obj}.child("owner-a-1.0.0.json").exists(),
	false,
	"first owner metadata is removed",
);
is(
	target{meta_obj}.child("owner-b-1.0.0.json").exists(),
	false,
	"second owner metadata is removed",
);

done_testing();
