#!/usr/bin/env python3
"""
X/Twitter Profile Auditor — Audit any X profile for growth readiness.

Checks bio quality, pinned tweet, posting patterns, and provides
actionable recommendations. Works without API access by analyzing
profile data you provide or scraping public info via web search.

Usage:
    python3 profile_auditor.py --handle @username
    python3 profile_auditor.py --handle @username --json
    python3 profile_auditor.py --bio "current bio text" --followers 5000 --posts-per-week 10
"""

import argparse
import json
import re
import sys
from dataclasses import dataclass, field, asdict
from typing import Optional


@dataclass
class ProfileData:
    handle: str = ""
    bio: str = ""
    followers: int = 0
    following: int = 0
    posts_per_week: float = 0
    reply_ratio: float = 0  # % of posts that are replies
    thread_ratio: float = 0  # % of posts that are threads
    has_pinned: bool = False
    pinned_age_days: int = 0
    has_link: bool = False
    has_newsletter: bool = False
    avg_engagement_rate: float = 0  # likes+replies+rts / followers


@dataclass
class AuditFinding:
    area: str
    status: str  # GOOD, WARN, CRITICAL
    message: str
    fix: str = ""


@dataclass
class AuditReport:
    handle: str
    score: int = 0
    max_score: int = 100
    grade: str = ""
    findings: list = field(default_factory=list)
    recommendations: list = field(default_factory=list)


def audit_bio(profile: ProfileData) -> list:
    findings = []
    bio = profile.bio.strip()

    if not bio:
        findings.append(AuditFinding("Bio", "CRITICAL", "No bio provided for audit",
                                     "Provide bio text with --bio flag"))
        return findings

    # Length check
    if len(bio) < 30:
        findings.append(AuditFinding("Bio", "WARN", f"Bio too short ({len(bio)} chars)",
                                     "Aim for 100-160 characters with clear value prop"))
    elif len(bio) > 160:
        findings.append(AuditFinding("Bio", "WARN", f"Bio may be too long ({len(bio)} chars)",
                                     "Keep under 160 chars for readability"))
    else:
        findings.append(AuditFinding("Bio", "GOOD", f"Bio length OK ({len(bio)} chars)"))

    # Hashtag check
    hashtags = re.findall(r'#\w+', bio)
    if hashtags:
        findings.append(AuditFinding("Bio", "WARN", f"Hashtags in bio ({', '.join(hashtags)})",
                                     "Remove hashtags — signals amateur. Use plain text."))
    else:
        findings.append(AuditFinding("Bio", "GOOD", "No hashtags in bio"))

    # Buzzword check
    buzzwords = ['entrepreneur', 'guru', 'ninja', 'rockstar', 'visionary', 'hustler',
                 'thought leader', 'serial entrepreneur', 'dreamer', 'doer']
    found = [bw for bw in buzzwords if bw.lower() in bio.lower()]
    if found:
        findings.append(AuditFinding("Bio", "WARN", f"Buzzwords detected: {', '.join(found)}",
                                     "Replace with specific, concrete descriptions of what you do"))

    # Specificity check — pipes and slashes often signal unfocused bios
    if bio.count('|') >= 3 or bio.count('/') >= 3:
        findings.append(AuditFinding("Bio", "WARN", "Bio may lack focus (too many roles/identities)",
                                     "Lead with ONE clear identity. What's the #1 thing you want to be known for?"))

    # Social proof check
    proof_patterns = [r'\d+[kKmM]?\+?\s*(followers|subscribers|readers|users|customers)',
                      r'(founder|ceo|cto|vp|head|director|lead)\s+(of|at|@)',
                      r'(author|writer)\s+of', r'featured\s+in', r'ex-\w+']
    has_proof = any(re.search(p, bio, re.IGNORECASE) for p in proof_patterns)
    if has_proof:
        findings.append(AuditFinding("Bio", "GOOD", "Social proof detected"))
    else:
        findings.append(AuditFinding("Bio", "WARN", "No obvious social proof in bio",
                                     "Add a credential: title, metric, brand association, or achievement"))

    # CTA/Link check
    if profile.has_link:
        findings.append(AuditFinding("Bio", "GOOD", "Profile has a link"))
    else:
        findings.append(AuditFinding("Bio", "WARN", "No link in profile",
                                     "Add a link to newsletter, product, or portfolio"))

    return findings


