"""Collector: company_follower_collector — Track new followers on company LinkedIn pages.

Polls GET /api/v1/users/followers to detect new followers over time.
Saves SIGNAL_COMPANY_FOLLOWER for each new follower.

Runs every 4 hours via the scheduler.
"""

from __future__ import annotations

import json
import logging
import time

from ..constants import (
    SIGNAL_COMPANY_FOLLOWER,
    SIGNAL_TTL_COMPANY_FOLLOWER,
)
from ..linkedin.circuit_breaker import CircuitBreakerOpen, CollectorCircuitBreaker

logger = logging.getLogger(__name__)

_cb = CollectorCircuitBreaker("company_followers")


async def collect_company_followers() -> str:
    """Collect new follower signals from company LinkedIn pages.

    For each company watchlist entry:
    1. Call get_followers() for the company account
    2. Diff against previously seen followers (stored in watchlist keywords)
    3. Save new followers as SIGNAL_COMPANY_FOLLOWER signals

    Note: This requires the company page admin to have connected their
    LinkedIn account via Unipile. The followers endpoint may not be
    available for all company pages — gracefully skips on failure.

    Returns summary string.
    """
    from ..db.async_bridge import run_db
    from ..db.signal_queries import (
        batch_signal_exists,
        list_watchlists,
        save_signal,
        update_watchlist,
        upsert_signal_account,
    )
    from ..linkedin import get_account_id, get_linkedin_client

    account_id = get_account_id()
    if not account_id:
        return "No LinkedIn account connected — skipping follower collection."

    client = get_linkedin_client()
    try:
        # Get company-type watchlists
        watchlists = await run_db(list_watchlists, is_active=True)
        company_watchlists = [w for w in watchlists if w.get("watch_type") == "company"]

        if not company_watchlists:
            return "No company watchlists configured."

        total_new = 0
        errors = 0
        now = int(time.time())

        for wl in company_watchlists:
            wl_id = wl["id"]
            company_name = wl.get("name", "Unknown Company")
            campaign_id = wl.get("campaign_id")

            try:
                # Get followers — use company-specific endpoint for numeric IDs
                keywords_list = wl.get("keywords_list", [])
                company_id = keywords_list[0] if keywords_list else ""
                if company_id.isdigit():
                    followers = await _cb.call(
                        client.get_followers(account_id, company_id=company_id),
                        label=f"get_followers({company_name})",
                    )
                else:
                    followers = await _cb.call(
                        client.get_followers(account_id),
                        label="get_followers(personal)",
                    )

                if not followers:
                    continue

                # Batch dedup: pre-fetch existing signals for all followers
                follower_dedup_keys = []
                follower_id_map: dict[str, tuple[str, str]] = {}  # dedup_key -> (follower_id, follower_name)
                for follower in followers:
                    fid = follower.get("provider_id") or follower.get("id", "")
                    fname = follower.get("name", "") or follower.get("full_name", "")
                    if fid:
                        dk = f"cf:{wl_id}:{fid}"
                        follower_dedup_keys.append(dk)
                        follower_id_map[dk] = (fid, fname)
                existing_signals = await run_db(
                    batch_signal_exists,
                    SIGNAL_COMPANY_FOLLOWER, post_ids=follower_dedup_keys,
                )

                for follower in followers:
                    follower_id = follower.get("provider_id") or follower.get("id", "")
                    follower_name = follower.get("name", "") or follower.get("full_name", "")

                    if not follower_id:
                        continue

                    dedup_key = f"cf:{wl_id}:{follower_id}"

                    if dedup_key in existing_signals:
                        continue

                    metadata = {
                        "company_name": company_name,
                        "follower_name": follower_name,
                        "follower_id": follower_id,
                        "follower_headline": follower.get("headline", ""),
                        "follower_url": follower.get("profile_url", ""),
                    }

                    await run_db(
                        save_signal,
                        signal_type=SIGNAL_COMPANY_FOLLOWER,
                        source="company_page",
                        prospect_name=follower_name,
                        linkedin_id=follower_id,
                        campaign_id=campaign_id,
                        content=f"New follower of {company_name}: {follower_name}",
                        post_id=dedup_key,
                        metadata_json=json.dumps(metadata),
                        expires_at=now + SIGNAL_TTL_COMPANY_FOLLOWER,
                    )
                    await run_db(
                        upsert_signal_account,
                        linkedin_id=follower_id,
                        prospect_name=follower_name,
                    )
                    total_new += 1

                # Update last polled timestamp
                await run_db(update_watchlist, wl_id, last_polled_at=now)

            except CircuitBreakerOpen as e:
                logger.warning("Skipping follower collection: %s", e)
                break
            except Exception as e:
                logger.warning(
                    "Follower collection failed for '%s': %s (endpoint may not be available for company pages)",
                    company_name, e,
                )
                errors += 1

        # ── Personal follower fallback ──
        # When company page followers returned zero (Voyager broken), collect
        # personal profile followers via the standard Unipile API instead.
        personal_new = 0
        if total_new == 0:
            try:
                personal_followers = await _cb.call(
                    client.get_followers(account_id),
                    label="get_followers(personal_fallback)",
                )
                if personal_followers:
                    # Use first active campaign for attribution
                    fallback_campaign_id = (
                        company_watchlists[0].get("campaign_id") if company_watchlists else None
                    )
                    # Batch dedup for personal followers
                    pf_dedup_keys = []
                    for f in personal_followers:
                        fid = f.get("provider_id") or f.get("id", "")
                        if fid:
                            pf_dedup_keys.append(f"pf:{fid}")
                    pf_existing = await run_db(
                        batch_signal_exists,
                        SIGNAL_COMPANY_FOLLOWER, post_ids=pf_dedup_keys,
                    )

                    for follower in personal_followers:
                        follower_id = follower.get("provider_id") or follower.get("id", "")
                        follower_name = follower.get("name", "") or follower.get("full_name", "")
                        if not follower_id:
                            continue

                        dedup_key = f"pf:{follower_id}"
                        if dedup_key in pf_existing:
                            continue

                        metadata = {
                            "source": "personal_profile",
                            "follower_name": follower_name,
                            "follower_id": follower_id,
                            "follower_headline": follower.get("headline", ""),
                            "follower_url": follower.get("profile_url", ""),
                        }
                        await run_db(
                            save_signal,
                            signal_type=SIGNAL_COMPANY_FOLLOWER,
                            source="personal_profile",
                            prospect_name=follower_name,
                            linkedin_id=follower_id,
                            campaign_id=fallback_campaign_id,
                            content=f"New personal profile follower: {follower_name}",
                            post_id=dedup_key,
                            metadata_json=json.dumps(metadata),
                            expires_at=now + SIGNAL_TTL_COMPANY_FOLLOWER,
                        )
                        await run_db(
                            upsert_signal_account,
                            linkedin_id=follower_id,
                            prospect_name=follower_name,
                        )
                        personal_new += 1

            except Exception as e:
                logger.debug("Personal follower fallback failed: %s", e)

        summary = f"Checked {len(company_watchlists)} company pages, found {total_new} new followers"
        if personal_new:
            summary += f", {personal_new} personal profile followers"
        if errors:
            summary += f", {errors} errors"
        return summary
    finally:
        await client.close()
