"""Deduplication service — prevent outreach to existing connections and cross-campaign duplicates.

Before adding prospects to a campaign, checks against:
1. Existing 1st-degree LinkedIn connections (via Unipile relations API)
2. All contacts across all campaigns in the local DB
3. Optional exclusion list (LinkedIn URLs / public_ids)

This solves the #2 complaint across all AI SDRs: "AI contacted our existing clients."
"""

from __future__ import annotations

import logging
from typing import Any

from ..db.schema import get_db

logger = logging.getLogger(__name__)


def get_all_known_linkedin_ids() -> set[str]:
    """Collect all linkedin_id and public_id values from the global contact base.

    Queries global_contacts (one row per person) for faster dedup than scanning
    all campaign contacts. Falls back to the contacts table if global_contacts
    doesn't exist yet (pre-migration).

    Returns a set of lowercase identifiers (public_ids + linkedin_ids + urls)
    that we have already contacted across all campaigns.
    """
    db = get_db()

    # Try global_contacts first (fast path — one row per person)
    try:
        rows = db.execute(
            """SELECT linkedin_id FROM global_contacts
               WHERE linkedin_id IS NOT NULL AND linkedin_id != ''
               UNION
               SELECT linkedin_url FROM global_contacts
               WHERE linkedin_url IS NOT NULL AND linkedin_url != ''"""
        ).fetchall()
    except Exception:
        # Fallback: old behavior (pre-migration, global_contacts doesn't exist)
        rows = db.execute(
            """SELECT DISTINCT linkedin_id FROM contacts
               WHERE linkedin_id IS NOT NULL AND linkedin_id != ''
               UNION
               SELECT DISTINCT linkedin_url FROM contacts
               WHERE linkedin_url IS NOT NULL AND linkedin_url != ''"""
        ).fetchall()

    db.close()

    ids: set[str] = set()
    for row in rows:
        val = row[0]
        if val:
            ids.add(val.lower().strip())
    return ids


async def fetch_connection_ids(
    client: Any,
    account_id: str,
    max_pages: int = 20,
) -> set[str]:
    """Fetch all 1st-degree connection identifiers from LinkedIn.

    Paginates through the relations API to build a complete set.
    Returns a set of provider_id and public_id values (lowercased).
    """
    all_ids: set[str] = set()

    try:
        relations = await client.get_relations(account_id, limit=100)
        for rel in relations:
            pid = rel.get("provider_id", "")
            pub = rel.get("public_id", "")
            if pid:
                all_ids.add(pid.lower().strip())
            if pub:
                all_ids.add(pub.lower().strip())
                all_ids.add(f"https://www.linkedin.com/in/{pub.lower().strip()}")
    except Exception as e:
        logger.warning("Failed to fetch connections for dedup: %s", e)

    return all_ids


def dedup_prospects(
    prospects: list[dict],
    known_ids: set[str],
    connection_ids: set[str],
    exclusion_ids: set[str] | None = None,
) -> tuple[list[dict], dict[str, int]]:
    """Filter out duplicate and already-known prospects.

    Args:
        prospects: List of prospect dicts from LinkedIn search.
        known_ids: Identifiers already in our contacts DB.
        connection_ids: 1st-degree LinkedIn connection identifiers.
        exclusion_ids: Optional set of manually excluded identifiers.

    Returns:
        (filtered_prospects, stats) where stats has counts for each filter reason.
    """
    exclusion = exclusion_ids or set()
    stats = {
        "total_before": len(prospects),
        "existing_connection": 0,
        "cross_campaign_duplicate": 0,
        "exclusion_list": 0,
        "passed": 0,
    }

    filtered: list[dict] = []

    for prospect in prospects:
        pub_id = (prospect.get("public_id") or "").lower().strip()
        prov_id = (prospect.get("provider_id") or "").lower().strip()
        url = (prospect.get("linkedin_url") or "").lower().strip()

        identifiers = {x for x in (pub_id, prov_id, url) if x}
        if pub_id:
            identifiers.add(f"https://www.linkedin.com/in/{pub_id}")

        # Check 1: existing connection
        if identifiers & connection_ids:
            stats["existing_connection"] += 1
            continue

        # Check 2: cross-campaign duplicate
        if identifiers & known_ids:
            stats["cross_campaign_duplicate"] += 1
            continue

        # Check 3: exclusion list
        if identifiers & exclusion:
            stats["exclusion_list"] += 1
            continue

        stats["passed"] += 1
        filtered.append(prospect)

    return filtered, stats


def format_dedup_summary(stats: dict[str, int]) -> str:
    """Format deduplication stats into a human-readable summary line."""
    removed = stats["total_before"] - stats["passed"]
    if removed == 0:
        return ""

    parts: list[str] = []
    if stats["existing_connection"] > 0:
        parts.append(f"{stats['existing_connection']} existing connections")
    if stats["cross_campaign_duplicate"] > 0:
        parts.append(f"{stats['cross_campaign_duplicate']} cross-campaign duplicates")
    if stats["exclusion_list"] > 0:
        parts.append(f"{stats['exclusion_list']} excluded")

    return f"Filtered {removed} prospects: {', '.join(parts)}"
