#!/usr/bin/env python3
"""
EDEN FIBONACCI FOLLOW-UP SYSTEM
Based on industry best practices:
- 80% of sales require 5+ follow-ups
- Fibonacci timing (1, 2, 3, 5, 8 days)
- CCQ method (Compliment, Commonality, Question)
- Value-first messaging
- Actually SENDS, not just logs
"""
import sqlite3
import json
import requests
import time
import subprocess
from datetime import datetime, timedelta
from pathlib import Path
from typing import Optional, List, Dict

# Fibonacci sequence for follow-up timing (in days)
FIBONACCI_DAYS = [1, 2, 3, 5, 8, 13]
MAX_FOLLOWUPS = 5
DAILY_LIMIT = 2  # Max 2 per day to avoid shadowban

# Paths
DB_PATH = "/Eden/DATA/sales.db"
TOKEN_PATH = "/Eden/SECRETS/github_token_clean.txt"
LOG_PATH = "/Eden/LOGS/fibonacci_followup.log"
STATE_PATH = "/Eden/DATA/fibonacci_followup_state.json"

def log(msg: str):
    ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    line = f"[{ts}] {msg}"
    print(line)
    with open(LOG_PATH, 'a') as f:
        f.write(line + "\n")

def get_token() -> str:
    return Path(TOKEN_PATH).read_text().strip()

def get_db():
    conn = sqlite3.connect(DB_PATH)
    conn.row_factory = sqlite3.Row
    return conn

def ensure_tables():
    """Create follow-up tracking table if not exists"""
    conn = get_db()
    conn.execute("""
        CREATE TABLE IF NOT EXISTS followup_sequence (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            user TEXT,
            repo TEXT,
            issue_url TEXT,
            engagement_type TEXT,
            score REAL,
            followup_count INTEGER DEFAULT 0,
            last_followup_date TEXT,
            next_followup_date TEXT,
            status TEXT DEFAULT 'active',
            created_at TEXT,
            notes TEXT
        )
    """)
    conn.execute("""
        CREATE TABLE IF NOT EXISTS followup_log (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            sequence_id INTEGER,
            followup_number INTEGER,
            message TEXT,
            sent_at TEXT,
            response TEXT,
            FOREIGN KEY (sequence_id) REFERENCES followup_sequence(id)
        )
    """)
    conn.commit()
    conn.close()
    log("✅ Database tables ready")

def get_next_fibonacci_days(followup_count: int) -> int:
    """Get days until next follow-up based on Fibonacci"""
    if followup_count >= len(FIBONACCI_DAYS):
        return FIBONACCI_DAYS[-1]
    return FIBONACCI_DAYS[followup_count]

def import_hot_leads():
    """Import existing hot leads from followups table"""
    conn = get_db()
    
    # Get existing hot leads
    existing = conn.execute("""
        SELECT user, repo, engagement_type, score, sent_at 
        FROM followups 
        WHERE score >= 0.8 AND converted = 0
    """).fetchall()
    
    imported = 0
    for lead in existing:
        # Check if already in sequence
        exists = conn.execute("""
            SELECT id FROM followup_sequence WHERE user = ? AND repo = ?
        """, (lead['user'], lead['repo'])).fetchone()
        
        if not exists:
            # Calculate issue URL from repo
            issue_url = f"https://github.com/{lead['repo']}/issues"
            
            conn.execute("""
                INSERT INTO followup_sequence 
                (user, repo, issue_url, engagement_type, score, followup_count, 
                 last_followup_date, next_followup_date, status, created_at)
                VALUES (?, ?, ?, ?, ?, 0, ?, ?, 'active', ?)
            """, (
                lead['user'], lead['repo'], issue_url, lead['engagement_type'],
                lead['score'], lead['sent_at'], 
                (datetime.now() + timedelta(days=1)).isoformat(),
                datetime.now().isoformat()
            ))
            imported += 1
    
    conn.commit()
    conn.close()
    log(f"📥 Imported {imported} hot leads into follow-up sequence")
    return imported

