import requests
import json
import os
import time
from dotenv import load_dotenv

load_dotenv()

def getAllPolyEvents():
    """Paginate through all open Polymarket events"""
    url = "https://gamma-api.polymarket.com/events"
    all_events = []
    
    params = {
        'order': 'id',
        'ascending': 'false',
        'closed': 'false',
        'limit': 100,
        'offset': 0
    }
    
    while True:
        response = requests.get(url, params=params, timeout=30)
        response.raise_for_status()
        events = response.json()
        
        if not events:
            break
        
        all_events.extend(events)
        params['offset'] += 100
    
    with open('poly_events.json', 'w') as f:
        json.dump(all_events, f, indent=2)
    
    return all_events

def getAllKalshiEvents():
    """Paginate through all Kalshi events using cursor"""
    url = "https://api.elections.kalshi.com/trade-api/v2/events"
    headers = {'Authorization': f'Bearer {os.getenv("KALSHI_API_KEY")}'}
    all_events = []
    
    params = {
        'limit': 200,
        'with_nested_markets': 'true',
        'status': 'open',
        'min_close_ts': int(time.time())
    }
    
    while True:
        response = requests.get(url, headers=headers, params=params, timeout=30)
        response.raise_for_status()
        data = response.json()
        
        events = data.get('events', [])
        if not events:
            break
        
        all_events.extend(events)
        
        cursor = data.get('cursor')
        if not cursor:
            break
        params['cursor'] = cursor
        time.sleep(0.5)
    
    with open('kalshi_events.json', 'w') as f:
        json.dump(all_events, f, indent=2)
    
    return all_events

