"""Tests for list_prs.py, view_pr.py, and delete_branch.py.

Mocks api_request and credentials.
"""
import sys
import unittest
import io
import contextlib
from unittest.mock import patch

sys.path.insert(0, str(__import__("pathlib").Path(__file__).resolve().parent.parent))
import list_prs  # noqa: E402
import view_pr  # noqa: E402
import delete_branch  # noqa: E402
import edit_pr  # noqa: E402


FAKE_CREDS = "Basic dGVzdHVzZXI6dGVzdHBhc3M="


class TestListPRs(unittest.TestCase):

    @patch("list_prs.api_request")
    @patch("list_prs.get_auth_header", return_value=FAKE_CREDS)
    def test_list_prs_success(self, _auth, mock_api):
        mock_api.return_value = [
            {"number": 1, "title": "PR 1", "head": {"ref": "branch1"}, "base": {"ref": "main"}, "html_url": "http://url1", "mergeable": True}
        ]
        with contextlib.redirect_stdout(io.StringIO()), contextlib.redirect_stderr(io.StringIO()):
            rc = list_prs.main([])
        self.assertEqual(rc, 0)
        mock_api.assert_called_once()

    @patch("list_prs.api_request", return_value=[])
    @patch("list_prs.get_auth_header", return_value=FAKE_CREDS)
    def test_list_prs_empty(self, _auth, mock_api):
        with contextlib.redirect_stdout(io.StringIO()), contextlib.redirect_stderr(io.StringIO()):
            rc = list_prs.main(["--state", "closed"])
        self.assertEqual(rc, 0)
        mock_api.assert_called_once()


class TestViewPR(unittest.TestCase):

    @patch("view_pr.api_request")
    @patch("view_pr.get_auth_header", return_value=FAKE_CREDS)
    def test_view_pr_success(self, _auth, mock_api):
        mock_api.return_value = {"number": 1, "title": "PR 1", "state": "open", "user": {"login": "user1"}, "head": {"ref": "branch1"}, "base": {"ref": "main"}, "html_url": "http://url1", "mergeable": True, "body": "PR description"}
        rc = view_pr.main(["1"])
        self.assertEqual(rc, 0)
        mock_api.assert_called_once()

    def test_missing_pr_number_exits(self):
        with self.assertRaises(SystemExit):
            view_pr.main([])


class TestDeleteBranch(unittest.TestCase):

    @patch("delete_branch.api_request")
    @patch("delete_branch.get_auth_header", return_value=FAKE_CREDS)
    def test_delete_branch_success(self, _auth, mock_api):
        rc = delete_branch.main(["feat/my-branch"])
        self.assertEqual(rc, 0)
        mock_api.assert_called_once()

    def test_missing_branch_exits(self):
        with self.assertRaises(SystemExit):
            delete_branch.main([])


class TestEditPR(unittest.TestCase):

    @patch("edit_pr.api_request")
    @patch("edit_pr.get_auth_header", return_value=FAKE_CREDS)
    def test_edit_pr_success(self, _auth, mock_api):
        mock_api.return_value = {
            "number": 1,
            "title": "New Title",
            "state": "open",
            "html_url": "http://url1",
            "base": {"ref": "main"},
            "body": "New Description"
        }
        rc = edit_pr.main(["1", "--title", "New Title", "--body", "New Description"])
        self.assertEqual(rc, 0)
        mock_api.assert_called_once()
        # Verify call payload
        payload = mock_api.call_args[0][3]
        self.assertEqual(payload["title"], "New Title")
        self.assertEqual(payload["body"], "New Description")

    @patch("edit_pr.get_auth_header", return_value=FAKE_CREDS)
    def test_missing_fields_fails(self, _auth):
        rc = edit_pr.main(["1"])
        self.assertEqual(rc, 1)

    def test_missing_pr_number_exits(self):
        with self.assertRaises(SystemExit):
            edit_pr.main([])


if __name__ == "__main__":
    unittest.main()
