#!/usr/bin/env python3
"""Banger-X Search Executor v4 - Execute 18 queries via GetXAPI and build report. Uses requests + cursor pagination."""

import json, os, sys, re, time
import requests
from datetime import datetime, timezone

# Get API key
env_path = os.path.expanduser("~/.hermes/.env")
api_key = None
for line in open(env_path):
    if line.startswith("GETXAPI_KEY="):
        api_key = line.strip().split("=", 1)[1]
        break

if not api_key:
    print("ERROR: No API key found")
    sys.exit(1)

headers = {"Authorization": f"Bearer {api_key}"}

# All 13 queries - clean strings
queries = [
    {
        "id": 1,
        "name": "AI film platform mentions",
        "query": '"kling" OR "seedance" OR "runway" min_faves:50 min_retweets:5 min_replies:3',
        "keywords": ["kling", "seedance", "runway"]
    },
    {
        "id": 2,
        "name": "AI creative workflows",
        "query": '"ai creative" OR "creative ai" min_faves:100 min_retweets:10 min_replies:5',
        "keywords": ["ai creative", "creative ai"]
    },
    {
        "id": 3,
        "name": "High-engagement AI video discussion",
        "query": '"ai video" min_faves:200 min_retweets:15 min_replies:5',
        "keywords": ["ai video"]
    },
    {
        "id": 4,
        "name": "Brand storytelling",
        "query": '"brand storytelling" min_faves:100 min_retweets:10 min_replies:5',
        "keywords": ["brand storytelling"]
    },
    {
        "id": 5,
        "name": "AI in marketing",
        "query": '"ai marketing" OR "ai advertising" min_faves:100 min_retweets:10',
        "keywords": ["ai marketing", "ai advertising"]
    },
    {
        "id": 6,
        "name": "AI agent ecosystem",
        "query": '"ai agent" OR "ai agents" min_faves:100 min_retweets:10 min_replies:5',
        "keywords": ["ai agent", "ai agents"]
    },
    {
        "id": 7,
        "name": "AI coding tools and workflows",
        "query": '"ai coding" OR "ai programming" min_faves:100 min_retweets:10 min_replies:5',
        "keywords": ["ai coding", "ai programming"]
    },
    {
        "id": 8,
        "name": "Sleep optimization",
        "query": '"sleep" OR "sleep hack" min_faves:100 min_retweets:5',
        "keywords": ["sleep", "sleep hack"]
    },
    {
        "id": 9,
        "name": "Fitness trending",
        "query": '"fitness" OR "workout" min_faves:100 min_retweets:5',
        "keywords": ["fitness", "workout"]
    },
    {
        "id": 10,
        "name": "Posture and ergonomic discussions",
        "query": '"posture" OR "ergonomic" OR "back pain" OR "neck pain" min_faves:50',
        "keywords": ["posture", "ergonomic", "back pain", "neck pain"]
    },
    {
        "id": 11,
        "name": "Ecommerce and DTC founder discussions",
        "query": '"ecommerce" OR "dtc" OR "direct to consumer" OR "dropshipping" min_faves:50 min_replies:3',
        "keywords": ["ecommerce", "dtc", "dropshipping"]
    },
    {
        "id": 12,
        "name": "Shopify and checkout optimization",
        "query": '"shopify" OR "woocommerce" OR "checkout" OR "conversion rate" min_faves:50 min_replies:3',
        "keywords": ["shopify", "woocommerce", "checkout", "conversion rate"]
    },
    {
        "id": 14,
        "name": "Travel and eSIM roaming",
        "query": '"travel" OR "vacation" OR "holiday" OR "trip" OR "flight" OR "hotel" min_faves:50 min_retweets:5 min_replies:3',
        "keywords": ["travel", "vacation", "holiday", "trip", "flight"]
    },
    {
        "id": 15,
        "name": "Digital nomad and international data",
        "query": '"digital nomad" OR "remote work" OR "international data" OR "sim card" OR "roaming" OR "data plan" min_faves:30 min_retweets:3',
        "keywords": ["digital nomad", "remote work", "sim card", "roaming", "data plan"]
    },
    {
        "id": 16,
        "name": "Solo travel and backpacking",
        "query": '"solo travel" OR "backpacking" OR "hostel" OR "travel tips" OR "budget travel" OR "travel hack" min_faves:30 min_retweets:3',
        "keywords": ["solo travel", "backpacking", "hostel", "travel tips", "budget travel"]
    },
    {
        "id": 17,
        "name": "Airports and connectivity while abroad",
        "query": '"airport" OR "layover" OR "connecting flight" OR "wifi abroad" OR "offline maps" OR "packing" min_faves:30 min_retweets:3',
        "keywords": ["airport", "layover", "wifi abroad", "offline maps", "packing"]
    },
    {
        "id": 18,
        "name": "Travel destinations and itineraries",
        "query": '"destination" OR "itinerary" OR "travel destination" OR "where to visit" OR "best time to visit" min_faves:30 min_retweets:3',
        "keywords": ["destination", "itinerary", "where to visit"]
    },
]

