import json
import subprocess
import sys

from click.testing import CliRunner

from abip import __version__
from abip import api
from abip.cli import main


class FakeClient:
    def __init__(self, *args, **kwargs):
        self.check_payload = {
            "data": {
                "ipAddress": "8.8.8.8",
                "abuseConfidenceScore": 42,
                "countryCode": "US",
                "countryName": "United States",
                "isp": "Example ISP",
                "domain": "example.com",
                "usageType": "Data Center/Web Hosting/Transit",
                "totalReports": 3,
                "numDistinctUsers": 2,
                "isPublic": True,
                "isWhitelisted": False,
                "isTor": False,
            }
        }

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        return False

    def check_ip(self, ip_address, max_age_days=30, verbose=False):
        payload = dict(self.check_payload)
        payload["data"] = dict(self.check_payload["data"])
        payload["data"]["ipAddress"] = ip_address
        payload["meta"] = {"maxAgeInDays": max_age_days, "verbose": verbose}
        return payload

    def check_block(self, network, max_age_days=30):
        return {
            "data": {
                "networkAddress": network,
                "netmask": "255.255.255.0",
                "minAddress": "203.0.113.0",
                "maxAddress": "203.0.113.255",
                "numPossibleHosts": 256,
                "addressSpaceDesc": "TEST-NET-3",
                "reportedAddress": [],
            },
            "meta": {"maxAgeInDays": max_age_days},
        }

    def report_ip(self, ip_address, categories, comment, timestamp=None):
        return {
            "data": {
                "ipAddress": ip_address,
                "categories": categories,
                "comment": comment,
                "timestamp": timestamp,
                "abuseConfidenceScore": 99,
            }
        }

    def blacklist(
        self,
        confidence_minimum=25,
        limit=10000,
        ip_version=None,
        only_countries=None,
    ):
        return {
            "meta": {"generatedAt": "2026-03-18T00:00:00Z"},
            "data": [
                {
                    "ipAddress": "203.0.113.10",
                    "abuseConfidenceScore": confidence_minimum,
                    "lastReportedAt": "2026-03-17T00:00:00Z",
                    "countryCode": only_countries or "US",
                }
            ][:limit],
        }


def test_version_option():
    result = CliRunner().invoke(main, ["--version"])

    assert result.exit_code == 0
    assert __version__ in result.output


def test_check_command_json(monkeypatch):
    monkeypatch.setattr(api, "AbuseIPDBClient", FakeClient)

    result = CliRunner().invoke(main, ["--json", "check", "8.8.8.8", "--days", "10"])

    assert result.exit_code == 0
    payload = json.loads(result.output)
    assert payload["data"]["ipAddress"] == "8.8.8.8"
    assert payload["meta"]["maxAgeInDays"] == 10


def test_block_command_human_output(monkeypatch):
    monkeypatch.setattr(api, "AbuseIPDBClient", FakeClient)

    result = CliRunner().invoke(main, ["block", "203.0.113.0/24"])

    assert result.exit_code == 0
    assert "Checking block:" in result.output
    assert "203.0.113.0/24" in result.output


def test_report_command_json(monkeypatch):
    monkeypatch.setattr(api, "AbuseIPDBClient", FakeClient)

    result = CliRunner().invoke(
        main,
        [
            "--json",
            "report",
            "203.0.113.10",
            "--categories",
            "18,22",
            "--comment",
            "SSH brute-force attempts",
        ],
    )

    assert result.exit_code == 0
    payload = json.loads(result.output)
    assert payload["data"]["categories"] == "18,22"


def test_blacklist_command_json(monkeypatch):
    monkeypatch.setattr(api, "AbuseIPDBClient", FakeClient)

    result = CliRunner().invoke(
        main,
        [
            "--json",
            "blacklist",
            "--min-confidence",
            "80",
            "--limit",
            "1",
            "--countries",
            "US",
        ],
    )

    assert result.exit_code == 0
    payload = json.loads(result.output)
    assert payload["data"][0]["abuseConfidenceScore"] == 80
    assert payload["data"][0]["countryCode"] == "US"


def test_check_command_error(monkeypatch):
    class FailingClient:
        def __enter__(self):
            return self

        def __exit__(self, exc_type, exc_val, exc_tb):
            return False

        def check_ip(self, *args, **kwargs):
            raise api.AbuseIPDBError("bad request", 400)

    monkeypatch.setattr(api, "AbuseIPDBClient", FailingClient)

    result = CliRunner().invoke(main, ["check", "8.8.8.8"])

    assert result.exit_code == 1
    assert "bad request" in result.output


def test_module_invocation_help():
    result = subprocess.run(
        [sys.executable, "-m", "abip", "--help"],
        capture_output=True,
        text=True,
        check=False,
    )

    assert result.returncode == 0
    assert "Usage:" in result.stdout
