#!/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 sys
sys.path.insert(0, '/Eden/CORE')
from github_rate_limiter import can_post, record_post
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"
        
        # RATE LIMIT CHECK
        allowed, reason = can_post("fibonacci_followup")
        if not allowed:
            print(f"🚫 {reason}")
            return False
        record_post("fibonacci_followup", api_url)
        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()