def execute_query(q_obj, max_pages=2):
    """Execute query with cursor-pagination to overcome GetXAPI truncation."""
    query_text = q_obj["query"]
    all_tweets = []
    cursor = None
    
    for page in range(max_pages):
        params = {"q": query_text, "product": "Top"}
        if cursor:
            params["cursor"] = cursor
        url = "https://api.getxapi.com/twitter/tweet/advanced_search"
        
        try:
            r = requests.get(url, params=params, headers=headers, timeout=30)
            r.raise_for_status()
            data = r.json()
        except requests.exceptions.RequestException as e:
            return {"error": f"Page {page+1}: {str(e)[:200]}", "tweets": all_tweets}
        except Exception as e:
            return {"error": f"Page {page+1} parse: {str(e)[:200]}", "tweets": all_tweets}
        
        tweets = data.get("tweets", [])
        all_tweets.extend(tweets)
        
        has_more = data.get("has_more", False)
        cursor = data.get("next_cursor", "")
        
        if not has_more or not cursor:
            break
        
        time.sleep(0.2)
    
    result = {"tweets": all_tweets, "tweet_count": len(all_tweets)}
    if cursor:
        result["has_more"] = True
        result["next_cursor"] = cursor
    return result

def is_off_topic(text, keywords, topic):
    """Filter off-topic tweets based on context."""
    text_lower = text.lower()
    
    # Off-topic patterns for "runway" - fashion not AI
    if "runway" in [k.lower() for k in keywords]:
        fashion_words = ["fashion", "model", "dress", "beauty", "makeup", "couture", "style", "fabric", "wear"]
        ai_words = ["ai", "artificial", "video", "film", "kling", "gen", "generation", "diffusion", "model"]
        # Check if it's fashion context vs AI context
        fashion_count = sum(1 for w in fashion_words if w in text_lower)
        ai_count = sum(1 for w in ai_words if w in text_lower)
        if fashion_count > ai_count and ai_count == 0:
            return True
    
    # Off-topic patterns for "sleep" - memes, not health
    if "sleep" in [k.lower() for k in keywords]:
        # Check if it's actually about sleep health
        health_words = ["health", "pillow", "mattress", "sleep", "bed", "rest", "insomnia", "tired", "energy"]
        has_health = any(w in text_lower for w in health_words)
        # But if it's just "sleep on" (slang for ignore) - that's off topic
        if "sleep on" in text_lower and "sleep" in keywords:
            if "hack" not in text_lower and "health" not in text_lower:
                # Could still be about ignoring something valuable, which IS on-topic
                pass
    
    return False

def filter_false_positives(tweets, keywords, topic_name):
    """Filter out false positive tweets."""
    filtered = []
    for t in tweets:
        text = t.get("full_text", "")
        author = t.get("author", "")
        text_lower = text.lower()
        author_lower = author.lower()
        
        # Check if any keyword appears in the tweet text
        text_matches = any(kw.lower() in text_lower for kw in keywords)
        
        # Check if keywords ONLY appear in the author handle
        handle_only = False
        if not text_matches:
            handle_matches = any(kw.lower() in author_lower for kw in keywords)
            if handle_matches:
                handle_only = True
        
        if handle_only:
            continue  # False positive - keyword only in handle
        
        # Check for off-topic content
        if is_off_topic(text, keywords, topic_name):
            continue
        
        filtered.append(t)
    
    return filtered

