<?php

declare(strict_types=1);
namespace Tests\git2;
use git2\git;
use git2\git_indexer_progress;

final class PackbuilderTest extends GitTestCase
{

	public function testPackbuilder(): void
	{
		$dir = $this->mkdir('packbuilder');
		git::repository_init($repo, $dir, false);
		git::repository_index($index, $repo);
		git::index_write_tree($treeId, $index);
		git::tree_lookup($tree, $repo, $treeId);
		git::signature_new($sig, 'John Doe', 'john.doe@example.com', 1640263000, 60);
		git::commit_create_v($id, $repo, 'HEAD', $sig, $sig, null, 'foo', $tree);

		$this->assertOK(git::packbuilder_new($pb, $repo));
		$this->assertSame(0, git::packbuilder_object_count($pb));

		$progress = [];

		$this->assertOK(git::packbuilder_set_callbacks($pb, function(int $stage, int $current, int $total) use(&$progress): int {
			$progress[] = func_get_args();
			return 0;
		}));

		$this->assertSame(1, git::packbuilder_set_threads($pb, 1));
		$this->assertTrue(git::oid_is_zero(git::packbuilder_hash($pb)));

		$this->assertOK(git::packbuilder_insert_commit($pb, $id));
		$this->assertCount(1, $progress);
		$this->assertSame([0, 1, 0], $progress[0]);
		$this->assertSame(2, git::packbuilder_object_count($pb));
		$this->assertSame(0, git::packbuilder_written($pb));

		$this->assertOK(git::packbuilder_write($pb, null, 0644, function(git_indexer_progress $stats): int {
			$this->assertSame(2, $stats->total_objects);
			return 0;
		}));

		$this->assertSame(2, git::packbuilder_written($pb));
	}

	public function testInsertTree(): void
	{
		$dir = $this->mkdir('insert_tree');
		git::repository_init($repo, $dir, false);
		git::repository_index($index, $repo);
		git::index_write_tree($treeId, $index);
		git::tree_lookup($tree, $repo, $treeId);
		git::signature_new($sig, 'John Doe', 'john.doe@example.com', 1640263000, 60);
		git::commit_create_v($id, $repo, 'HEAD', $sig, $sig, null, 'foo', $tree);
		git::packbuilder_new($pb, $repo);

		$this->assertOK(git::packbuilder_insert_tree($pb, $treeId));
		$this->assertOK(git::packbuilder_write_buf($buf, $pb));
		$this->assertSame('UEFDSwAAAAIAAAABIHicAwAAAAAB07G3z2atMXqwj7eB26jYrmjhsgA=', base64_encode((string) $buf));
	}

	public function testInsertWalk(): void
	{
		$dir = $this->mkdir('insert_walk');
		git::repository_init($repo, $dir, false);
		git::repository_index($index, $repo);
		git::index_write_tree($treeId, $index);
		git::tree_lookup($tree, $repo, $treeId);
		git::signature_new($sig, 'John Doe', 'john.doe@example.com', 1640263000, 60);
		git::commit_create_v($id, $repo, 'HEAD', $sig, $sig, null, 'foo', $tree);
		git::packbuilder_new($pb, $repo);

		git::revwalk_new($walk, $repo);
		git::revwalk_push_head($walk);

		$this->assertOK(git::packbuilder_insert_walk($pb, $walk));
		$this->assertOK(git::packbuilder_write($pb, null, 0644, null));
		$this->assertSame('8bfb73c1703567c0afb0e5fcbc90066cc70d187c', git::oid_tostr_s(git::packbuilder_hash($pb)));
	}

	public function testInsert(): void
	{
		$dir = $this->mkdir('insert');
		git::repository_init($repo, $dir, false);
		git::repository_index($index, $repo);
		git::index_write_tree($treeId, $index);
		git::tree_lookup($tree, $repo, $treeId);
		git::signature_new($sig, 'John Doe', 'john.doe@example.com', 1640263000, 60);
		git::commit_create_v($id, $repo, 'HEAD', $sig, $sig, null, 'foo', $tree);
		git::packbuilder_new($pb, $repo);

		$this->assertOK(git::packbuilder_insert($pb, $id, null));
		$this->assertOK(git::packbuilder_write($pb, null, 0644, null));
		$this->assertSame('56c02b2428120acc1efcd827009dc568a247b775', git::oid_tostr_s(git::packbuilder_hash($pb)));
	}

	public function testInsertRecur(): void
	{
		$dir = $this->mkdir('insert_recur');
		git::repository_init($repo, $dir, false);
		git::repository_index($index, $repo);
		git::index_write_tree($treeId, $index);
		git::tree_lookup($tree, $repo, $treeId);
		git::signature_new($sig, 'John Doe', 'john.doe@example.com', 1640263000, 60);
		git::commit_create_v($id, $repo, 'HEAD', $sig, $sig, null, 'foo', $tree);
		git::packbuilder_new($pb, $repo);

		$this->assertOK(git::packbuilder_insert_recur($pb, $id, null));
		$this->assertOK(git::packbuilder_write($pb, null, 0644, null));
		$this->assertSame('8bfb73c1703567c0afb0e5fcbc90066cc70d187c', git::oid_tostr_s(git::packbuilder_hash($pb)));
	}

	public function testForeach(): void
	{
		$dir = $this->mkdir('foreach');
		git::repository_init($repo, $dir, false);
		git::repository_index($index, $repo);
		git::index_write_tree($treeId, $index);
		git::tree_lookup($tree, $repo, $treeId);
		git::signature_new($sig, 'John Doe', 'john.doe@example.com', 1640263000, 60);
		git::commit_create_v($id, $repo, 'HEAD', $sig, $sig, null, 'foo', $tree);
		git::packbuilder_new($pb, $repo);
		git::packbuilder_insert($pb, $id, null);
		git::packbuilder_write($pb, null, 0644, null);

		$samples = [];

		$this->assertSame(1, git::packbuilder_foreach($pb, function(mixed $buf, int $size) use(&$samples): int {
			$samples[] = [fread($buf, 4), $size];
			return 1;
		}));

		$this->assertSame([['PACK', 12], ["\xe5\x07\xae\xe3", 20]], $samples);
	}

}