"""Tests for curl_to_fetcher.py - TDD RED phase."""

import sys
from pathlib import Path

import pytest

# Allow importing from the scripts directory regardless of cwd
sys.path.insert(0, str(Path(__file__).parent.parent))

from curl_to_fetcher import parse_curl  # noqa: E402


# ---------------------------------------------------------------------------
# 1. 기본 GET 요청 URL 파싱
# ---------------------------------------------------------------------------
class TestBasicGetUrl:
    def test_simple_url(self) -> None:
        result = parse_curl("curl 'https://example.com'")
        assert result["url"] == "https://example.com"
        assert result["method"] == "GET"

    def test_url_as_last_arg(self) -> None:
        result = parse_curl("curl -H 'Accept: text/html' 'https://example.com'")
        assert result["url"] == "https://example.com"

    def test_url_without_quotes(self) -> None:
        result = parse_curl("curl https://example.com/path?q=1")
        assert result["url"] == "https://example.com/path?q=1"

    def test_minimal_curl(self) -> None:
        """URL만 있는 최소 curl 명령어."""
        result = parse_curl("curl https://example.com")
        assert result["url"] == "https://example.com"
        assert result["method"] == "GET"
        assert result["headers"] == {}
        assert result["cookies"] == {}
        assert result.get("data") is None
        assert result.get("proxy") is None


# ---------------------------------------------------------------------------
# 2. POST 요청 + data
# ---------------------------------------------------------------------------
class TestPostRequest:
    def test_post_with_data_flag(self) -> None:
        result = parse_curl("curl -X POST -d 'key=value' https://example.com")
        assert result["method"] == "POST"
        assert result["data"] == "key=value"

    def test_post_inferred_from_data(self) -> None:
        """--data가 있으면 -X 없어도 POST로 추론."""
        result = parse_curl("curl --data 'key=value' https://example.com")
        assert result["method"] == "POST"
        assert result["data"] == "key=value"

    def test_data_raw(self) -> None:
        result = parse_curl("curl --data-raw 'raw body' https://example.com")
        assert result["data"] == "raw body"
        assert result["method"] == "POST"

    def test_data_binary(self) -> None:
        result = parse_curl("curl --data-binary 'binary body' https://example.com")
        assert result["data"] == "binary body"
        assert result["method"] == "POST"

    def test_post_with_json_data(self) -> None:
        """data가 JSON인 경우."""
        json_body = '{"name": "test", "value": 42}'
        result = parse_curl(
            f"curl -X POST -H 'Content-Type: application/json' " f"-d '{json_body}' https://api.example.com"
        )
        assert result["method"] == "POST"
        assert result["data"] == json_body
        assert result["headers"]["Content-Type"] == "application/json"


# ---------------------------------------------------------------------------
# 3. 헤더 파싱 (-H)
# ---------------------------------------------------------------------------
class TestHeaderParsing:
    def test_single_header(self) -> None:
        result = parse_curl("curl -H 'Accept: text/html' https://example.com")
        assert result["headers"]["Accept"] == "text/html"

    def test_multiple_headers(self) -> None:
        result = parse_curl("curl -H 'Accept: text/html' -H 'Accept-Language: ko' " "https://example.com")
        assert result["headers"]["Accept"] == "text/html"
        assert result["headers"]["Accept-Language"] == "ko"

    def test_header_with_double_quotes(self) -> None:
        result = parse_curl('curl -H "Accept: application/json" https://example.com')
        assert result["headers"]["Accept"] == "application/json"

    def test_long_header_option(self) -> None:
        result = parse_curl("curl --header 'User-Agent: Mozilla/5.0' https://example.com")
        assert result["headers"]["User-Agent"] == "Mozilla/5.0"


# ---------------------------------------------------------------------------
# 4. Cookie 헤더 → cookies dict 분리
# ---------------------------------------------------------------------------
class TestCookieFromHeader:
    def test_cookie_header_extracted_to_cookies(self) -> None:
        result = parse_curl("curl -H 'Cookie: session=abc123; user=xyz' https://example.com")
        assert "Cookie" not in result["headers"]
        assert result["cookies"]["session"] == "abc123"
        assert result["cookies"]["user"] == "xyz"

    def test_cookie_header_does_not_pollute_headers(self) -> None:
        result = parse_curl("curl -H 'Accept: text/html' -H 'Cookie: token=secret' " "https://example.com")
        assert "Cookie" not in result["headers"]
        assert result["cookies"]["token"] == "secret"
        assert result["headers"]["Accept"] == "text/html"


# ---------------------------------------------------------------------------
# 5. -b 쿠키 파싱
# ---------------------------------------------------------------------------
class TestBCookieFlag:
    def test_b_flag_single_cookie(self) -> None:
        result = parse_curl("curl -b 'session=abc123' https://example.com")
        assert result["cookies"]["session"] == "abc123"

    def test_b_flag_multiple_cookies(self) -> None:
        result = parse_curl("curl -b 'session=abc123; user=xyz' https://example.com")
        assert result["cookies"]["session"] == "abc123"
        assert result["cookies"]["user"] == "xyz"

    def test_cookie_long_flag(self) -> None:
        result = parse_curl("curl --cookie 'token=mytoken' https://example.com")
        assert result["cookies"]["token"] == "mytoken"

    def test_b_flag_merges_with_cookie_header(self) -> None:
        """-b 와 -H Cookie: 가 동시에 있으면 병합."""
        result = parse_curl("curl -b 'a=1' -H 'Cookie: b=2' https://example.com")
        assert result["cookies"]["a"] == "1"
        assert result["cookies"]["b"] == "2"