# Execute all queries
all_results = {}
errors = []
results_dir = "/home/kiro/trend-engine/trends/x/banger-x-results"
os.makedirs(results_dir, exist_ok=True)
date_str = datetime.now(timezone.utc).strftime("%Y-%m-%d")

# Load partial results if exists (resume support)
partial_path = f"{results_dir}/{date_str}_banger-x-partial.json"
if os.path.exists(partial_path):
    try:
        with open(partial_path) as f:
            all_results = json.load(f)
        print(f"[RESUME] Loaded {len(all_results)} already-executed queries from partial save")
        done_queries = set(all_results.keys())
    except:
        done_queries = set()
else:
    done_queries = set()

for q in queries:
    qid = str(q["id"])
    qname = q["name"]
    
    if qid in done_queries:
        print(f"\n=== Query {qid}: {qname} [SKIP - already done] ===")
        continue
    
    print(f"\n=== Query {qid}: {qname} ===")
    print(f"Query: {q['query'][:60]}...")
    
    result = execute_query(q)
    
    if "error" in result and not result.get("tweets"):
        print(f"  ERROR: {result['error'][:150]}")
        errors.append(f"Q{qid}: {result['error'][:100]}")
        all_results[qid] = {"tweets": [], "name": qname, "error": result["error"]}
        # Save partial
        with open(partial_path, "w") as f:
            json.dump(all_results, f, indent=2, default=str)
        time.sleep(1)
        continue
    
    # Parse tweets
    raw_tweets = []
    for t in result.get("tweets", []):
        if isinstance(t, str):
            continue
        author_data = t.get("author", {})
        if isinstance(author_data, dict):
            handle = author_data.get("userName", "unknown")
        else:
            handle = str(author_data)
        
        tweet_text = t.get("text", "")
        tweet_id = t.get("id", "")
        
        tweet_obj = {
            "author": handle,
            "text": tweet_text[:250],
            "full_text": tweet_text,
            "likes": t.get("likeCount", 0),
            "retweets": t.get("retweetCount", 0),
            "replies": t.get("replyCount", 0),
            "views": t.get("viewCount", 0),
            "id": tweet_id
        }
        raw_tweets.append(tweet_obj)
    
    # Apply false positive filter
    filtered = filter_false_positives(raw_tweets, q["keywords"], qname)
    # Also filter off-topic tweets
    off_topic = [t for t in filtered if not is_off_topic(t.get("text", ""), q["keywords"], qname)]
    
    all_results[qid] = {"tweets": off_topic, "name": qname}
    print(f"  Raw: {len(raw_tweets)}, After filter: {len(off_topic)}")
    
    # Print top tweets
    sorted_tweets = sorted(off_topic, key=lambda x: x["views"], reverse=True)[:5]
    for i, t in enumerate(sorted_tweets):
        preview = t["text"][:80].replace('\n', ' ')
        print(f"  {i+1}. @{t['author']}: {preview}... | ❤️{t['likes']} 🔄{t['retweets']} 💬{t['replies']} 👁️{t['views']}")
    
    # Incremental save
    with open(partial_path, "w") as f:
        json.dump(all_results, f, indent=2, default=str)
    
    # Rate limit delay
    time.sleep(1)

# Save raw data files
with open(f"{results_dir}/{date_str}_banger-x-raw.json", "w") as f:
    json.dump(all_results, f, indent=2, default=str)

# Print final summary
print(f"\n\n=== EXECUTION SUMMARY ===")
total_tweets = sum(len(v["tweets"]) for v in all_results.values())
print(f"Total queries executed: {len(all_results)}")
print(f"Total tweets after filtering: {total_tweets}")
print(f"Errors: {len(errors)}")
for e in errors:
    print(f"  - {e}")

# Write out a compact JSON for the report builder
report_data = {
    "date": date_str,
    "queries": {},
    "errors": errors
}

for qid, data in all_results.items():
    report_data["queries"][str(qid)] = {
        "name": data.get("name", str(qid)),
        "count": len(data["tweets"]),
        "tweets": data["tweets"]
    }

with open(f"{results_dir}/{date_str}_banger-x-parsed.json", "w") as f:
    json.dump(report_data, f, indent=2, default=str)

print("Raw data saved.")
