"""Tests for autobuilder_hook_helpers.vercel."""

import json
import subprocess
import sys
import time
from pathlib import Path
from unittest.mock import MagicMock, patch

import pytest

sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "hook-helpers"))

from autobuilder_hook_helpers.vercel import (
    _get_latest_deployment,
    get_vercel_preview_url,
    wait_for_vercel_deploy,
)


class TestGetLatestDeployment:
    def test_list_format(self, tmp_path):
        deploy = {"url": "my-app-abc123.vercel.app", "state": "READY"}
        with patch("subprocess.run") as mock_run:
            mock_run.return_value = MagicMock(
                stdout=json.dumps([deploy]),
                returncode=0,
            )
            result = _get_latest_deployment(tmp_path)
        assert result == deploy

    def test_object_format(self, tmp_path):
        deploy = {"url": "my-app-abc123.vercel.app", "state": "READY"}
        with patch("subprocess.run") as mock_run:
            mock_run.return_value = MagicMock(
                stdout=json.dumps({"deployments": [deploy]}),
                returncode=0,
            )
            result = _get_latest_deployment(tmp_path)
        assert result == deploy

    def test_empty_list(self, tmp_path):
        with patch("subprocess.run") as mock_run:
            mock_run.return_value = MagicMock(stdout="[]", returncode=0)
            result = _get_latest_deployment(tmp_path)
        assert result is None

    def test_empty_deployments(self, tmp_path):
        with patch("subprocess.run") as mock_run:
            mock_run.return_value = MagicMock(
                stdout=json.dumps({"deployments": []}),
                returncode=0,
            )
            result = _get_latest_deployment(tmp_path)
        assert result is None

    def test_nonzero_exit(self, tmp_path):
        with patch("subprocess.run") as mock_run:
            mock_run.return_value = MagicMock(stdout="", returncode=1)
            result = _get_latest_deployment(tmp_path)
        assert result is None

    def test_vercel_not_installed(self, tmp_path):
        with patch("subprocess.run", side_effect=FileNotFoundError("vercel")):
            result = _get_latest_deployment(tmp_path)
        assert result is None

    def test_timeout(self, tmp_path):
        with patch("subprocess.run", side_effect=subprocess.TimeoutExpired("vercel", 30)):
            result = _get_latest_deployment(tmp_path)
        assert result is None

    def test_invalid_json(self, tmp_path):
        with patch("subprocess.run") as mock_run:
            mock_run.return_value = MagicMock(stdout="not json", returncode=0)
            result = _get_latest_deployment(tmp_path)
        assert result is None


class TestWaitForVercelDeploy:
    def test_ready_immediately(self, tmp_path):
        deploy = {"url": "my-app-abc123.vercel.app", "state": "READY"}
        with patch(
            "autobuilder_hook_helpers.vercel._get_latest_deployment",
            return_value=deploy,
        ):
            ok, url = wait_for_vercel_deploy(tmp_path, timeout=10)
        assert ok is True
        assert url == "https://my-app-abc123.vercel.app"

    def test_ready_with_https_prefix(self, tmp_path):
        deploy = {"url": "https://my-app.vercel.app", "state": "READY"}
        with patch(
            "autobuilder_hook_helpers.vercel._get_latest_deployment",
            return_value=deploy,
        ):
            ok, url = wait_for_vercel_deploy(tmp_path, timeout=10)
        assert ok is True
        assert url == "https://my-app.vercel.app"

    def test_lowercase_ready(self, tmp_path):
        deploy = {"url": "my-app.vercel.app", "readyState": "ready"}
        with patch(
            "autobuilder_hook_helpers.vercel._get_latest_deployment",
            return_value=deploy,
        ):
            ok, url = wait_for_vercel_deploy(tmp_path, timeout=10)
        assert ok is True

    def test_error_state(self, tmp_path):
        deploy = {"url": "", "state": "ERROR"}
        with patch(
            "autobuilder_hook_helpers.vercel._get_latest_deployment",
            return_value=deploy,
        ):
            ok, url = wait_for_vercel_deploy(tmp_path, timeout=10)
        assert ok is False
        assert url == ""

    def test_canceled_state(self, tmp_path):
        deploy = {"url": "", "state": "CANCELED"}
        with patch(
            "autobuilder_hook_helpers.vercel._get_latest_deployment",
            return_value=deploy,
        ):
            ok, url = wait_for_vercel_deploy(tmp_path, timeout=10)
        assert ok is False

    def test_building_then_ready(self, tmp_path):
        building = {"url": "my-app.vercel.app", "state": "BUILDING"}
        ready = {"url": "my-app.vercel.app", "state": "READY"}
        call_count = [0]

        def mock_get(_):
            call_count[0] += 1
            if call_count[0] <= 2:
                return building
            return ready

        with patch(
            "autobuilder_hook_helpers.vercel._get_latest_deployment",
            side_effect=mock_get,
        ), patch("time.sleep"):
            ok, url = wait_for_vercel_deploy(tmp_path, timeout=60, poll_interval=1)
        assert ok is True
        assert "my-app.vercel.app" in url

    def test_timeout_no_deploy(self, tmp_path):
        with patch(
            "autobuilder_hook_helpers.vercel._get_latest_deployment",
            return_value=None,
        ), patch("time.sleep"), patch("time.time") as mock_time:
            mock_time.side_effect = [0, 0, 100, 200, 700]
            ok, url = wait_for_vercel_deploy(tmp_path, timeout=5, poll_interval=1)
        assert ok is False
        assert url == ""

    def test_timeout_stuck_building(self, tmp_path):
        building = {"url": "my-app.vercel.app", "state": "BUILDING"}
        with patch(
            "autobuilder_hook_helpers.vercel._get_latest_deployment",
            return_value=building,
        ), patch("time.sleep"), patch("time.time") as mock_time:
            mock_time.side_effect = [0, 0, 100, 200, 700]
            ok, url = wait_for_vercel_deploy(tmp_path, timeout=5, poll_interval=1)
        assert ok is False


class TestGetVercelPreviewUrl:
    def test_returns_url(self, tmp_path):
        deploy = {"url": "my-app-abc123.vercel.app", "state": "READY"}
        with patch(
            "autobuilder_hook_helpers.vercel._get_latest_deployment",
            return_value=deploy,
        ):
            url = get_vercel_preview_url(tmp_path)
        assert url == "https://my-app-abc123.vercel.app"

    def test_returns_empty_when_no_deploy(self, tmp_path):
        with patch(
            "autobuilder_hook_helpers.vercel._get_latest_deployment",
            return_value=None,
        ):
            url = get_vercel_preview_url(tmp_path)
        assert url == ""

    def test_preserves_https_prefix(self, tmp_path):
        deploy = {"url": "https://already-prefixed.vercel.app"}
        with patch(
            "autobuilder_hook_helpers.vercel._get_latest_deployment",
            return_value=deploy,
        ):
            url = get_vercel_preview_url(tmp_path)
        assert url == "https://already-prefixed.vercel.app"

    def test_empty_url_field(self, tmp_path):
        deploy = {"url": "", "state": "READY"}
        with patch(
            "autobuilder_hook_helpers.vercel._get_latest_deployment",
            return_value=deploy,
        ):
            url = get_vercel_preview_url(tmp_path)
        assert url == ""
