<?php

declare(strict_types=1);
namespace Tests\git2;
use git2\git;
use git2\git_commit;
use git2\git_error_code;
use git2\git_object;
use git2\git_object_t;
use git2\git_oid;
use git2\git_strarray;
use git2\git_tag;

final class TagTest extends GitTestCase
{

	public function testAnnotationCreate(): void
	{
		$dir = $this->mkdir('annotation_create');
		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, 'Hello world!', $tree);
		git::commit_lookup($commit, $repo, $id);
		$this->assertOK(git::tag_annotation_create(
			$oid,
			$repo,
			'v1.0',
			$commit,
			$sig,
			'Initial release.',
		));

		$this->assertOK(git::tag_lookup($tag, $repo, $oid));
		$this->assertInstanceOf(git_tag::class, $tag);
	}

	public function testGet(): void
	{
		$dir = $this->mkdir('get');
		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, 'Hello world!', $tree);
		git::commit_lookup($commit, $repo, $id);
		$this->assertOK(git::tag_annotation_create(
			$oid,
			$repo,
			'v1.0',
			$commit,
			$sig,
			'Initial release.',
		));

		$this->assertOK(git::tag_lookup($tag, $repo, $oid));
		$this->assertInstanceOf(git_tag::class, $tag);

		$this->assertSame('00589bac0d193222f62c7dc11498771c0f649347', git::oid_tostr_s($oid));
		$this->assertSame('v1.0', git::tag_name($tag));
		$this->assertSame($repo, git::tag_owner($tag));
		$this->assertSame('Initial release.', git::tag_message($tag));

		$this->assertOK(git::tag_peel($peeled, $tag));
		$this->assertInstanceOf(git_object::class, $peeled);

		$this->assertSame($commit, $peeled->as(git_commit::class));

		$tid = git::tag_id($tag);
		$this->assertSame('00589bac0d193222f62c7dc11498771c0f649347', git::oid_tostr_s($tid));

		$tagger = git::tag_tagger($tag);
		$this->assertSame('John Doe', $tagger->name);

		$this->assertOK(git::tag_lookup_prefix($tagLookupPrefix, $repo, $oid, 6));
		$this->assertInstanceOf(git_tag::class, $tagLookupPrefix);
		$this->assertSame('00589bac0d193222f62c7dc11498771c0f649347', git::oid_tostr_s(git::tag_id($tagLookupPrefix)));

		$this->assertSame(git_object_t::COMMIT, git::tag_target_type($tag));
		$this->assertOK(git::tag_target($target, $tag));
		$this->assertInstanceOf(git_object::class, $target);
		$this->assertSame($commit, $target->as(git_commit::class));
		$this->assertSame($target, $commit->as(git_object::class));
		$this->assertSame('4ce6effae5129f525fb2174ef364875e31efd1e4', git::oid_tostr_s(git::object_id($target)));
		$this->assertSame('4ce6effae5129f525fb2174ef364875e31efd1e4', git::oid_tostr_s(git::object_id($commit)));
		$this->assertSame('4ce6effae5129f525fb2174ef364875e31efd1e4', git::oid_tostr_s(git::tag_target_id($tag)));
	}

	public function testCreate(): void
	{
		$dir = $this->mkdir('create');
		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, 'Hello world!', $tree);
		git::commit_lookup($commit, $repo, $id);

		$this->assertOK(git::tag_create(
			$oid,
			$repo,
			'v1.0',
			$commit,
			$sig,
			'Initial release.',
			false,
		));

		$this->assertOK(git::tag_lookup($tag, $repo, $oid));
		$this->assertInstanceOf(git_tag::class, $tag);
		$this->assertSame('00589bac0d193222f62c7dc11498771c0f649347', git::oid_tostr_s($oid));

		$this->assertSame(git_error_code::EEXISTS, git::tag_create(
			$oid,
			$repo,
			'v1.0',
			$commit,
			$sig,
			'force = no',
			false,
		));

		$this->assertOK(git::tag_create(
			$oid,
			$repo,
			'v1.0',
			$commit,
			$sig,
			'force = no',
			true,
		));

		$this->assertOK(git::tag_lookup($tag, $repo, $oid));
		$this->assertInstanceOf(git_tag::class, $tag);
		$this->assertSame('force = no', git::tag_message($tag));
	}

	public function testDelete(): void
	{
		$dir = $this->mkdir('delete');
		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, 'Hello world!', $tree);
		git::commit_lookup($commit, $repo, $id);

		$this->assertOK(git::tag_create(
			$oid,
			$repo,
			'v1.0',
			$commit,
			$sig,
			'Initial release.',
			false,
		));

		$this->assertOK(git::tag_delete($repo, 'v1.0'));
		$this->assertOK(git::tag_list($list, $repo));
		$this->assertInstanceOf(git_strarray::class, $list);
		$this->assertSame(0, $list->count);
	}

	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, 'Hello world!', $tree);
		git::commit_lookup($commit, $repo, $id);

		$this->assertOK(git::tag_create($oid1, $repo, 'v1.0', $commit, $sig, '', false));
		$this->assertOK(git::tag_create($oid2, $repo, 'v1.1.0', $commit, $sig, '', false));
		$this->assertOK(git::tag_create($oid3, $repo, 'v1.1.1', $commit, $sig, '', false));

		$this->assertOK(git::tag_list($list, $repo));
		$this->assertInstanceOf(git_strarray::class, $list);
		$this->assertSame(3, count($list));
		$this->assertSame('v1.0', $list[0]);
		$this->assertSame('v1.1.0', $list[1]);
		$this->assertSame('v1.1.1', $list[2]);

		$this->assertOK(git::tag_list_match($list, 'v1.1.*', $repo));
		$this->assertInstanceOf(git_strarray::class, $list);
		$this->assertSame(2, count($list));
		$this->assertSame('v1.1.0', $list[0]);
		$this->assertSame('v1.1.1', $list[1]);

		$items = [];

		$this->assertOK(git::tag_foreach($repo, function(string $name, git_oid $oid) use(&$items): void {
			$items[] = [$name, git::oid_tostr_s($oid)];
		}));

		$this->assertSame([
			['refs/tags/v1.0',   '4df389d49780d0c92d0559f01c111d126d3385b7'],
			['refs/tags/v1.1.0', '91862834f24b7dce8ce41b2a582c0845ca807dde'],
			['refs/tags/v1.1.1', '5e4c5eb443b51326d520f0fd76eb26d710f70e71'],
		], $items);

		$this->assertSame(1, git::tag_foreach($repo, function(string $name, git_oid $oid) use(&$items): int {
			$this->assertSame('refs/tags/v1.0', $name);
			$this->assertSame('4df389d49780d0c92d0559f01c111d126d3385b7', git::oid_tostr_s($oid));
			return 1;
		}));
	}

	public function testDup(): void
	{
		$dir = $this->mkdir('dup');
		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, 'Hello world!', $tree);
		git::commit_lookup($commit, $repo, $id);

		$this->assertOK(git::tag_create($oid, $repo, 'v1.0', $commit, $sig, '', false));
		$this->assertOK(git::tag_lookup($tag, $repo, $oid));

		$this->assertOK(git::tag_dup($dup, $tag));
		$this->assertSame('v1.0', git::tag_name($dup));
		$this->assertSame('4df389d49780d0c92d0559f01c111d126d3385b7', git::oid_tostr_s(git::tag_id($dup)));
	}

	public function testCreateFromBuffer(): void
	{
		$dir = $this->mkdir('create_from_buffer');
		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, 'Hello world!', $tree);
		git::commit_lookup($commit, $repo, $id);

		$this->assertOK(git::tag_create_from_buffer(
			$oid,
			$repo,
			"object 4ce6effae5129f525fb2174ef364875e31efd1e4\ntype commit\ntag v1.0\ntagger John T. Doe <john.doe@example.com> 08-Jan-22 21:25:22 GMT\n\nInitial release.",
			false
		));

		$this->assertOK(git::tag_lookup($tag, $repo, $oid));
		$this->assertInstanceOf(git_tag::class, $tag);

		$this->assertSame('d73ddb98ab7e8ca0a60935c4dc49526b735dba15', git::oid_tostr_s($oid));
		$this->assertSame('v1.0', git::tag_name($tag));
		$this->assertSame('Initial release.', git::tag_message($tag));
		$this->assertSame('John T. Doe', git::tag_tagger($tag)->name);
	}

	public function testCreateLightweight(): void
	{
		$dir = $this->mkdir('create_lightweight');
		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, 'Hello world!', $tree);
		git::commit_lookup($commit, $repo, $id);

		$this->assertOK(git::tag_create_lightweight(
			$oid,
			$repo,
			'v1.0',
			$commit,
			false,
		));

		$this->assertOK(git::commit_lookup($target, $repo, $oid));
		$this->assertSame($commit, $target);
	}

	public function testNameIsValid(): void
	{
		$this->assertOK(git::tag_name_is_valid($true, 'v1.0'));
		$this->assertTrue($true);

		$this->assertOK(git::tag_name_is_valid($false, '/'));
		$this->assertFalse($false);
	}

}