"""Live, destructive end-to-end exercise for every AbuseIPDB SDK operation."""

from __future__ import annotations

import argparse
import os
import sys
from collections.abc import Callable
from datetime import datetime, timezone
from pprint import pformat

from abuseipdb import AbuseCategory, AbuseIPDB

REQUIRED_ENV = (
    "ABUSEIPDB_API_KEY",
    "ABUSEIPDB_E2E_CHECK_IP",
    "ABUSEIPDB_E2E_REPORT_IP",
    "ABUSEIPDB_E2E_BULK_IP",
    "ABUSEIPDB_E2E_NETWORK",
)


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="Call every AbuseIPDB endpoint and print each result."
    )
    parser.add_argument(
        "--allow-writes",
        action="store_true",
        help=(
            "Required acknowledgement: report, bulk-report, and clear-address modify account data."
        ),
    )
    return parser.parse_args()


def require_configuration(allow_writes: bool) -> dict[str, str]:
    missing = [name for name in REQUIRED_ENV if not os.getenv(name)]
    if missing:
        names = ", ".join(missing)
        raise ValueError(f"Missing required environment variables: {names}")
    if not allow_writes:
        raise ValueError(
            "Refusing destructive live calls without --allow-writes. "
            "This submits reports, then clears them."
        )
    values = {name: os.environ[name] for name in REQUIRED_ENV}
    if values["ABUSEIPDB_E2E_REPORT_IP"] == values["ABUSEIPDB_E2E_BULK_IP"]:
        raise ValueError(
            "Report and bulk-report IPs must differ to avoid duplicate-report rejection."
        )
    return values


def run_call(
    name: str,
    operation: Callable[[], object],
    results: list[tuple[str, bool]],
) -> object | None:
    print(f"\n{'=' * 72}\n{name}\n{'=' * 72}")
    try:
        output = operation()
    except (
        Exception
    ) as error:  # Manual diagnostic runner must continue through remaining endpoints.
        results.append((name, False))
        print(f"[FAIL] {type(error).__name__}: {error}")
        response = getattr(error, "response", None)
        if response is not None:
            print(f"HTTP body: {response.text}")
        return None
    results.append((name, True))
    print("[PASS]")
    print(pformat(output, sort_dicts=False))
    return output


def main() -> int:
    args = parse_args()
    try:
        config = require_configuration(args.allow_writes)
    except ValueError as error:
        print(error, file=sys.stderr)
        return 2

    results: list[tuple[str, bool]] = []
    check_ip = config["ABUSEIPDB_E2E_CHECK_IP"]
    report_ip = config["ABUSEIPDB_E2E_REPORT_IP"]
    bulk_ip = config["ABUSEIPDB_E2E_BULK_IP"]
    network = config["ABUSEIPDB_E2E_NETWORK"]

    print("LIVE E2E: write endpoints enabled. Reports will be cleared after submission.")
    with AbuseIPDB(api_key=config["ABUSEIPDB_API_KEY"], timeout=30.0) as client:
        run_call("check", lambda: client.check(check_ip, verbose=True), results)
        run_call("reports", lambda: client.reports(check_ip, per_page=5), results)
        run_call("blacklist (JSON)", lambda: client.blacklist(limit=10), results)
        run_call(
            "blacklist (plaintext)",
            lambda: client.blacklist(limit=10, plaintext=True),
            results,
        )
        run_call("check_block", lambda: client.check_block(network), results)
        run_call(
            "report",
            lambda: client.report(
                report_ip,
                [AbuseCategory.WEB_APP_ATTACK],
                comment="abuseipdb-python-sdk 0.1.0 live E2E test",
                timestamp=datetime.now(timezone.utc),
            ),
            results,
        )
        run_call("clear_address (report cleanup)", lambda: client.clear_address(report_ip), results)

        csv_timestamp = datetime.now(timezone.utc).isoformat()
        csv_contents = (
            "IP,Categories,ReportDate,Comment\n"
            f'{bulk_ip},21,{csv_timestamp},"abuseipdb-python-sdk 0.1.0 live E2E test"\n'
        )
        run_call("bulk_report", lambda: client.bulk_report(csv_contents), results)
        run_call("clear_address (bulk cleanup)", lambda: client.clear_address(bulk_ip), results)

    print(f"\n{'=' * 72}\nSUMMARY\n{'=' * 72}")
    for name, passed in results:
        print(f"[{'PASS' if passed else 'FAIL'}] {name}")
    passed = sum(success for _, success in results)
    print(f"\n{passed}/{len(results)} calls succeeded")
    return 0 if passed == len(results) else 1


if __name__ == "__main__":
    raise SystemExit(main())
