"""Funnel timing metrics and campaign-level rollups."""

from typing import Any

from models import CampaignRollup, Person


def compute_funnel_times(people: list[Person]) -> list[Person]:
    """Populate days_to_newsletter and days_to_newspaper on each Person.

    Both metrics are measured from `first_touch_at`. If the newsletter signup or
    newspaper conversion *is* the first touch, the corresponding field is 0.0.
    """
    for p in people:
        if p.first_touch_at and p.newsletter_subscribed_at:
            p.days_to_newsletter = _days_between(p.first_touch_at, p.newsletter_subscribed_at)
        if p.first_touch_at and p.newspaper_subscribed_at:
            p.days_to_newspaper = _days_between(p.first_touch_at, p.newspaper_subscribed_at)
    return people


def _days_between(start, end) -> float:
    return (end - start).total_seconds() / 86400.0


def rollup_campaigns(
    people: list[Person],
    fb_campaigns: dict[str, dict[str, Any]],
) -> list[CampaignRollup]:
    """Aggregate person-level outcomes by Facebook campaign.

    For each campaign we know spend for, count distinct leads, the leads who became
    newsletter subscribers, and the leads who became newspaper subscribers — then
    derive cost-per-X metrics. Returns an empty list when no spend data is available.
    """
    if not fb_campaigns:
        return []

    leads_by_campaign: dict[str, set[str]] = {cid: set() for cid in fb_campaigns}
    nl_by_campaign: dict[str, set[str]] = {cid: set() for cid in fb_campaigns}
    np_by_campaign: dict[str, set[str]] = {cid: set() for cid in fb_campaigns}

    for p in people:
        cid = p.facebook_campaign_id
        if cid is None or cid not in leads_by_campaign:
            continue
        if p.facebook_lead_at is None:
            continue
        leads_by_campaign[cid].add(p.email)
        if p.newsletter_subscribed_at:
            nl_by_campaign[cid].add(p.email)
        if p.newspaper_subscribed_at:
            np_by_campaign[cid].add(p.email)

    results: list[CampaignRollup] = []
    for cid, info in fb_campaigns.items():
        leads_n = len(leads_by_campaign[cid])
        nl_n = len(nl_by_campaign[cid])
        np_n = len(np_by_campaign[cid])
        spend = float(info.get("spend_usd", 0))
        results.append(
            CampaignRollup(
                campaign_id=cid,
                campaign_name=info.get("campaign_name", ""),
                spend_usd=spend,
                leads_count=leads_n,
                newsletter_subscribers=nl_n,
                newspaper_subscribers=np_n,
                cost_per_lead=spend / leads_n if leads_n else None,
                cost_per_newsletter_subscriber=spend / nl_n if nl_n else None,
                cost_per_newspaper_subscriber=spend / np_n if np_n else None,
            )
        )
    return results