def generate_ccq_opener(user: str, repo: str, followup_num: int) -> str:
    """Generate CCQ-style opener (Compliment, Commonality, Question)"""
    
    if followup_num == 1:
        # First follow-up - Compliment
        return f"@{user}, I've been looking at {repo} more closely - really solid architecture."
    elif followup_num == 2:
        # Second follow-up - Commonality  
        return f"@{user}, as someone who also cares about code quality, I wanted to follow up."
    elif followup_num == 3:
        # Third follow-up - Question
        return f"@{user}, quick question - is security auditing something on your roadmap for {repo.split('/')[-1]}?"
    elif followup_num == 4:
        # Fourth follow-up - Value add
        return f"@{user}, I ran an extended scan on {repo.split('/')[-1]} - found a few things worth sharing."
    else:
        # Fifth follow-up - Final
        return f"@{user}, last note on this - happy to help whenever timing works better."
    
def generate_followup_message(user: str, repo: str, engagement_type: str, 
                               followup_num: int, score: float) -> str:
    """Generate contextual follow-up based on engagement and sequence number"""
    
    opener = generate_ccq_opener(user, repo, followup_num)
    repo_name = repo.split('/')[-1]
    
    if followup_num == 1:
        if engagement_type == 'HOT_LEAD':
            return f"""{opener}

Ready whenever you are:
1. $149 at https://paypal.me/jamlen
2. Reply with your email
3. Full audit delivered within 24h

— Eden 💚"""
        elif engagement_type in ['PR_MERGED', 'ISSUE_FIXED']:
            return f"""{opener}

Since you're actively improving the codebase, a full security sweep might save you some headaches down the road.

$149 covers: vulnerabilities, dependencies, secrets, configs, plus 30-day rescan.

Worth considering?

— Eden"""
        else:
            return f"""{opener}

I have some additional findings from scanning `{repo_name}` that might be useful.

Want me to share them?

— Eden"""
    
    elif followup_num == 2:
        return f"""{opener}

Just floating this back up - the security scan offer still stands.

Quick overview:
- Full vulnerability analysis
- Dependency risk mapping  
- Prioritized fixes

$149, 24h turnaround. Let me know.

— Eden"""
    
    elif followup_num == 3:
        return f"""{opener}

If audits aren't a priority right now, no worries.

But if you ever need a quick security check before a release or client demo, I'm here.

— Eden"""
    
    elif followup_num == 4:
        return f"""{opener}

No pressure at all - just wanted you to know I found:
- A few dependency updates worth reviewing
- Some config patterns that could be tightened

Happy to share details if useful, or leave it here.

— Eden"""
    
    else:  # followup_num >= 5
        return f"""{opener}

This is my last follow-up. If security auditing isn't a fit right now, totally understand.

Feel free to reach out anytime if that changes. Good luck with {repo_name}!

— Eden 💚"""

def post_github_comment(issue_url: str, message: str) -> bool:
    """Post a comment to GitHub issue"""
    token = get_token()
    
    try:
        # Parse URL to get API endpoint
        # Format: https://github.com/owner/repo/issues/123
        parts = issue_url.replace("https://github.com/", "").split("/")
        if len(parts) < 4:
            # Try to find an open issue
            owner, repo = parts[0], parts[1]
            api_url = f"https://api.github.com/repos/{owner}/{repo}/issues"
            resp = requests.get(api_url, 
                headers={"Authorization": f"token {token}"},
                params={"state": "open", "per_page": 1})
            if resp.ok and resp.json():
                issue_num = resp.json()[0]['number']
            else:
                log(f"❌ No open issues found for {owner}/{repo}")
                return False
        else:
            owner, repo, _, issue_num = parts[0], parts[1], parts[2], parts[3]
        
        api_url = f"https://api.github.com/repos/{owner}/{repo}/issues/{issue_num}/comments"
        
        resp = requests.post(api_url,
            headers={
                "Authorization": f"token {token}",
                "Accept": "application/vnd.github.v3+json"
            },
            json={"body": message}
        )
        
        if resp.status_code == 201:
            log(f"✅ Posted follow-up to {owner}/{repo}#{issue_num}")
            return True
        else:
            log(f"❌ GitHub API error: {resp.status_code} - {resp.text[:100]}")
            return False
            
    except Exception as e:
        log(f"❌ Error posting comment: {e}")
        return False

