"""Enrich company name from domain using FoundryGraph Gold tier.

Uses the FoundryGraph serving layer (GCS artifact) for fresh data,
with fallback to local wikidata_profiles if unavailable.
"""

import logging
import os
from typing import Dict, Any, Optional, List
from functools import lru_cache

from ..services.foundrygraph_bq import lookup_company_by_domain

__transform_id__ = "enrich_company_name"
__version__ = "2.1.0"
__updated__ = "2026-01-22"

log = logging.getLogger(__name__)


def _is_b2c_domain(domain: str) -> bool:
    """Check if domain is a consumer/freemail domain that shouldn't be enriched.

    These domains (gmail.com, yahoo.com, etc.) are email providers, not companies
    that should have their names looked up for B2B use cases.

    Uses the comprehensive B2C bloom filter (57K+ domains) for accurate checking.
    """
    if not domain:
        return False

    normalized = domain.strip().lower()
    if normalized.startswith("www."):
        normalized = normalized[4:]

    # Try the comprehensive B2C bloom filter first (57K+ domains)
    try:
        from fmatch.core.b2c_bloom_filter import is_b2c_domain as bloom_is_b2c
        return bloom_is_b2c(normalized)
    except ImportError:
        pass

    # Fallback to heuristics FREEMAIL_DOMAINS
    try:
        from fmatch.core.heuristics import FREEMAIL_DOMAINS, TEMP_DOMAINS
        return normalized in FREEMAIL_DOMAINS or normalized in TEMP_DOMAINS
    except ImportError:
        pass

    # Last resort: minimal fallback
    B2C_FALLBACK = {
        "gmail.com", "yahoo.com", "hotmail.com", "outlook.com", "live.com",
        "aol.com", "icloud.com", "me.com", "protonmail.com", "proton.me",
        "mail.com", "gmx.com", "qq.com", "163.com", "mail.ru", "yandex.com",
    }
    return normalized in B2C_FALLBACK


def _is_foundrygraph_disabled() -> bool:
    """Check if FoundryGraph lookups are disabled via env."""
    value = os.getenv("FM_DISABLE_FOUNDRYGRAPH", "").strip().lower()
    return value in ("1", "true", "yes", "on")


def _allow_local_fallback() -> bool:
    value = os.getenv("FM_DISABLE_LOCAL_FOUNDRYGRAPH", "").strip().lower()
    if value in ("1", "true", "yes", "on"):
        return False
    env = os.getenv("ENV", "").strip().lower()
    return env in ("development", "dev", "local")


@lru_cache(maxsize=1000)
def normalize_domain(url_or_domain: str) -> str:
    """Extract and normalize domain from URL or domain string."""
    if not url_or_domain:
        return ""

    s = url_or_domain.strip().lower()
    if "://" not in s:
        s = "http://" + s

    try:
        from urllib.parse import urlparse

        parsed = urlparse(s)
        domain = parsed.hostname or parsed.path.split("/")[0]
        # Remove www prefix
        if domain and domain.startswith("www."):
            domain = domain[4:]
        return domain or ""
    except:
        return ""


def _lookup_foundrygraph(domain: Optional[str]) -> Optional[Dict[str, Any]]:
    """
    Query FoundryGraph Gold tier for company name.

    Uses FoundryGraph BigQuery tables for fresh data.
    """
    normalized_domain = (domain or "").lower().strip()
    if not normalized_domain:
        return None
    if normalized_domain.startswith("www."):
        normalized_domain = normalized_domain[4:]

    row = lookup_company_by_domain(normalized_domain)
    if row and row.get("label"):
        log.debug(
            "FoundryGraph BQ hit for %s: %s (Q=%s)",
            normalized_domain,
            row.get("label"),
            row.get("quality_score"),
        )
        return {
            "name": row.get("label"),
            "wikidata_id": row.get("wikidata_id"),
            "family_id": None,
            "is_primary": None,
            "quality_score": row.get("quality_score"),
            "source": row.get("source", "foundrygraph_bq"),
        }

    return None


def _lookup_wikidata_fallback(domain: Optional[str]) -> Optional[Dict[str, Any]]:
    """Fallback to local wikidata_profiles if FoundryGraph unavailable."""
    try:
        import os

        if os.getenv("FM_COMPANY_TO_DOMAIN_WIKIDATA", "true").lower() != "true":
            return None

        from . import wikidata_profiles

        normalized_domain = (domain or "").lower()
        if not normalized_domain:
            return None

        profile = wikidata_profiles.get_profile_for_domain(normalized_domain)
        if not profile:
            return None

        label = profile.get("label")
        if label:
            return {
                "name": label,
                "wikidata_id": profile.get("wikidata_id"),
                "aliases": profile.get("aliases", []),
                "source": "wikidata_local",
            }

        return None

    except Exception:
        return None


