<?php

declare(strict_types=1);
namespace Tests\git2;
use git2\git;
use git2\git_commit;
use git2\git_error_code;
use git2\git_repository;
use git2\git_signature;

final class CommitTest extends GitTestCase
{

	public function testCreateV(): void
	{
		$dir = $this->mkdir('create_v');
		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);

		$result = git::commit_create_v(
			$id,
			$repo,
			'HEAD',
			$sig, $sig,
			null,
			'Hello world!',
			$tree,
		);

		$this->assertOK($result);
		$this->assertSame('4ce6effae5129f525fb2174ef364875e31efd1e4', git::oid_tostr_s($id));

		$this->assertOK(git::commit_lookup($root, $repo, $id));

		$result = git::commit_create_v(
			$id2,
			$repo,
			'HEAD',
			$sig, $sig,
			null,
			'Hello world!',
			$tree,
			$root,
		);

		$this->assertOK($result);
		$this->assertSame('5b3b8cfd195c8120aeb20e9022ccf2410ab0e11b', git::oid_tostr_s($id2));
	}

	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);

		$result = git::commit_create(
			$id,
			$repo,
			'HEAD',
			$sig, $sig,
			null,
			'Hello world!',
			$tree,
			null,
		);

		$this->assertOK($result);
		$this->assertSame('4ce6effae5129f525fb2174ef364875e31efd1e4', git::oid_tostr_s($id));

		$this->assertOK(git::commit_lookup($root, $repo, $id));

		$result = git::commit_create(
			$id2,
			$repo,
			'HEAD',
			$sig, $sig,
			null,
			'Hello world!',
			$tree,
			[$root],
		);

		$this->assertOK($result);
		$this->assertSame('5b3b8cfd195c8120aeb20e9022ccf2410ab0e11b', git::oid_tostr_s($id2));
	}

	public function testCreateBuffer(): 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);

		$result = git::commit_create_buffer(
			$buf,
			$repo,
			$sig, $sig,
			null,
			'Hello world!',
			$tree,
			null,
		);

		$this->assertOK($result);
		$this->assertSame(
			"tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n" .
			"author John Doe <john.doe@example.com> 1640263000 +0100\n" .
			"committer John Doe <john.doe@example.com> 1640263000 +0100\n" .
			"\nHello world!",
			(string) $buf
		);
	}

	public function testAmend(): void
	{
		$dir = $this->mkdir('amend');
		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);

		$result = git::commit_create_v(
			$id,
			$repo,
			'HEAD',
			$sig, $sig,
			null,
			'Hello world!',
			$tree,
		);

		$this->assertOK($result);
		$this->assertOK(git::commit_lookup($commit, $repo, $id));

		$result = git::commit_amend($idAmended, $commit, null, null, null, null, 'Amended!', null);

		$this->assertOK($result);
		$this->assertOK(git::commit_lookup($commitAmended, $repo, $idAmended));
		$this->assertSame('Amended!', git::commit_message($commitAmended));
	}

	public function testAuthorWithMailmap(): void
	{
		$dir = $this->mkdir('author_with_mailmap');
		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', 'john@home', 1640263000, 60);

		$result = git::commit_create_v(
			$id,
			$repo,
			'HEAD',
			$sig, $sig,
			null,
			'Hello world!',
			$tree,
		);

		$this->assertOK($result);
		$this->assertOK(git::commit_lookup($commit, $repo, $id));
		$this->assertOK(git::mailmap_new($mailmap));
		$this->assertOK(git::mailmap_add_entry($mailmap, 'John Doe', 'john.doe@example.com', null, 'john@home'));

		$this->assertOK(git::commit_author_with_mailmap($author, $commit, $mailmap));
		$this->assertInstanceOf(git_signature::class, $author);
		$this->assertSame('John Doe', $author->name);
		$this->assertSame('john.doe@example.com', $author->email);

		$this->assertOK(git::commit_committer_with_mailmap($committer, $commit, $mailmap));
		$this->assertInstanceOf(git_signature::class, $committer);
		$this->assertSame('John Doe', $committer->name);
		$this->assertSame('john.doe@example.com', $committer->email);
	}

	public function testAuthor(): void
	{
		$dir = $this->mkdir('author');
		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_now($aut, 'John Doe', 'john.doe@example.com');
		git::signature_now($com, 'Jane Doe', 'jane.doe@example.com');
		git::commit_create_v($id, $repo, 'HEAD', $aut, $com, null, 'Hello world!', $tree);
		git::commit_lookup($commit, $repo, $id);

		$author = git::commit_author($commit);
		$this->assertNotNull($author);
		$this->assertSame('John Doe', $author->name);

		$committer = git::commit_committer($commit);
		$this->assertNotNull($committer);
		$this->assertSame('Jane Doe', $committer->name);
	}

	public function testLookup(): void
	{
		$dir = $this->mkdir('lookup');
		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_now($sig, 'John Doe', 'john.doe@example.com');
		git::commit_create_v($id, $repo, 'HEAD', $sig, $sig, null, 'Hello world!', $tree);
		$this->assertOK(git::commit_lookup($commit, $repo, $id));
		$this->assertInstanceOf(git_commit::class, $commit);
		$this->assertInstanceOf(git_repository::class, git::commit_owner($commit));
	}

	public function testMessage(): void
	{
		$dir = $this->mkdir('message');
		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, "\nA\n\nB\n", $tree);
		git::commit_lookup($commit, $repo, $id);
		$this->assertSame("A\n\nB\n", git::commit_message($commit));
		$this->assertSame("A", git::commit_summary($commit));
		$this->assertSame("\nA\n\nB\n", git::commit_message_raw($commit));
		$this->assertSame('B', git::commit_body($commit));
		$this->assertNull(git::commit_message_encoding($commit));
		$this->assertSame(1640263000, git::commit_time($commit));
		$this->assertSame(60, git::commit_time_offset($commit));
		$this->assertSame(
			"tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904\n" .
				"author John Doe <john.doe@example.com> 1640263000 +0100\n" .
				"committer John Doe <john.doe@example.com> 1640263000 +0100\n",
			git::commit_raw_header($commit),
		);
	}

	public function testMessageEmptyBody(): void
	{
		$dir = $this->mkdir('message_empty_body');
		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, "A", $tree);
		git::commit_lookup($commit, $repo, $id);
		$this->assertNull(git::commit_body($commit));
	}

	public function testParent(): void
	{
		$dir = $this->mkdir('parent');
		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, "\nA\n\nB\n", $tree);
		git::commit_lookup($commit, $repo, $id);

		$cid = git::commit_id($commit);
		$this->assertSame('775a064dde2e307174887215de8580e0c5e6ca9d', git::oid_tostr_s($cid));

		$this->assertSame(0, git::commit_parentcount($commit));
		$this->assertSame(git_error_code::ENOTFOUND, git::commit_parent($parent, $commit, 0));
		$this->assertNull(git::commit_parent_id($commit, 0));

		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, "\nA\n\nB\n", $tree, $commit);
		git::commit_lookup($commit, $repo, $id);

		$this->assertSame(1, git::commit_parentcount($commit));
		$this->assertOK(git::commit_parent($parent, $commit, 0));
		$this->assertInstanceOf(git_commit::class, $parent);
		$this->assertSame('775a064dde2e307174887215de8580e0c5e6ca9d', git::oid_tostr_s(git::commit_parent_id($commit, 0)));
	}

}