def audit_activity(profile: ProfileData) -> list:
    findings = []

    # Posting frequency
    if profile.posts_per_week <= 0:
        findings.append(AuditFinding("Activity", "CRITICAL", "No posting data provided",
                                     "Provide --posts-per-week estimate"))
    elif profile.posts_per_week < 3:
        findings.append(AuditFinding("Activity", "CRITICAL",
                                     f"Very low posting ({profile.posts_per_week:.0f}/week)",
                                     "Minimum 7 posts/week (1/day). Aim for 14-21."))
    elif profile.posts_per_week < 7:
        findings.append(AuditFinding("Activity", "WARN",
                                     f"Low posting ({profile.posts_per_week:.0f}/week)",
                                     "Aim for 2-3 posts per day for consistent growth"))
    elif profile.posts_per_week < 21:
        findings.append(AuditFinding("Activity", "GOOD",
                                     f"Good posting cadence ({profile.posts_per_week:.0f}/week)"))
    else:
        findings.append(AuditFinding("Activity", "GOOD",
                                     f"High posting cadence ({profile.posts_per_week:.0f}/week)"))

    # Reply ratio
    if profile.reply_ratio > 0:
        if profile.reply_ratio < 0.2:
            findings.append(AuditFinding("Activity", "WARN",
                                         f"Low reply ratio ({profile.reply_ratio:.0%})",
                                         "Aim for 30%+ replies. Engage with others, don't just broadcast."))
        elif profile.reply_ratio >= 0.3:
            findings.append(AuditFinding("Activity", "GOOD",
                                         f"Healthy reply ratio ({profile.reply_ratio:.0%})"))

    # Follower/following ratio
    if profile.followers > 0 and profile.following > 0:
        ratio = profile.followers / profile.following
        if ratio < 0.5:
            findings.append(AuditFinding("Profile", "WARN",
                                         f"Low follower/following ratio ({ratio:.1f}x)",
                                         "Unfollow inactive accounts. Ratio should trend toward 2:1+"))
        elif ratio >= 2:
            findings.append(AuditFinding("Profile", "GOOD",
                                         f"Healthy follower/following ratio ({ratio:.1f}x)"))

    # Pinned tweet
    if profile.has_pinned:
        if profile.pinned_age_days > 30:
            findings.append(AuditFinding("Profile", "WARN",
                                         f"Pinned tweet is {profile.pinned_age_days} days old",
                                         "Update pinned tweet monthly with your latest best content"))
        else:
            findings.append(AuditFinding("Profile", "GOOD", "Pinned tweet is recent"))
    else:
        findings.append(AuditFinding("Profile", "WARN", "No pinned tweet",
                                     "Pin your best-performing tweet or thread. It's your landing page."))

    return findings


def calculate_score(findings: list) -> tuple:
    total = len(findings)
    if total == 0:
        return 0, "F"

    good = sum(1 for f in findings if f.status == "GOOD")
    score = int((good / total) * 100)

    if score >= 90:
        grade = "A"
    elif score >= 75:
        grade = "B"
    elif score >= 60:
        grade = "C"
    elif score >= 40:
        grade = "D"
    else:
        grade = "F"

    return score, grade


def generate_recommendations(findings: list, profile: ProfileData) -> list:
    recs = []
    criticals = [f for f in findings if f.status == "CRITICAL"]
    warns = [f for f in findings if f.status == "WARN"]

    for f in criticals:
        if f.fix:
            recs.append(f"🔴 {f.fix}")

    for f in warns[:3]:  # Top 3 warnings
        if f.fix:
            recs.append(f"🟡 {f.fix}")

    # Stage-specific advice
    if profile.followers < 1000:
        recs.append("📈 Growth phase: Focus 70% on replies to larger accounts, 30% on your own posts")
    elif profile.followers < 10000:
        recs.append("📈 Momentum phase: 2-3 threads/week + daily engagement. Start a recurring series.")
    else:
        recs.append("📈 Scale phase: Leverage audience with cross-platform repurposing + newsletter growth")

    return recs


def main():
    parser = argparse.ArgumentParser(
        description="Audit an X/Twitter profile for growth readiness",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  %(prog)s --handle @rezarezvani --bio "CTO building AI products" --followers 5000
  %(prog)s --bio "Entrepreneur | Dreamer | Hustle" --followers 200 --posts-per-week 3
  %(prog)s --handle @example --followers 50000 --posts-per-week 21 --reply-ratio 0.4 --json
        """)

    parser.add_argument("--handle", default="@unknown", help="X handle")
    parser.add_argument("--bio", default="", help="Current bio text")
    parser.add_argument("--followers", type=int, default=0, help="Follower count")
    parser.add_argument("--following", type=int, default=0, help="Following count")
    parser.add_argument("--posts-per-week", type=float, default=0, help="Average posts per week")
    parser.add_argument("--reply-ratio", type=float, default=0, help="Fraction of posts that are replies (0-1)")
    parser.add_argument("--has-pinned", action="store_true", help="Has a pinned tweet")
    parser.add_argument("--pinned-age-days", type=int, default=0, help="Age of pinned tweet in days")
    parser.add_argument("--has-link", action="store_true", help="Has link in profile")
    parser.add_argument("--json", action="store_true", help="Output JSON")

    args = parser.parse_args()

    profile = ProfileData(
        handle=args.handle,
        bio=args.bio,
        followers=args.followers,
        following=args.following,
        posts_per_week=args.posts_per_week,
        reply_ratio=args.reply_ratio,
        has_pinned=args.has_pinned,
        pinned_age_days=args.pinned_age_days,
        has_link=args.has_link,
    )

    findings = audit_bio(profile) + audit_activity(profile)
    score, grade = calculate_score(findings)
    recs = generate_recommendations(findings, profile)

    report = AuditReport(
        handle=profile.handle,
        score=score,
        grade=grade,
        findings=[asdict(f) for f in findings],
        recommendations=recs,
    )

    if args.json:
        print(json.dumps(asdict(report), indent=2))
    else:
        print(f"\n{'='*60}")
        print(f"  X PROFILE AUDIT — {report.handle}")
        print(f"{'='*60}")
        print(f"\n  Score: {report.score}/100 (Grade: {report.grade})\n")

        for f in findings:
            icon = {"GOOD": "✅", "WARN": "⚠️", "CRITICAL": "🔴"}.get(f.status, "❓")
            print(f"  {icon} [{f.area}] {f.message}")
            if f.fix and f.status != "GOOD":
                print(f"     → {f.fix}")

        if recs:
            print(f"\n  {'─'*56}")
            print(f"  TOP RECOMMENDATIONS\n")
            for i, r in enumerate(recs, 1):
                print(f"  {i}. {r}")

        print(f"\n{'='*60}\n")


if __name__ == "__main__":
    main()