# ---------------------------------------------------------------------------
# 6. 프록시 (-x)
# ---------------------------------------------------------------------------
class TestProxy:
    def test_x_proxy(self) -> None:
        result = parse_curl("curl -x 'http://proxy.example.com:8080' https://example.com")
        assert result["proxy"] == "http://proxy.example.com:8080"

    def test_proxy_long_flag(self) -> None:
        result = parse_curl("curl --proxy 'http://proxy.example.com:3128' https://example.com")
        assert result["proxy"] == "http://proxy.example.com:3128"


# ---------------------------------------------------------------------------
# 7. 멀티라인 curl (\ 줄연결)
# ---------------------------------------------------------------------------
class TestMultilineCurl:
    def test_backslash_line_continuation(self) -> None:
        curl_cmd = "curl 'https://example.com' \\\n" "  -H 'Accept: text/html' \\\n" "  -H 'Accept-Language: ko'"
        result = parse_curl(curl_cmd)
        assert result["url"] == "https://example.com"
        assert result["headers"]["Accept"] == "text/html"
        assert result["headers"]["Accept-Language"] == "ko"

    def test_devtools_style_multiline(self) -> None:
        """실제 DevTools에서 복사한 멀티라인 curl 형식."""
        curl_cmd = (
            "curl 'https://api.example.com/data' \\\n"
            "  -X 'POST' \\\n"
            "  -H 'Content-Type: application/json' \\\n"
            "  -H 'Authorization: Bearer token123' \\\n"
            "  -H 'Cookie: session=abc; csrf=xyz' \\\n"
            '  --data-raw \'{"key": "value"}\''
        )
        result = parse_curl(curl_cmd)
        assert result["url"] == "https://api.example.com/data"
        assert result["method"] == "POST"
        assert result["headers"]["Content-Type"] == "application/json"
        assert result["headers"]["Authorization"] == "Bearer token123"
        assert result["cookies"]["session"] == "abc"
        assert result["cookies"]["csrf"] == "xyz"
        assert result["data"] == '{"key": "value"}'


# ---------------------------------------------------------------------------
# 8. --compressed 무시
# ---------------------------------------------------------------------------
class TestCompressedIgnored:
    def test_compressed_flag_ignored(self) -> None:
        result = parse_curl("curl --compressed 'https://example.com'")
        assert result["url"] == "https://example.com"
        assert "compressed" not in result
        assert result["method"] == "GET"

    def test_compressed_with_other_flags(self) -> None:
        result = parse_curl("curl -H 'Accept: text/html' --compressed 'https://example.com'")
        assert result["url"] == "https://example.com"
        assert result["headers"]["Accept"] == "text/html"
        assert "compressed" not in result


# ---------------------------------------------------------------------------
# 9. 빈/잘못된 입력 에러 처리
# ---------------------------------------------------------------------------
class TestErrorHandling:
    def test_empty_string_raises(self) -> None:
        with pytest.raises(ValueError, match="curl"):
            parse_curl("")

    def test_whitespace_only_raises(self) -> None:
        with pytest.raises(ValueError):
            parse_curl("   ")

    def test_no_url_raises(self) -> None:
        with pytest.raises(ValueError):
            parse_curl("curl -H 'Accept: text/html'")

    def test_missing_curl_command_raises(self) -> None:
        with pytest.raises(ValueError):
            parse_curl("wget https://example.com")


# ---------------------------------------------------------------------------
# 10. PUT / DELETE 메서드
# ---------------------------------------------------------------------------
class TestPutDeleteMethod:
    def test_put_method(self) -> None:
        result = parse_curl("curl -X PUT https://example.com/resource/1")
        assert result["method"] == "PUT"

    def test_delete_method(self) -> None:
        result = parse_curl("curl -X DELETE https://example.com/resource/1")
        assert result["method"] == "DELETE"

    def test_request_long_flag(self) -> None:
        result = parse_curl("curl --request PUT https://example.com/resource/1")
        assert result["method"] == "PUT"


# ---------------------------------------------------------------------------
# 11. 복잡한 DevTools 출력 (다수 헤더 + 쿠키)
# ---------------------------------------------------------------------------
class TestComplexDevToolsOutput:
    def test_full_devtools_curl(self) -> None:
        """실제 DevTools 복사 스타일의 복잡한 명령어."""
        curl_cmd = (
            "curl 'https://www.example.com/api/search?q=test&page=1' \\\n"
            "  -H 'authority: www.example.com' \\\n"
            "  -H 'accept: text/html,application/xhtml+xml' \\\n"
            "  -H 'accept-language: ko-KR,ko;q=0.9' \\\n"
            "  -H 'cookie: _ga=GA1.2.123456789; session_id=abcdef123456; "
            "csrftoken=xyz987' \\\n"
            "  -H 'referer: https://www.example.com/' \\\n"
            "  -H 'user-agent: Mozilla/5.0' \\\n"
            "  --compressed"
        )
        result = parse_curl(curl_cmd)
        assert result["url"] == "https://www.example.com/api/search?q=test&page=1"
        assert result["method"] == "GET"
        assert result["headers"]["accept"] == "text/html,application/xhtml+xml"
        assert result["headers"]["accept-language"] == "ko-KR,ko;q=0.9"
        assert result["headers"]["referer"] == "https://www.example.com/"
        assert result["headers"]["user-agent"] == "Mozilla/5.0"
        assert "cookie" not in result["headers"]
        assert result["cookies"]["_ga"] == "GA1.2.123456789"
        assert result["cookies"]["session_id"] == "abcdef123456"
        assert result["cookies"]["csrftoken"] == "xyz987"
