#!/usr/bin/env python3
"""
X/Twitter Growth Tracker — Track and analyze account growth over time.

Stores periodic snapshots of account metrics and calculates growth trends,
engagement patterns, and milestone projections.

Usage:
    python3 growth_tracker.py --record --handle @user --followers 5200 --eng-rate 2.1
    python3 growth_tracker.py --report --handle @user
    python3 growth_tracker.py --report --handle @user --period 30d --json
    python3 growth_tracker.py --milestone --handle @user --target 10000
"""

import argparse
import json
import os
import sys
from datetime import datetime, timedelta
from pathlib import Path

DATA_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", ".growth-data")


def get_data_file(handle: str) -> str:
    clean = handle.lstrip("@").lower()
    os.makedirs(DATA_DIR, exist_ok=True)
    return os.path.join(DATA_DIR, f"{clean}.jsonl")


def record_snapshot(handle: str, followers: int, following: int = 0,
                    eng_rate: float = 0, posts_week: float = 0, notes: str = ""):
    entry = {
        "timestamp": datetime.now().isoformat(),
        "handle": handle,
        "followers": followers,
        "following": following,
        "engagement_rate": eng_rate,
        "posts_per_week": posts_week,
        "notes": notes,
    }

    filepath = get_data_file(handle)
    with open(filepath, "a") as f:
        f.write(json.dumps(entry) + "\n")

    return entry


def load_snapshots(handle: str, period_days: int = 0) -> list:
    filepath = get_data_file(handle)
    if not os.path.exists(filepath):
        return []

    entries = []
    cutoff = None
    if period_days > 0:
        cutoff = datetime.now() - timedelta(days=period_days)

    with open(filepath) as f:
        for line in f:
            line = line.strip()
            if not line:
                continue
            entry = json.loads(line)
            if cutoff:
                ts = datetime.fromisoformat(entry["timestamp"])
                if ts < cutoff:
                    continue
            entries.append(entry)

    return entries


def generate_report(handle: str, entries: list) -> dict:
    if not entries:
        return {"handle": handle, "error": "No data found"}

    report = {
        "handle": handle,
        "data_points": len(entries),
        "first_record": entries[0]["timestamp"],
        "last_record": entries[-1]["timestamp"],
        "current_followers": entries[-1]["followers"],
    }

    if len(entries) >= 2:
        first = entries[0]
        last = entries[-1]

        follower_change = last["followers"] - first["followers"]
        days_span = (datetime.fromisoformat(last["timestamp"]) -
                     datetime.fromisoformat(first["timestamp"])).days
        days_span = max(days_span, 1)

        report["follower_change"] = follower_change
        report["days_tracked"] = days_span
        report["daily_growth"] = round(follower_change / days_span, 1)
        report["weekly_growth"] = round((follower_change / days_span) * 7, 1)
        report["monthly_projection"] = round((follower_change / days_span) * 30)

        if first["followers"] > 0:
            pct_change = ((last["followers"] - first["followers"]) / first["followers"]) * 100
            report["growth_percent"] = round(pct_change, 1)

        # Engagement trend
        eng_rates = [e["engagement_rate"] for e in entries if e.get("engagement_rate", 0) > 0]
        if len(eng_rates) >= 2:
            mid = len(eng_rates) // 2
            first_half_avg = sum(eng_rates[:mid]) / mid
            second_half_avg = sum(eng_rates[mid:]) / (len(eng_rates) - mid)
            report["engagement_trend"] = "improving" if second_half_avg > first_half_avg else "declining"
            report["avg_engagement_rate"] = round(sum(eng_rates) / len(eng_rates), 2)

    return report


def project_milestone(handle: str, entries: list, target: int) -> dict:
    if len(entries) < 2:
        return {"error": "Need at least 2 data points for projection"}

    current = entries[-1]["followers"]
    if current >= target:
        return {"handle": handle, "target": target, "status": "Already reached!"}

    first = entries[0]
    last = entries[-1]
    days_span = (datetime.fromisoformat(last["timestamp"]) -
                 datetime.fromisoformat(first["timestamp"])).days
    days_span = max(days_span, 1)

    daily_growth = (last["followers"] - first["followers"]) / days_span

    if daily_growth <= 0:
        return {"handle": handle, "target": target, "status": "Not growing — can't project",
                "daily_growth": round(daily_growth, 1)}

    remaining = target - current
    days_needed = remaining / daily_growth
    target_date = datetime.now() + timedelta(days=days_needed)

    return {
        "handle": handle,
        "current": current,
        "target": target,
        "remaining": remaining,
        "daily_growth": round(daily_growth, 1),
        "days_needed": round(days_needed),
        "projected_date": target_date.strftime("%Y-%m-%d"),
    }


