from __future__ import annotations

import httpx

from email_enrichment.harvester import (
    _extract_emails_for_domain,
    harvest_crt_sh,
    harvest_domain,
    harvest_duckduckgo,
    harvest_github,
)


def test_extract_emails_filters_by_domain():
    text = (
        "contact: jon@dasaninc.com and noise foo@other.com; "
        "admin@DASANINC.COM duplicate"
    )
    out = _extract_emails_for_domain(text, "dasaninc.com")
    assert out == ["jon@dasaninc.com", "admin@dasaninc.com"]


def test_crt_sh_parses_name_value():
    payload = [
        {"name_value": "CN=*.dasaninc.com\nadmin@dasaninc.com"},
        {"name_value": "security@dasaninc.com"},
        {"name_value": "foo@other.com"},
    ]

    def handler(request: httpx.Request) -> httpx.Response:
        assert request.url.host == "crt.sh"
        return httpx.Response(200, json=payload)

    with httpx.Client(transport=httpx.MockTransport(handler)) as client:
        emails = harvest_crt_sh("dasaninc.com", client)
    assert "admin@dasaninc.com" in emails
    assert "security@dasaninc.com" in emails
    assert "foo@other.com" not in emails


def test_crt_sh_handles_502_gracefully():
    def handler(request: httpx.Request) -> httpx.Response:
        return httpx.Response(502, text="bad gateway")

    with httpx.Client(transport=httpx.MockTransport(handler)) as client:
        emails = harvest_crt_sh("dasaninc.com", client)
    assert emails == []


def test_duckduckgo_extracts_from_html():
    html = """
    <html><body>
    <a class="result__a" href="...">contact jmitchell@dasaninc.com today</a>
    <div class="result__snippet">Reach us at info@dasaninc.com</div>
    <div>Unrelated: foo@bar.com</div>
    </body></html>
    """

    def handler(request: httpx.Request) -> httpx.Response:
        return httpx.Response(200, text=html)

    with httpx.Client(transport=httpx.MockTransport(handler)) as client:
        emails = harvest_duckduckgo("dasaninc.com", client)
    assert "jmitchell@dasaninc.com" in emails
    assert "info@dasaninc.com" in emails
    assert "foo@bar.com" not in emails


def test_duckduckgo_handles_ratelimit():
    def handler(request: httpx.Request) -> httpx.Response:
        return httpx.Response(429, text="slow down")

    with httpx.Client(transport=httpx.MockTransport(handler)) as client:
        emails = harvest_duckduckgo("dasaninc.com", client)
    assert emails == []


def test_harvest_domain_unions_sources_and_dedupes():
    def handler(request: httpx.Request) -> httpx.Response:
        if request.url.host == "crt.sh":
            return httpx.Response(200, json=[{"name_value": "alice@dasaninc.com"}])
        if request.url.host == "html.duckduckgo.com":
            return httpx.Response(
                200,
                text="alice@dasaninc.com and bob@dasaninc.com",
            )
        return httpx.Response(404)

    with httpx.Client(transport=httpx.MockTransport(handler)) as client:
        result = harvest_domain(
            "dasaninc.com", sources=("crt_sh", "duckduckgo"), client=client
        )
    assert set(result.emails) == {"alice@dasaninc.com", "bob@dasaninc.com"}
    assert result.per_source["crt_sh"] == ["alice@dasaninc.com"]
    assert set(result.per_source["duckduckgo"]) == {
        "alice@dasaninc.com",
        "bob@dasaninc.com",
    }


def test_github_extracts_emails_from_items(monkeypatch):
    monkeypatch.setenv("GITHUB_TOKEN", "ghp_test")

    payload = {
        "items": [
            {
                "name": "config.yml",
                "path": "deploy/config.yml",
                "text_matches": [{"fragment": "owner: admin@dasaninc.com"}],
            },
            {
                "name": "README.md",
                "path": "README.md",
                "text_matches": [{"fragment": "contact eng-lead@dasaninc.com"}],
            },
        ]
    }

    def handler(request: httpx.Request) -> httpx.Response:
        assert request.headers.get("Authorization") == "Bearer ghp_test"
        return httpx.Response(200, json=payload)

    with httpx.Client(transport=httpx.MockTransport(handler)) as client:
        emails = harvest_github("dasaninc.com", client)
    assert "admin@dasaninc.com" in emails
    assert "eng-lead@dasaninc.com" in emails


def test_github_skipped_without_token(monkeypatch):
    monkeypatch.delenv("GITHUB_TOKEN", raising=False)

    def handler(request: httpx.Request) -> httpx.Response:
        raise AssertionError("should not be called when GITHUB_TOKEN is missing")

    with httpx.Client(transport=httpx.MockTransport(handler)) as client:
        assert harvest_github("dasaninc.com", client) == []
