<?php

declare(strict_types=1);
namespace Tests\git2;
use git2\git;
use git2\git_buf;
use git2\git_error_code;
use git2\git_repository_init_options;
use git2\git_strarray;
use git2\git_worktree;
use git2\git_worktree_add_options;
use git2\git_worktree_prune_options;
use git2\git_worktree_prune_t;

final class WorktreeTest extends GitTestCase
{

	public function testAdd(): void
	{
		$gitDir = $this->mkdir('add_git');
		$wtDir  = $this->mkdir('add_wt');

		git::repository_init($repo, $gitDir, 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', 1640165957, 0);
		git::commit_create_v($id, $repo, 'HEAD', $sig, $sig, null, 'Hello world!', $tree);

		$this->assertOK(git::worktree_add($wt, $repo, 'worktree', $wtDir . '/wt', null));
		$this->assertTrue(is_dir($wtDir . '/wt'));
		$this->assertSame(realpath($wtDir . '/wt'), realpath(git::worktree_path($wt)));
		$this->assertSame('worktree', git::worktree_name($wt));
	}

	public function testAddOptionsInit(): void
	{
		$this->assertOK(git::worktree_add_options_init($opts, git_worktree_add_options::VERSION));
		$this->assertInstanceOf(git_worktree_add_options::class, $opts);
		$this->assertSame(git_worktree_add_options::VERSION, $opts->version);
		$this->assertSame(0, $opts->lock);
	}

	public function testLock(): void
	{
		$gitDir = $this->mkdir('add_git');
		$wtDir  = $this->mkdir('add_wt');
		git::repository_init($repo, $gitDir, 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', 1640165957, 0);
		git::commit_create_v($id, $repo, 'HEAD', $sig, $sig, null, 'Hello world!', $tree);
		git::worktree_add($wt, $repo, 'worktree', $wtDir . '/wt', null);

		$this->assertFalse(git::worktree_is_locked($reason, $wt));
		$this->assertNull($reason);

		$this->assertOK(git::worktree_lock($wt, 'reason'));

		$this->assertTrue(git::worktree_is_locked($reason, $wt));
		$this->assertInstanceOf(git_buf::class, $reason);
		$this->assertSame('reason', (string) $reason);

		$this->assertOK(git::worktree_unlock($wt));
		$this->assertFalse(git::worktree_unlock($wt));

		$this->assertOK(git::worktree_lock($wt, null));

		$this->assertTrue(git::worktree_is_locked($reason, $wt));
		$this->assertInstanceOf(git_buf::class, $reason);
		$this->assertSame('', (string) $reason);

		$this->assertSame(git_error_code::ELOCKED, git::worktree_lock($wt, null));
	}

	public function testPrune(): void
	{
		$gitDir = $this->mkdir('prune_git');
		$wtDir  = $this->mkdir('prune_wt');
		git::repository_init($repo, $gitDir, 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', 1640165957, 0);
		git::commit_create_v($id, $repo, 'HEAD', $sig, $sig, null, 'Hello world!', $tree);
		git::worktree_add($wt, $repo, 'worktree', $wtDir . '/wt', null);

		git::worktree_prune_options_init($opts, git_worktree_prune_options::VERSION);
		$opts->flags = git_worktree_prune_t::VALID;

		$this->assertTrue(git::worktree_is_prunable($wt, $opts));
		$this->assertOK(git::worktree_prune($wt, $opts));
	}

	public function testList(): void
	{
		$gitDir = $this->mkdir('lit_git');
		$wtDir  = $this->mkdir('lit_wt');
		git::repository_init($repo, $gitDir, 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', 1640165957, 0);
		git::commit_create_v($id, $repo, 'HEAD', $sig, $sig, null, 'Hello world!', $tree);
		git::worktree_add($wt, $repo, 'worktree', $wtDir . '/wt', null);

		$this->assertOK(git::worktree_list($list, $repo));
		$this->assertInstanceOf(git_strarray::class, $list);
		$this->assertSame(1, count($list));
		$this->assertSame('worktree', $list[0]);

		$this->assertOK(git::worktree_lookup($out, $repo, $list[0]));
		$this->assertInstanceOf(git_worktree::class, $out);
		$this->assertNotSame($wt, $out);
		$this->assertOK(git::worktree_validate($wt));
	}

}