import importlib
import io
import tempfile
import unittest
from contextlib import redirect_stdout
from pathlib import Path
from unittest import mock


class LoginDouyinModuleTests(unittest.TestCase):
    def test_build_login_command_uses_expected_chrome_arguments(self) -> None:
        module = importlib.import_module("login_douyin")
        command = module.build_login_command(
            chrome_path="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
            profile_dir=Path("/tmp/douyin-profile"),
            browser_port=9223,
            user_url="https://www.douyin.com/user/example",
        )
        self.assertEqual(
            command,
            [
                "open",
                "-na",
                "/Applications/Google Chrome.app",
                "--args",
                "--user-data-dir=/tmp/douyin-profile",
                "--remote-debugging-port=9223",
                "https://www.douyin.com/user/example",
            ],
        )

    def test_build_parser_uses_expected_defaults(self) -> None:
        module = importlib.import_module("login_douyin")
        args = module.build_parser().parse_args([])
        self.assertEqual(args.browser_port, 9223)
        self.assertEqual(args.chrome_path, module.DEFAULT_CHROME_PATH)
        self.assertEqual(args.user_url, module.DEFAULT_USER_URL)

    def test_main_creates_profile_dir_and_prints_next_step(self) -> None:
        module = importlib.import_module("login_douyin")
        with tempfile.TemporaryDirectory() as temp_dir:
            profile_dir = Path(temp_dir) / "profile"
            stdout = io.StringIO()
            with redirect_stdout(stdout):
                with mock.patch.object(module, "launch_browser") as mocked_launch:
                    with mock.patch.object(module, "wait_for_browser_debug_port") as mocked_wait:
                        exit_code = module.main(
                            [
                                "--chrome-path",
                                "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
                                "--profile-dir",
                                str(profile_dir),
                                "--browser-port",
                                "9333",
                            ]
                        )
            self.assertEqual(exit_code, 0)
            self.assertTrue(profile_dir.exists())
            mocked_launch.assert_called_once()
            mocked_wait.assert_called_once_with(9333)
            self.assertIn("9333", stdout.getvalue())
            self.assertIn("./.venv/bin/python Douyin.py --browser-port 9333", stdout.getvalue())

    def test_main_uses_zero_argument_next_step_for_default_browser_port(self) -> None:
        module = importlib.import_module("login_douyin")
        with tempfile.TemporaryDirectory() as temp_dir:
            profile_dir = Path(temp_dir) / "profile"
            stdout = io.StringIO()
            with redirect_stdout(stdout):
                with mock.patch.object(module, "launch_browser"):
                    with mock.patch.object(module, "wait_for_browser_debug_port"):
                        exit_code = module.main(
                            [
                                "--chrome-path",
                                "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
                                "--profile-dir",
                                str(profile_dir),
                            ]
                        )
        self.assertEqual(exit_code, 0)
        self.assertIn("./.venv/bin/python Douyin.py", stdout.getvalue())
        self.assertNotIn("--browser-port 9223", stdout.getvalue())

    def test_main_returns_error_when_chrome_path_missing(self) -> None:
        module = importlib.import_module("login_douyin")
        stdout = io.StringIO()
        with redirect_stdout(stdout):
            exit_code = module.main(["--chrome-path", "/tmp/does-not-exist-chrome"])
        self.assertEqual(exit_code, 1)
        self.assertIn("Chrome", stdout.getvalue())
        self.assertIn("不存在", stdout.getvalue())

    def test_main_returns_error_when_debug_port_never_becomes_ready(self) -> None:
        module = importlib.import_module("login_douyin")
        with tempfile.TemporaryDirectory() as temp_dir:
            profile_dir = Path(temp_dir) / "profile"
            stdout = io.StringIO()
            with redirect_stdout(stdout):
                with mock.patch.object(module, "launch_browser"):
                    with mock.patch.object(
                        module,
                        "wait_for_browser_debug_port",
                        side_effect=RuntimeError("端口未就绪"),
                    ):
                        exit_code = module.main(
                            [
                                "--chrome-path",
                                "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
                                "--profile-dir",
                                str(profile_dir),
                            ]
                        )
        self.assertEqual(exit_code, 1)
        self.assertIn("端口未就绪", stdout.getvalue())


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