"""Tests for #1118 — api() retries on network errors (stale keep-alive after idle)."""
import re


def _src() -> str:
    with open("static/workspace.js") as f:
        return f.read()


class TestApiRetryOnNetworkError:
    """The api() function in workspace.js should retry on fetch TypeError (network failure)."""

    def test_api_function_has_retry_loop(self):
        """api() must contain a retry loop (for/while with attempt counter)."""
        src = _src()
        assert re.search(r'for\s*\(\s*let\s+\w+\s*=\s*0\s*;', src), \
            "api() must have a for loop with attempt counter"

    def test_api_retries_on_typeerror(self):
        """api() must retry when fetch throws TypeError (network failure)."""
        src = _src()
        # Find the api function body
        m = re.search(r'async function api\(path,opts.*?\n\}(?!\n[\s]*function)', src, re.DOTALL)
        assert m, "api() function must exist"
        body = m.group(0)
        assert 'TypeError' in body, \
            "api() must check for TypeError to detect network failures"
        assert 'attempt' in body, \
            "api() must track attempt count for retry logic"

    def test_api_does_not_retry_http_errors(self):
        """api() must NOT retry on HTTP error responses (4xx/5xx) — only network failures."""
        src = _src()
        m = re.search(r'async function api\(path,opts.*?\n\}(?!\n[\s]*function)', src, re.DOTALL)
        assert m, "api() function must exist"
        body = m.group(0)
        # The retry should be in catch block (after res.ok check), not in the ok path
        # HTTP errors throw Error (not TypeError), so only TypeError triggers retry
        assert 'e instanceof TypeError' in body, \
            "api() retry must be limited to TypeError (network errors), not all errors"

    def test_api_max_3_attempts(self):
        """api() must limit retries (max 3 attempts total = 1 initial + 2 retries)."""
        src = _src()
        m = re.search(r'async function api\(path,opts.*?\n\}(?!\n[\s]*function)', src, re.DOTALL)
        assert m, "api() function must exist"
        body = m.group(0)
        # Should have attempt < 2 (0, 1, 2 = 3 attempts max)
        assert re.search(r'attempt\s*<\s*2', body), \
            "api() must limit to 3 attempts max (attempt < 2)"

    def test_api_preserves_401_redirect(self):
        """api() must still redirect to login on 401 without escaping subpath mounts."""
        src = _src()
        assert "res.status===401" in src, \
            "api() must still check for 401 status"
        assert "login?next=" in src, \
            "api() must still redirect to login on 401"
        assert "/login?next=" not in src, \
            "api() must not escape subpath mounts by redirecting to root /login"

    def test_api_preserves_error_parsing(self):
        """api() must still parse JSON error bodies for non-200 responses."""
        src = _src()
        assert "JSON.parse(text)" in src, \
            "api() must still parse JSON error responses"
        assert "res.json()" in src, \
            "api() must still parse JSON success responses"
