import asyncio
import logging
from datetime import datetime, timezone
from typing import Any, Dict, List, Optional
import httpx

logger = logging.getLogger(__name__)


async def fetch_securitytrails_history(
    domain: str,
    record_type: str,
    api_key: str,
) -> List[Dict[str, Any]]:
    """
    Query SecurityTrails API for historical DNS records.
    Endpoint: GET https://api.securitytrails.com/v1/history/{domain}/dns/{type}
    """
    if not api_key:
        return []

    rtype = record_type.lower()
    url = f"https://api.securitytrails.com/v1/history/{domain.strip().lower()}/dns/{rtype}"
    headers = {"APIKEY": api_key, "Accept": "application/json"}

    try:
        async with httpx.AsyncClient(timeout=15.0) as client:
            resp = await client.get(url, headers=headers)
            if resp.status_code == 200:
                data = resp.json()
                records = data.get("records", [])
                formatted = []
                for rec in records:
                    values = rec.get("values", [])
                    first_seen = rec.get("first_seen")
                    last_seen = rec.get("last_seen")
                    organizations = rec.get("organizations", [])

                    for v in values:
                        val_str = v.get("ip") or v.get("nameserver") or v.get("value") or v.get("host") or str(v)
                        formatted.append({
                            "source": "SecurityTrails",
                            "record_type": record_type.upper(),
                            "value": val_str,
                            "first_seen": first_seen,
                            "last_seen": last_seen,
                            "organization": ", ".join(organizations) if organizations else None,
                        })
                return formatted
    except Exception as e:
        logger.warning(f"SecurityTrails lookup failed for {domain}: {e}")
    return []


async def fetch_alienvault_otx_history(domain: str) -> List[Dict[str, Any]]:
    """
    Free passive DNS history from AlienVault OTX.
    Endpoint: https://otx.alienvault.com/api/v1/indicators/domain/{domain}/passive_dns
    """
    clean_domain = domain.strip().lower()
    url = f"https://otx.alienvault.com/api/v1/indicators/domain/{clean_domain}/passive_dns"
    records = []

    try:
        async with httpx.AsyncClient(timeout=12.0) as client:
            resp = await client.get(url)
            if resp.status_code == 200:
                data = resp.json()
                passive_records = data.get("passive_dns", [])
                for item in passive_records:
                    rec_type = item.get("record_type", "A").upper()
                    address = item.get("address", "")
                    first_seen = item.get("first")
                    last_seen = item.get("last")
                    asn = item.get("asn", "")

                    if address:
                        records.append({
                            "source": "AlienVault OTX (Passive DNS)",
                            "record_type": rec_type,
                            "value": address,
                            "first_seen": first_seen,
                            "last_seen": last_seen,
                            "organization": asn or None,
                        })
    except Exception as e:
        logger.warning(f"AlienVault OTX lookup failed for {domain}: {e}")

    return records


async def fetch_crtsh_subdomains(domain: str) -> List[Dict[str, Any]]:
    """
    Free Certificate Transparency historical log lookup via crt.sh.
    Discovers historical hostnames, subdomains, and validity dates.
    """
    clean_domain = domain.strip().lower()
    url = f"https://crt.sh/?q=%.{clean_domain}&output=json"
    results = []

    try:
        async with httpx.AsyncClient(timeout=15.0) as client:
            resp = await client.get(url)
            if resp.status_code == 200:
                data = resp.json()
                seen = set()
                for item in data:
                    name_value = item.get("name_value", "")
                    for sub in name_value.splitlines():
                        sub = sub.strip().lower()
                        if sub and sub not in seen:
                            seen.add(sub)
                            results.append({
                                "subdomain": sub,
                                "logged_at": item.get("entry_timestamp"),
                                "issuer_name": item.get("issuer_name"),
                            })
    except Exception as e:
        logger.warning(f"crt.sh lookup failed for {domain}: {e}")

    return results


async def get_aggregated_historical_dns(
    domain: str,
    record_type: str = "A",
    securitytrails_api_key: Optional[str] = None,
) -> Dict[str, Any]:
    """
    Aggregate historical DNS records across SecurityTrails (if configured),
    AlienVault OTX passive DNS, and crt.sh.
    """
    tasks = [
        fetch_alienvault_otx_history(domain),
        fetch_crtsh_subdomains(domain),
    ]
    if securitytrails_api_key:
        tasks.append(fetch_securitytrails_history(domain, record_type, securitytrails_api_key))

    completed = await asyncio.gather(*tasks, return_exceptions=True)

    otx_records = completed[0] if isinstance(completed[0], list) else []
    subdomains = completed[1] if isinstance(completed[1], list) else []
    st_records = completed[2] if len(completed) > 2 and isinstance(completed[2], list) else []

    # Merge records
    all_history = st_records + [
        r for r in otx_records if r["record_type"].upper() == record_type.upper() or record_type.upper() == "ALL"
    ]

    return {
        "domain": domain,
        "record_type": record_type.upper(),
        "total_historical_records": len(all_history),
        "history": all_history,
        "subdomains_count": len(subdomains),
        "subdomains": subdomains[:50],  # Return up to 50 subdomains
    }