def get_leads_due_for_followup() -> List[Dict]:
    """Get leads that are due for follow-up today"""
    conn = get_db()
    today = datetime.now().isoformat()
    
    leads = conn.execute("""
        SELECT * FROM followup_sequence
        WHERE status = 'active'
        AND followup_count < ?
        AND (next_followup_date IS NULL OR next_followup_date <= ?)
        ORDER BY score DESC, followup_count ASC
    """, (MAX_FOLLOWUPS, today)).fetchall()
    
    conn.close()
    return [dict(l) for l in leads]

def record_followup(sequence_id: int, followup_num: int, message: str):
    """Record that we sent a follow-up"""
    conn = get_db()
    now = datetime.now()
    next_days = get_next_fibonacci_days(followup_num)
    next_date = (now + timedelta(days=next_days)).isoformat()
    
    # Update sequence
    conn.execute("""
        UPDATE followup_sequence 
        SET followup_count = ?, last_followup_date = ?, next_followup_date = ?
        WHERE id = ?
    """, (followup_num, now.isoformat(), next_date, sequence_id))
    
    # Log the followup
    conn.execute("""
        INSERT INTO followup_log (sequence_id, followup_number, message, sent_at)
        VALUES (?, ?, ?, ?)
    """, (sequence_id, followup_num, message, now.isoformat()))
    
    conn.commit()
    conn.close()

def mark_converted(sequence_id: int):
    """Mark a lead as converted"""
    conn = get_db()
    conn.execute("""
        UPDATE followup_sequence SET status = 'converted' WHERE id = ?
    """, (sequence_id,))
    conn.commit()
    conn.close()

def mark_closed(sequence_id: int, reason: str = "max_followups"):
    """Mark a lead as closed (no more follow-ups)"""
    conn = get_db()
    conn.execute("""
        UPDATE followup_sequence SET status = ?, notes = ? WHERE id = ?
    """, ('closed', reason, sequence_id))
    conn.commit()
    conn.close()

def run_followup_cycle():
    """Run one follow-up cycle - respects daily limits"""
    log("🔄 Starting Fibonacci follow-up cycle...")
    
    leads = get_leads_due_for_followup()
    log(f"📋 Found {len(leads)} leads due for follow-up")
    
    sent_today = 0
    
    for lead in leads:
        if sent_today >= DAILY_LIMIT:
            log(f"⏸️ Daily limit ({DAILY_LIMIT}) reached. Remaining leads queued for tomorrow.")
            break
        
        user = lead['user']
        repo = lead['repo']
        issue_url = lead['issue_url']
        engagement_type = lead['engagement_type']
        score = lead['score']
        current_count = lead['followup_count']
        next_num = current_count + 1
        
        log(f"📧 Processing: {user}/{repo} (score: {score}, follow-up #{next_num})")
        
        # Generate message
        message = generate_followup_message(user, repo, engagement_type, next_num, score)
        
        # Try to send
        success = post_github_comment(issue_url, message)
        
        if success:
            record_followup(lead['id'], next_num, message)
            sent_today += 1
            log(f"✅ Sent follow-up #{next_num} to {user}")
            
            # Check if this was the last follow-up
            if next_num >= MAX_FOLLOWUPS:
                mark_closed(lead['id'], "max_followups_reached")
                log(f"📪 Sequence complete for {user}/{repo}")
        else:
            log(f"⚠️ Failed to send to {user}/{repo}")
        
        # Rate limiting
        time.sleep(30)  # Wait 30 seconds between posts
    
    log(f"✅ Cycle complete. Sent {sent_today} follow-ups.")
    return sent_today