def matchEvents():
    """Match Polymarket and Kalshi events/markets using keywords and close times"""
    from datetime import datetime, timedelta, timezone
    import re
    
    print("Loading events...")
    with open('poly_events.json', 'r') as f:
        poly = json.load(f)
    with open('kalshi_events.json', 'r') as f:
        kalshi = json.load(f)
    
    print(f"Loaded {len(poly)} Poly events, {len(kalshi)} Kalshi events")
    
    now = datetime.now(timezone.utc)
    two_days = now + timedelta(days=2)
    
    # Filter Poly events with markets closing within 2 days
    print("Filtering Poly events by close time...")
    filtered_poly = []
    for p in poly:
        has_near_close = False
        for m in p.get('markets', []):
            end_date_str = m.get('endDate')
            if end_date_str:
                try:
                    end_date = datetime.fromisoformat(end_date_str.replace('Z', '+00:00'))
                    if now <= end_date <= two_days:
                        has_near_close = True
                        break
                except:
                    pass
        if has_near_close:
            filtered_poly.append(p)
    
    print(f"Filtered to {len(filtered_poly)} Poly events closing within 2 days")
    
    # Filter Kalshi events with markets closing within 2 days
    print("Filtering Kalshi events by close time...")
    filtered_kalshi = []
    for k in kalshi:
        has_near_close = False
        for m in k.get('markets', []):
            close_time_str = m.get('close_time')
            if close_time_str:
                close_time = datetime.fromisoformat(close_time_str.replace('Z', '+00:00'))
                if now <= close_time <= two_days:
                    has_near_close = True
                    break
        if has_near_close:
            filtered_kalshi.append(k)
    
    print(f"Filtered to {len(filtered_kalshi)} Kalshi events closing within 2 days")
    
    def extract_keywords(text):
        """Extract meaningful keywords from text"""
        text = text.lower()
        # Remove common words and extract key terms
        stopwords = {'the', 'a', 'an', 'in', 'on', 'at', 'for', 'to', 'of', 'and', 'or', 'will', 'be', 'is', 'are', 'was', 'were', 'been', 'being', 'have', 'has', 'had', 'do', 'does', 'did', 'but', 'if', 'then', 'than', 'this', 'that', 'these', 'those', 'what', 'which', 'who', 'when', 'where', 'why', 'how'}
        words = re.findall(r'\b[a-z0-9]+\b', text)
        return set(w for w in words if w not in stopwords and len(w) > 2)
    
    def keyword_match_score(text1, text2):
        """Score based on keyword overlap"""
        kw1 = extract_keywords(text1)
        kw2 = extract_keywords(text2)
        if not kw1 or not kw2:
            return 0
        intersection = kw1 & kw2
        union = kw1 | kw2
        return len(intersection) / len(union) if union else 0
    
    def get_close_times(event):
        """Get all close times from event markets"""
        times = []
        for m in event.get('markets', []):
            time_str = m.get('close_time') or m.get('endDate')
            if time_str:
                try:
                    times.append(datetime.fromisoformat(time_str.replace('Z', '+00:00')))
                except:
                    pass
        return times
    
    matches = []
    print(f"\nMatching {len(filtered_kalshi)} Kalshi events against {len(filtered_poly)} Poly events...")
    
    # Debug: show first few Kalshi events
    if filtered_kalshi:
        print(f"\nSample Kalshi event: {filtered_kalshi[0].get('title', '')}")
    if filtered_poly:
        print(f"Sample Poly event: {filtered_poly[0].get('title', '')}\n")
    
    for i, k in enumerate(filtered_kalshi):
        if i % 10 == 0:
            print(f"  Processed {i}/{len(filtered_kalshi)} Kalshi events, found {len(matches)} matches")
        
        if not k.get('markets'):
            continue
            
        k_title = f"{k.get('title', '')} {k.get('sub_title', '')}".strip()
        k_times = get_close_times(k)
        
        best_p = None
        best_score = 0
        
        for p in filtered_poly:
            if not p.get('markets'):
                continue
            
            p_title = p.get('title', '')
            p_times = get_close_times(p)
            
            # Calculate keyword match score
            kw_score = keyword_match_score(p_title, k_title)
            
            # Bonus for close time proximity (within 6 hours)
            time_bonus = 0
            if p_times and k_times:
                min_diff = min(abs((pt - kt).total_seconds()) for pt in p_times for kt in k_times)
                if min_diff < 21600:  # 6 hours
                    time_bonus = 0.3 * (1 - min_diff / 21600)
            
            score = kw_score + time_bonus
            
            if score > best_score and score > 0.2:
                best_score = score
                best_p = p
        
        # Debug first event
        if i == 0:
            print(f"  Best match for '{k_title[:50]}...': score={best_score:.3f}, match={best_p.get('title', '')[:50] if best_p else 'None'}")
        
        if best_p:
            # Match markets within events
            market_matches = []
            used_kalshi = set()
            
            for pm in best_p.get('markets', []):
                p_question = pm.get('question', '')
                p_outcomes = pm.get('outcomes', '')
                
                best_match = None
                best_market_score = 0
                
                for km in k.get('markets', []):
                    if km.get('ticker') in used_kalshi:
                        continue
                    
                    k_subtitle = km.get('yes_sub_title', '') or km.get('no_sub_title', '')
                    k_question = f"{km.get('title', '')} {k_subtitle}".strip()
                    
                    # Match based on keywords and outcomes
                    m_score = keyword_match_score(p_question, k_question)
                    
                    # Bonus for matching outcome types
                    if 'yes' in p_outcomes.lower() and 'no' in p_outcomes.lower():
                        m_score += 0.1
                    
                    if m_score > best_market_score and m_score > 0.2:
                        best_market_score = m_score
                        best_match = km
                
                if best_match:
                    k_subtitle = best_match.get('yes_sub_title', '') or best_match.get('no_sub_title', '')
                    k_ticker = best_match.get('ticker')
                    used_kalshi.add(k_ticker)
                    
                    market_matches.append({
                        'score': round(best_market_score, 3),
                        'poly_market': {
                            'id': pm.get('id'),
                            'question': p_question,
                            'outcomes': pm.get('outcomes'),
                            'prices': pm.get('outcomePrices')
                        },
                        'kalshi_market': {
                            'ticker': k_ticker,
                            'title': f"{best_match.get('title', '')} - {k_subtitle}" if k_subtitle else best_match.get('title', ''),
                            'yes_bid': best_match.get('yes_bid'),
                            'yes_ask': best_match.get('yes_ask'),
                            'close_time': best_match.get('close_time')
                        }
                    })
            
            if market_matches:  # Only add if we found market matches
                matches.append({
                    'score': round(best_score, 3),
                    'poly_event': {'id': best_p['id'], 'title': best_p.get('title', ''), 'slug': best_p.get('slug')},
                    'kalshi_event': {'ticker': k.get('event_ticker'), 'title': k_title},
                    'market_matches': market_matches
                })
    
    print(f"\nFound {len(matches)} total event matches")
    print("Sorting by score...")
    matches.sort(key=lambda x: (x['score'], len(x['market_matches'])), reverse=True)
    
    print("Writing to matches.json...")
    with open('matches.json', 'w') as f:
        json.dump(matches, f, indent=2)
    
    print("Done!")
    return matches
