"""Tests for autobuilder_hook_helpers.deploy."""

import subprocess
import sys
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.deploy import (
    _resolve_deploy_script,
    health_check,
    run_deploy_script,
    store_deploy_url,
)


class TestResolveDeployScript:
    def test_explicit_absolute(self, tmp_path):
        script = tmp_path / "my-deploy.sh"
        script.write_text("#!/bin/bash\necho ok\n")
        path, is_proj = _resolve_deploy_script(tmp_path, str(script))
        assert path == script
        assert is_proj is True

    def test_explicit_relative(self, tmp_path):
        script = tmp_path / "deploy.sh"
        script.write_text("#!/bin/bash\necho ok\n")
        path, is_proj = _resolve_deploy_script(tmp_path, "deploy.sh")
        assert path == script
        assert is_proj is True

    def test_explicit_missing(self, tmp_path):
        path, is_proj = _resolve_deploy_script(tmp_path, "nonexistent.sh")
        assert path is None

    def test_project_level(self, tmp_path):
        script = tmp_path / "deploy.sh"
        script.write_text("#!/bin/bash\necho ok\n")
        path, is_proj = _resolve_deploy_script(tmp_path, None)
        assert path == script
        assert is_proj is True

    def test_no_script_found(self, tmp_path):
        path, is_proj = _resolve_deploy_script(tmp_path, None)
        assert path is None


class TestRunDeployScript:
    def test_project_level_success(self, tmp_path):
        script = tmp_path / "deploy.sh"
        script.write_text("#!/bin/bash\necho deployed\n")
        with patch("subprocess.run") as mock_run:
            mock_run.return_value = MagicMock(
                stdout="deployed\n", stderr="", returncode=0,
            )
            ok, output = run_deploy_script(tmp_path, "myapp", 3080)
        assert ok is True
        assert "deployed" in output

    def test_deploy_failure(self, tmp_path):
        script = tmp_path / "deploy.sh"
        script.write_text("#!/bin/bash\nexit 1\n")
        with patch("subprocess.run") as mock_run:
            mock_run.return_value = MagicMock(
                stdout="", stderr="build failed\n", returncode=1,
            )
            ok, output = run_deploy_script(tmp_path, "myapp", 3080)
        assert ok is False

    def test_timeout(self, tmp_path):
        script = tmp_path / "deploy.sh"
        script.write_text("#!/bin/bash\nsleep 999\n")
        with patch("subprocess.run", side_effect=subprocess.TimeoutExpired("bash", 600)):
            ok, output = run_deploy_script(tmp_path, "myapp", 3080, timeout=600)
        assert ok is False
        assert "timed out" in output.lower()

    def test_no_script_returns_ok(self, tmp_path):
        ok, output = run_deploy_script(tmp_path, "myapp", 3080)
        assert ok is True
        assert "skipping" in output.lower()

    def test_custom_deploy_script(self, tmp_path):
        script = tmp_path / "custom.sh"
        script.write_text("#!/bin/bash\necho custom\n")
        with patch("subprocess.run") as mock_run:
            mock_run.return_value = MagicMock(
                stdout="custom\n", stderr="", returncode=0,
            )
            ok, output = run_deploy_script(
                tmp_path, "myapp", 3080, deploy_script=str(script),
            )
        assert ok is True

    def test_server_app_name_override(self, tmp_path):
        script = tmp_path / "deploy.sh"
        script.write_text("#!/bin/bash\necho ok\n")
        with patch("subprocess.run") as mock_run:
            mock_run.return_value = MagicMock(
                stdout="ok\n", stderr="", returncode=0,
            )
            run_deploy_script(
                tmp_path, "myapp", 3080, server_app_name="alt-name",
            )


class TestHealthCheck:
    def test_passes_on_200(self):
        with patch("subprocess.run") as mock_run, patch("time.sleep"):
            mock_run.return_value = MagicMock(
                stdout="200", returncode=0,
            )
            assert health_check("https://example.com", attempts=3) is True

    def test_passes_on_301(self):
        with patch("subprocess.run") as mock_run, patch("time.sleep"):
            mock_run.return_value = MagicMock(
                stdout="301", returncode=0,
            )
            assert health_check("https://example.com", attempts=3) is True

    def test_fails_on_500(self):
        with patch("subprocess.run") as mock_run, patch("time.sleep"):
            mock_run.return_value = MagicMock(
                stdout="500", returncode=0,
            )
            assert health_check("https://example.com", attempts=2, interval=0) is False

    def test_eventual_success(self):
        responses = [
            MagicMock(stdout="503", returncode=0),
            MagicMock(stdout="503", returncode=0),
            MagicMock(stdout="200", returncode=0),
        ]
        with patch("subprocess.run", side_effect=responses), patch("time.sleep"):
            assert health_check("https://example.com", attempts=5) is True

    def test_exception_counts_as_000(self):
        with patch("subprocess.run", side_effect=OSError("fail")), \
             patch("time.sleep"):
            assert health_check("https://example.com", attempts=1) is False


class TestStoreDeployUrl:
    def test_writes_file(self, tmp_path):
        proj = tmp_path / "project"
        proj.mkdir()
        (proj / ".autobuilder").mkdir()
        store_deploy_url(proj, "https://myapp.example.com")
        content = (proj / ".autobuilder" / "deploy_url").read_text()
        assert content.strip() == "https://myapp.example.com"

    def test_creates_directories(self, tmp_path):
        proj = tmp_path / "project"
        proj.mkdir()
        store_deploy_url(proj, "https://myapp.example.com")
        assert (proj / ".autobuilder" / "deploy_url").exists()