def get_stats():
    """Get follow-up statistics"""
    conn = get_db()
    
    stats = {
        'active_sequences': conn.execute("SELECT COUNT(*) FROM followup_sequence WHERE status='active'").fetchone()[0],
        'total_followups_sent': conn.execute("SELECT COUNT(*) FROM followup_log").fetchone()[0],
        'converted': conn.execute("SELECT COUNT(*) FROM followup_sequence WHERE status='converted'").fetchone()[0],
        'closed': conn.execute("SELECT COUNT(*) FROM followup_sequence WHERE status='closed'").fetchone()[0],
        'hot_leads': conn.execute("SELECT COUNT(*) FROM followup_sequence WHERE score >= 0.9 AND status='active'").fetchone()[0],
    }
    
    # Get leads by followup count
    for i in range(MAX_FOLLOWUPS + 1):
        stats[f'at_followup_{i}'] = conn.execute(
            "SELECT COUNT(*) FROM followup_sequence WHERE followup_count = ? AND status='active'",
            (i,)).fetchone()[0]
    
    conn.close()
    return stats

def display_status():
    """Display current follow-up status"""
    stats = get_stats()
    
    print()
    print("╔" + "═"*60 + "╗")
    print("║" + "  EDEN FIBONACCI FOLLOW-UP STATUS  ".center(60) + "║")
    print("╠" + "═"*60 + "╣")
    print(f"║  Active sequences: {stats['active_sequences']}".ljust(61) + "║")
    print(f"║  Total follow-ups sent: {stats['total_followups_sent']}".ljust(61) + "║")
    print(f"║  Converted: {stats['converted']}".ljust(61) + "║")
    print(f"║  Closed (max reached): {stats['closed']}".ljust(61) + "║")
    print(f"║  Hot leads (score ≥0.9): {stats['hot_leads']}".ljust(61) + "║")
    print("╠" + "═"*60 + "╣")
    print("║  Sequence Distribution:".ljust(61) + "║")
    for i in range(MAX_FOLLOWUPS + 1):
        count = stats.get(f'at_followup_{i}', 0)
        bar = "█" * min(count, 20)
        print(f"║    Follow-up #{i}: {count} {bar}".ljust(61) + "║")
    print("╠" + "═"*60 + "╣")
    print("║  Timing: Fibonacci (1, 2, 3, 5, 8 days)".ljust(61) + "║")
    print("║  Daily limit: 2 (anti-shadowban)".ljust(61) + "║")
    print("╚" + "═"*60 + "╝")
    print()

def main():
    """Main service loop"""
    log("🌀 Eden Fibonacci Follow-Up System starting...")
    
    ensure_tables()
    import_hot_leads()
    display_status()
    
    while True:
        try:
            # Run follow-up cycle
            sent = run_followup_cycle()
            
            # Display updated status
            display_status()
            
        except Exception as e:
            log(f"❌ Error in cycle: {e}")
        
        # Run every 6 hours
        log("😴 Sleeping 6 hours until next cycle...")
        time.sleep(6 * 60 * 60)

if __name__ == "__main__":
    import sys
    
    if len(sys.argv) > 1:
        if sys.argv[1] == "status":
            ensure_tables()
            display_status()
        elif sys.argv[1] == "import":
            ensure_tables()
            import_hot_leads()
        elif sys.argv[1] == "run":
            ensure_tables()
            import_hot_leads()
            run_followup_cycle()
            display_status()
        elif sys.argv[1] == "test":
            ensure_tables()
            import_hot_leads()
            display_status()
    else:
        main()
