"""Run the pipeline through stitch + metrics and print stats. No Sheets writing.

Useful for validating the join logic and exploring the funnel before any output
goes to Google Sheets, and for debugging without round-tripping through Sheets.
"""

from collections import Counter
from statistics import mean, median

import yaml
from dotenv import load_dotenv

from pipeline import metrics, normalize, stitch
from sources import mailchimp, stripe_source


def main() -> None:
    load_dotenv()
    with open("config.yaml") as f:
        config = yaml.safe_load(f)

    print("=" * 60)
    print("Funnel Tracker - stitch + metrics validation")
    print("=" * 60)

    raw_members = mailchimp.fetch_members(config)
    raw_customers = stripe_source.fetch_customers(config)
    fb_leads: list = []  # Facebook source not implemented yet

    mc_members = [normalize.mailchimp_member(r) for r in raw_members]
    stripe_customers = [normalize.stripe_customer(r) for r in raw_customers]

    print(
        f"\nInputs: {len(mc_members)} Mailchimp members, "
        f"{len(stripe_customers)} Stripe customers, "
        f"{len(fb_leads)} Facebook leads"
    )

    people = stitch.build_people(fb_leads, mc_members, stripe_customers)
    people = metrics.compute_funnel_times(people)
    print(f"Stitched: {len(people)} unique people\n")

    _print_overlap(people)
    _print_first_touch(people)
    _print_funnel_times(people)
    _print_status(people)


def _print_overlap(people: list) -> None:
    has_newsletter = sum(1 for p in people if p.newsletter_subscribed_at)
    has_newspaper = sum(1 for p in people if p.newspaper_subscribed_at)
    both = sum(
        1 for p in people if p.newsletter_subscribed_at and p.newspaper_subscribed_at
    )
    only_newsletter = has_newsletter - both
    only_newspaper = has_newspaper - both
    conv_rate = (100 * both / has_newsletter) if has_newsletter else 0.0

    print("Audience overlap")
    print(f"  Newsletter subscribers:        {has_newsletter:>6}")
    print(f"    of which only newsletter:    {only_newsletter:>6}")
    print(f"    of which also newspaper:     {both:>6}")
    print(f"  Newspaper subscribers:         {has_newspaper:>6}")
    print(f"    of which only newspaper:     {only_newspaper:>6}")
    print(f"  Newsletter -> newspaper rate:  {conv_rate:>6.2f}%")
    print()


def _print_first_touch(people: list) -> None:
    counts = Counter(p.first_touch_source for p in people)
    print("First-touch source")
    for src, c in counts.most_common():
        print(f"  {src:<12} {c:>6}")
    print()


def _print_funnel_times(people: list) -> None:
    times_newspaper = [
        p.days_to_newspaper for p in people if p.days_to_newspaper is not None
    ]
    if times_newspaper:
        print(f"Days to newspaper subscription (n={len(times_newspaper)})")
        _print_distribution(times_newspaper)
        print()

    times_newsletter = [
        p.days_to_newsletter
        for p in people
        if p.days_to_newsletter is not None and p.days_to_newsletter > 0
    ]
    if times_newsletter:
        print(
            f"Days from earlier first-touch to newsletter (n={len(times_newsletter)}, "
            "excludes newsletter-was-first-touch)"
        )
        _print_distribution(times_newsletter)
        print()


def _print_distribution(values: list[float]) -> None:
    sorted_v = sorted(values)
    n = len(sorted_v)
    p10 = sorted_v[max(0, n // 10 - 1)]
    p90 = sorted_v[min(n - 1, 9 * n // 10)]
    print(f"  mean:   {mean(values):>8.1f}")
    print(f"  median: {median(values):>8.1f}")
    print(f"  p10:    {p10:>8.1f}")
    print(f"  p90:    {p90:>8.1f}")
    print(f"  min:    {min(values):>8.1f}")
    print(f"  max:    {max(values):>8.1f}")


def _print_status(people: list) -> None:
    counts = Counter(
        p.newspaper_subscription_status
        for p in people
        if p.newspaper_subscription_status
    )
    if not counts:
        return
    print("Current newspaper subscription status (Stripe)")
    for status, c in counts.most_common():
        print(f"  {status:<15} {c:>6}")


if __name__ == "__main__":
    main()