def print_report(report: dict):
    print(f"\n{'='*60}")
    print(f"  GROWTH REPORT — {report['handle']}")
    print(f"{'='*60}")

    if "error" in report:
        print(f"\n  ⚠️  {report['error']}")
        print(f"  Record data first: python3 growth_tracker.py --record --handle {report['handle']} --followers N")
        print()
        return

    print(f"\n  Current followers:    {report['current_followers']:,}")
    print(f"  Data points:         {report['data_points']}")
    print(f"  Tracking since:      {report['first_record'][:10]}")

    if "follower_change" in report:
        change_icon = "📈" if report["follower_change"] > 0 else "📉" if report["follower_change"] < 0 else "➡️"
        print(f"\n  {change_icon} Change:  {report['follower_change']:+,} followers over {report['days_tracked']} days")
        print(f"  Daily avg:           {report.get('daily_growth', 0):+.1f}/day")
        print(f"  Weekly avg:          {report.get('weekly_growth', 0):+.1f}/week")
        print(f"  30-day projection:   {report.get('monthly_projection', 0):+,}")

        if "growth_percent" in report:
            print(f"  Growth rate:         {report['growth_percent']:+.1f}%")

        if "engagement_trend" in report:
            trend_icon = "📈" if report["engagement_trend"] == "improving" else "📉"
            print(f"  Engagement:          {trend_icon} {report['engagement_trend']} (avg {report['avg_engagement_rate']}%)")

    print(f"\n{'='*60}\n")


def main():
    parser = argparse.ArgumentParser(
        description="Track X/Twitter account growth over time",
        formatter_class=argparse.RawDescriptionHelpFormatter)

    parser.add_argument("--record", action="store_true", help="Record a new snapshot")
    parser.add_argument("--report", action="store_true", help="Generate growth report")
    parser.add_argument("--milestone", action="store_true", help="Project when target will be reached")

    parser.add_argument("--handle", required=True, help="X handle")
    parser.add_argument("--followers", type=int, default=0, help="Current follower count")
    parser.add_argument("--following", type=int, default=0, help="Current following count")
    parser.add_argument("--eng-rate", type=float, default=0, help="Current engagement rate (pct)")
    parser.add_argument("--posts-week", type=float, default=0, help="Posts per week")
    parser.add_argument("--notes", default="", help="Notes for this snapshot")
    parser.add_argument("--period", default="all", help="Report period: 7d, 30d, 90d, all")
    parser.add_argument("--target", type=int, default=0, help="Follower milestone target")
    parser.add_argument("--json", action="store_true", help="Output JSON")

    args = parser.parse_args()

    if not args.handle.startswith("@"):
        args.handle = f"@{args.handle}"

    if args.record:
        if args.followers <= 0:
            print("Error: --followers required for recording", file=sys.stderr)
            sys.exit(1)
        entry = record_snapshot(args.handle, args.followers, args.following,
                                args.eng_rate, args.posts_week, args.notes)
        if args.json:
            print(json.dumps(entry, indent=2))
        else:
            print(f"  ✅ Recorded: {args.handle} — {args.followers:,} followers")
            print(f"     File: {get_data_file(args.handle)}")

    elif args.report:
        period_days = 0
        if args.period != "all":
            period_days = int(args.period.rstrip("d"))
        entries = load_snapshots(args.handle, period_days)
        report = generate_report(args.handle, entries)
        if args.json:
            print(json.dumps(report, indent=2))
        else:
            print_report(report)

    elif args.milestone:
        if args.target <= 0:
            print("Error: --target required for milestone projection", file=sys.stderr)
            sys.exit(1)
        entries = load_snapshots(args.handle)
        result = project_milestone(args.handle, entries, args.target)
        if args.json:
            print(json.dumps(result, indent=2))
        else:
            if "error" in result:
                print(f"  ⚠️  {result['error']}")
            elif "status" in result and "days_needed" not in result:
                print(f"  🎉 {result['status']}")
            else:
                print(f"\n  🎯 Milestone Projection: {result['handle']}")
                print(f"  Current:  {result['current']:,}")
                print(f"  Target:   {result['target']:,}")
                print(f"  Gap:      {result['remaining']:,}")
                print(f"  Growth:   {result['daily_growth']:+.1f}/day")
                print(f"  ETA:      {result['projected_date']} (~{result['days_needed']} days)")
                print()

    else:
        parser.print_help()


if __name__ == "__main__":
    main()