def enrich_company_name(
    company: Optional[str] = None,
    website: Optional[str] = None,
    domain: Optional[str] = None,
) -> Dict[str, Any]:
    """
    Enrich company with canonical name from Wikidata/FoundryGraph.

    Given a domain (e.g., cisco.com), returns the official company name
    (e.g., "Cisco Systems, Inc."). This is useful for fixing typos or
    standardizing company names when you have domain data.

    Args:
        company: Company name (not used currently, reserved for future fuzzy matching)
        website: Company website URL
        domain: Domain (if already extracted)

    Returns:
        Dict with company name information.

    Examples:
        >>> enrich_company_name(domain="cisco.com")
        {"company_name": "Cisco Systems", "confidence": 1.0}
        >>> enrich_company_name(website="https://www.microsoft.com")
        {"company_name": "Microsoft Corporation", "confidence": 1.0}
    """
    # Try domain first, then extract from website
    effective_domain = domain
    if not effective_domain and website:
        effective_domain = normalize_domain(website)

    if not effective_domain:
        return {
            "company_name": "",
            "confidence": 0.0,
            "source": None,
            "warning": "FoundryGraph lookup requires a domain",
        }

    # Skip B2C/freemail domains - these are email providers, not B2B companies
    if _is_b2c_domain(effective_domain):
        return {
            "company_name": "",
            "confidence": 0.0,
            "source": None,
            "skipped": True,
            "skip_reason": "b2c_domain",
            "warning": f"Skipped B2C/freemail domain: {effective_domain}",
        }

    warning = None
    fg_disabled = _is_foundrygraph_disabled()
    if fg_disabled:
        warning = "FoundryGraph lookups disabled (FM_DISABLE_FOUNDRYGRAPH=1)"

    # Try FoundryGraph via BigQuery first
    result = None
    if not fg_disabled:
        result = _lookup_foundrygraph(effective_domain)

    # Fallback to local wikidata_profiles only in dev when allowed
    if not result and _allow_local_fallback():
        result = _lookup_wikidata_fallback(effective_domain)

    if result and result.get("name"):
        response = {
            "company_name": result["name"],
            "wikidata_id": result.get("wikidata_id"),
            "family_id": result.get("family_id"),
            "quality_score": result.get("quality_score"),
            "aliases": result.get("aliases", []),
            "confidence": 0.95 if result.get("source") == "foundrygraph_gold" else 0.8,
            "source": result.get("source", "wikidata"),
        }
        if warning:
            response["warning"] = warning
        return response

    # No match found
    response = {
        "company_name": "",
        "confidence": 0.0,
        "source": None,
    }
    if warning:
        response["warning"] = warning
    return response


def transform(values: List[str], params: Dict[str, Any] = None) -> List[List[str]]:
    """
    Transform function for batch processing domains -> company names.

    Uses batch BigQuery lookup for efficiency (1 query instead of N queries).

    Args:
        values: List of domains or websites
        params: Optional parameters (unused currently)

    Returns:
        List of [company_name] for each input
    """
    from ..services.foundrygraph_bq import lookup_companies_by_domain

    # Normalize all domains upfront and track B2C status
    normalized_domains = []
    b2c_domains = set()
    for val in values:
        domain = normalize_domain(val) if val else ""
        normalized_domains.append(domain)
        if domain and _is_b2c_domain(domain):
            b2c_domains.add(domain)

    # Collect non-empty, non-B2C domains for batch lookup
    domains_to_lookup = [d for d in normalized_domains if d and d not in b2c_domains]

    # Single batch BigQuery lookup (instead of N individual queries)
    batch_results = {}
    if domains_to_lookup and not _is_foundrygraph_disabled():
        batch_results = lookup_companies_by_domain(domains_to_lookup)

    if b2c_domains:
        log.debug("Skipped %d B2C domains: %s", len(b2c_domains), list(b2c_domains)[:5])

    # Map results back to original order
    results = []
    for domain in normalized_domains:
        # Skip B2C domains - return empty
        if domain in b2c_domains:
            results.append([""])
            continue
        if domain and domain in batch_results:
            label = batch_results[domain].get("label", "")
            results.append([label])
        else:
            # Try local fallback for misses (only in dev)
            if domain and _allow_local_fallback():
                fallback = _lookup_wikidata_fallback(domain)
                if fallback and fallback.get("name"):
                    results.append([fallback["name"]])
                    continue
            results.append([""])

    return results
