from __future__ import annotations

from collections.abc import Generator
from pathlib import Path
from unittest.mock import patch

import pygit2
import pytest
from fastapi.testclient import TestClient

from pygittools.merge import MR_REF_PREFIX, MergeRequest
from pygitweb.config import settings
from pygitweb.main import app


def _commit_chain(repo: pygit2.Repository) -> tuple[pygit2.Oid, pygit2.Oid]:
	sig = pygit2.Signature("tester", "tester@example.com")
	tb = repo.TreeBuilder()
	tree = tb.write()
	a = repo.create_commit(None, sig, sig, "a", tree, [])
	repo.create_reference("refs/heads/main", a)
	b = repo.create_commit(None, sig, sig, "b", tree, [a])
	return a, b


class TestMergeRequestTagView:
	@pytest.fixture
	def mr_env(self, tmp_path: Path) -> Generator[dict[str, str], None, None]:
		root: Path = tmp_path / "merge-requests-web"
		root.mkdir()
		repo_dir: Path = root / "demo"
		repo_dir.mkdir()
		repo = pygit2.init_repository(str(repo_dir), bare=False)
		_a, b = _commit_chain(repo)
		mr = MergeRequest(
			b,
			pygit2.Signature("tester", "tester@example.com"),
			ours="refs/heads/main",
			title="Feature MR",
			description="Desc line",
			name=f"{MR_REF_PREFIX}aaaabbbbccccdddd",
		)
		mr_oid = mr.write(repo)
		projects_list: Path = root / "projects.list"
		projects_list.write_text("demo tester\n", encoding="utf-8")
		with (
			patch.object(settings, "PROJECTROOT", str(root)),
			patch.object(settings, "PROJECTS_LIST", str(projects_list)),
			patch.object(settings, "STRICT_EXPORT", False),
			patch.object(settings, "EXPORT_OK", ""),
			patch.object(settings, "AUTH", False),
		):
			client = TestClient(app)
			yield {
				"client": client,
				"project": "demo",
				"mr_tag_oid": str(mr_oid),
				"mr_ref": mr.name,
				"tip_b": str(b),
			}

	def test_tag_action_renders_merge_request_template(self, mr_env: dict[str, str]) -> None:
		client = mr_env["client"]
		resp = client.get(
			f"/project/{mr_env['project']}",
			params={"a": "tag", "h": mr_env["mr_tag_oid"]},
		)
		assert resp.status_code == 200
		text = resp.text
		assert "Merge request" in text
		assert "Feature MR" in text
		assert "Desc line" in text
		assert "Can fast-forward" in text
		assert "refs/heads/main" in text

	def test_merge_ff_updates_branch(self, mr_env: dict[str, str]) -> None:
		client = mr_env["client"]
		post = client.post(
			"/mr/ff",
			params={"project": mr_env["project"], "h": mr_env["mr_tag_oid"]},
			follow_redirects=False,
		)
		assert post.status_code == 303
		repo = pygit2.Repository(str(Path(settings.PROJECTROOT) / mr_env["project"]))
		assert repo.references["refs/heads/main"].resolve().target == pygit2.Oid(hex=mr_env["tip_b"])