#!/usr/bin/env python3
"""
Ghost Agency Upwork Sniper - Multi-source Edition
Usa fonti alternative visto che Upwork ha cambiato l'RSS.
Fonti: HackerNews "Who is hiring", RemoteOK, WeWorkRemotely, RSSHub.
"""
import os
import re
import json
import feedparser
import requests
from pathlib import Path

TELEGRAM_TOKEN = os.getenv("TELEGRAM_TOKEN", "8816727123:AAFvd_1oh1ZAQq69kz1mvD1QCWbZyMkaRKw")
CHAT_ID = os.getenv("CHAT_ID", "1640434336")
OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY", "")
STATE_FILE = Path("/home/ubuntu/GhostAgency/upwork_state.json")
DRAFTS_DIR = Path("/home/ubuntu/GhostAgency/drafts")

DRAFTS_DIR.mkdir(exist_ok=True)

# Fonti RSS alternative per job Python/webdev
RSS_SOURCES = [
    # Reddit Freelance & ForHire (Clienti diretti, basta un DM su Reddit)
    "https://www.reddit.com/r/forhire/search.rss?q=%5BHiring%5D+AND+(React+OR+Next.js+OR+Web+OR+Python)&restrict_sr=on&sort=new&t=week",
    "https://www.reddit.com/r/freelance_forhire/search.rss?q=%5BHiring%5D&restrict_sr=on&sort=new&t=week",
    "https://www.reddit.com/r/Jobbit/search.rss?q=%5BHiring%5D&restrict_sr=on&sort=new&t=week"
]

KEYWORDS_MUST = ["python", "django", "fastapi", "flask", "react", "nextjs", "next.js", "typescript", "javascript", "node", "api", "scraping", "selenium", "playwright", "beautifulsoup", "pandas", "data", "backend", "fullstack", "freelance"]
KEYWORDS_SKIP = ["senior", "lead", "architect", "manager", "director", "cto", "vp", "principal", "staff", "5+ years", "7+ years", "10+ years"]

HEADERS = {
    "User-Agent": "Mozilla/5.0 (GhostAgency Sniper/2.0; +https://svoraj.me)"
}

def send_telegram(text):
    url = f"https://api.telegram.org/bot{TELEGRAM_TOKEN}/sendMessage"
    try:
        requests.post(url, json={"chat_id": CHAT_ID, "text": text, "parse_mode": "Markdown"}, timeout=10)
    except Exception as e:
        print(f"[!] Errore Telegram: {e}")

def ask_nemotron(job_description):
    nv_key = os.getenv("NVIDIA_API_KEY", "")
    if not nv_key:
        for env_path in ["/home/ubuntu/.hermes/.env", "/home/ubuntu/GhostAgency/.env"]:
            p = Path(env_path)
            if p.exists():
                for line in p.read_text().splitlines():
                    if "NVIDIA_API_KEY" in line and "=" in line:
                        parts = line.split("=", 1)
                        if len(parts) == 2:
                            nv_key = parts[1].strip().strip('"').strip("'")
                            break
            if nv_key:
                break

    if nv_key:
        headers = {
            "Authorization": f"Bearer {nv_key}",
            "Content-Type": "application/json"
        }
        payload = {
            "model": "meta/llama-3.2-11b-vision-instruct",
            "messages": [
                {
                    "role": "system",
                    "content": "Sei un programmatore freelance senior. Per questa richiesta di lavoro, genera: 1) Una brevissima proposta in inglese convincente (massimo 4 frasi) con cui candidarsi. 2) Lo script Python completo e pulito che risolve la richiesta del cliente."
                },
                {
                    "role": "user",
                    "content": job_description
                }
            ],
            "max_tokens": 1200
        }
        try:
            resp = requests.post("https://integrate.api.nvidia.com/v1/chat/completions", headers=headers, json=payload, timeout=25)
            if resp.status_code == 200:
                return resp.json()["choices"][0]["message"]["content"]
        except Exception as e:
            print(f"NVIDIA error: {e}")

    return "# Errore generazione codice"


def is_relevant_job(title, description):
    text = (title + " " + description).lower()
    # Deve contenere almeno una keyword MUST
    has_must = any(kw in text for kw in KEYWORDS_MUST)
    # Non deve contenere keyword SKIP
    has_skip = any(kw in text for kw in KEYWORDS_SKIP)
    return has_must and not has_skip

def clean_html(text):
    text = re.sub('<[^<]+>', '', text)
    return text[:2000]

def load_state():
    if STATE_FILE.exists():
        with open(STATE_FILE, "r") as f:
            return json.load(f)
    return []

def save_state(seen_jobs):
    # Keep last 200
    if len(seen_jobs) > 200:
        seen_jobs = seen_jobs[-200:]
    with open(STATE_FILE, "w") as f:
        json.dump(seen_jobs, f)

def sniper():
    seen_jobs = load_state()
    total_new = 0
    
    for feed_url in RSS_SOURCES:
        print(f"[*] Scansione {feed_url}...")
        try:
            feed = feedparser.parse(feed_url)
            
            for entry in feed.entries[:10]:  # Ultimi 10 per feed
                job_id = entry.get('id', entry.get('link', ''))
                
                if job_id in seen_jobs:
                    continue
                
                title = entry.get('title', '')
                link = entry.get('link', '')
                description = entry.get('description', entry.get('summary', ''))
                
                if not is_relevant_job(title, description):
                    continue
                
                print(f"[*] Trovato lavoro rilevante: {title}")
                
                clean_desc = clean_html(description)
                
                # Genera codice con Nemotron
                print("[*] Generazione codice via Nemotron...")
                generated_code = ask_nemotron(f"Titolo: {title}\nDescrizione: {clean_desc}")
                
                # Salva draft
                safe_id = re.sub(r'[^a-zA-Z0-9]', '_', job_id[-20:])
                file_path = DRAFTS_DIR / f"{safe_id}.py"
                with open(file_path, "w") as f:
                    f.write(generated_code)
                
                # Notifica Telegram
                msg = f"💸 *NUOVO LAVORO TROVATO*\n\n"
                msg += f"*{title}*\n\n"
                msg += f"Fonte: {feed_url}\n"
                msg += f"Ho già scritto la soluzione in Python usando Nemotron.\n"
                msg += f"File pronto: `{file_path}`\n\n"
                msg += f"Link: {link}"
                
                send_telegram(msg)
                seen_jobs.append(job_id)
                total_new += 1
                
        except Exception as e:
            print(f"[!] Errore feed {feed_url}: {e}")
    
    save_state(seen_jobs)
    print(f"[+] Fatto. {total_new} nuovi lavori trovati.")

if __name__ == "__main__":
    sniper()