"""
前程无忧 (51Job) HTTP 层 mock 测试（ARCH-04 / QUAL-03）

使用 unittest.mock.MagicMock 替代真实 HTTP 客户端，无网络依赖。
"""

from __future__ import annotations

from unittest.mock import MagicMock

from spiderJobs.platforms.job51.api import (
    GetCompanyInfo,
    GetJobDetail,
    SearchCompanyJobs,
    SearchRecommendJobs,
    _parse_job51_response,
)
from spiderJobs.platforms.job51.client import Job51Client
from crawler_core.base import Result


# ─────────────────────────────────────────────────────────
# 1. _parse_job51_response 纯函数测试
# ─────────────────────────────────────────────────────────

class TestParseJob51Response:

    def test_http_error_returns_failure(self):
        result = _parse_job51_response(500, {})
        assert result.success is False
        assert result.status_code == 500

    def test_status_zero_returns_failure(self):
        result = _parse_job51_response(200, {"status": 0, "message": "系统繁忙"})
        assert result.success is False
        assert "系统繁忙" in result.error

    def test_status_str_zero_returns_failure(self):
        result = _parse_job51_response(200, {"status": "0", "message": "错误"})
        assert result.success is False

    def test_status_one_with_resultbody_joblist(self):
        raw = {
            "status": 1,
            "resultbody": {
                "jobList": {"items": [{"jobId": "123", "jobName": "Python 工程师"}], "totalCount": 1}
            }
        }
        result = _parse_job51_response(200, raw)
        assert result.success is True
        assert len(result.list) == 1
        assert result.list[0]["jobName"] == "Python 工程师"

    def test_status_one_no_items_is_end_page(self):
        raw = {"status": 1, "resultbody": {"jobList": {"items": []}}}
        result = _parse_job51_response(200, raw)
        assert result.success is True
        assert result.is_end_page is True

    def test_non_dict_raw_returns_failure(self):
        result = _parse_job51_response(200, "not a dict")
        assert result.success is False

    def test_detail_payload(self):
        raw = {"status": 1, "resultbody": {"companyName": "测试公司"}}
        result = _parse_job51_response(200, raw)
        assert result.success is True
        assert result.data["companyName"] == "测试公司"


# ─────────────────────────────────────────────────────────
# 2. SearchRecommendJobs
# ─────────────────────────────────────────────────────────

class TestSearchRecommendJobs:

    def _make_client(self, return_value):
        mock_client = MagicMock()
        mock_client.post.return_value = return_value
        return mock_client

    def test_search_success(self):
        raw = {
            "status": 1,
            "resultbody": {
                "jobList": {"items": [{"jobId": "1", "jobName": "测试职位"}]}
            }
        }
        searcher = SearchRecommendJobs(job_area="020000",
                                       client=self._make_client((200, raw)))
        result = searcher.search(page_index=1)
        assert result.success is True
        assert len(result.list) == 1

    def test_search_http_error(self):
        searcher = SearchRecommendJobs(client=self._make_client((403, {})))
        result = searcher.search(page_index=1)
        assert result.success is False
        assert result.status_code == 403

    def test_search_biz_error(self):
        raw = {"status": 0, "message": "接口限流"}
        searcher = SearchRecommendJobs(client=self._make_client((200, raw)))
        result = searcher.search(page_index=1)
        assert result.success is False


# ─────────────────────────────────────────────────────────
# 3. GetJobDetail（路径拼接版）
# ─────────────────────────────────────────────────────────

class TestGetJobDetail:

    def test_fetch_success(self):
        mock_client = MagicMock()
        mock_client.get.return_value = (200, {
            "status": 1,
            "resultbody": {"jobName": "数据工程师", "salary": "20k-30k"},
        })
        fetcher = GetJobDetail(job_id="170651439", client=mock_client)
        result = fetcher.fetch()
        assert result.success is True
        assert result.data["jobName"] == "数据工程师"

    def test_fetch_exception_handled(self):
        mock_client = MagicMock()
        mock_client.get.side_effect = ConnectionError("网络超时")
        fetcher = GetJobDetail(job_id="123", client=mock_client)
        result = fetcher.fetch()
        assert result.success is False
        assert "网络超时" in result.error

    def test_fetch_http_error(self):
        mock_client = MagicMock()
        mock_client.get.return_value = (404, {})
        fetcher = GetJobDetail(job_id="nonexist", client=mock_client)
        result = fetcher.fetch()
        assert result.success is False
        assert result.status_code == 404


# ─────────────────────────────────────────────────────────
# 4. GetCompanyInfo
# ─────────────────────────────────────────────────────────

class TestGetCompanyInfo:

    def test_fetch_success(self):
        mock_client = MagicMock()
        mock_client.get.return_value = (200, {
            "status": 1,
            "resultbody": {"companyName": "测试科技有限公司", "coId": "9825088"},
        })
        fetcher = GetCompanyInfo(company_id="9825088", client=mock_client)
        result = fetcher.fetch()
        assert result.success is True
        assert result.data["companyName"] == "测试科技有限公司"

    def test_fetch_exception(self):
        mock_client = MagicMock()
        mock_client.get.side_effect = TimeoutError("请求超时")
        fetcher = GetCompanyInfo(company_id="123", client=mock_client)
        result = fetcher.fetch()
        assert result.success is False


# ─────────────────────────────────────────────────────────
# 5. SearchCompanyJobs
# ─────────────────────────────────────────────────────────

class TestSearchCompanyJobs:

    def test_search_success(self):
        mock_client = MagicMock()
        mock_client.post.return_value = (200, {
            "status": 1,
            "resultbody": {"items": [{"jobId": "1"}], "totalCount": 1},
        })
        searcher = SearchCompanyJobs(company_id="9825088", client=mock_client)
        result = searcher.search(page_index=1)
        assert result.success is True
        assert len(result.list) == 1

    def test_search_empty(self):
        mock_client = MagicMock()
        mock_client.post.return_value = (200, {
            "status": 1,
            "resultbody": {"items": [], "totalCount": 0},
        })
        searcher = SearchCompanyJobs(company_id="9825088", client=mock_client)
        result = searcher.search(page_index=1)
        assert result.success is True
        assert result.is_end_page is True


# ─────────────────────────────────────────────────────────
# 6. Job51Client — sign 注入
# ─────────────────────────────────────────────────────────

class TestJob51ClientHeaders:

    def test_headers_contain_sign(self):
        client = Job51Client()
        headers = client._job51_headers(sign="test_sign_value")
        assert headers["sign"] == "test_sign_value"

    def test_headers_uuid_format(self):
        client = Job51Client()
        headers = client._job51_headers(sign="abc")
        assert len(headers["uuid"]) >= 20

    def test_headers_empty_account(self):
        client = Job51Client()
        headers = client._job51_headers(sign="xyz")
        assert headers["user-token"] == ""
        assert headers["account-id"] == ""
