#!/usr/bin/env python3
"""
BetPredictAI - Real-Time Match Result Verifier

Verifica i risultati delle partite in tempo reale:
1. Controlla le partite che dovrebbero essere finite (kickoff + 105 min)
2. Se non c'è risultato, aspetta per supplementari/rigori (+45 min extra)
3. Aggiorna automaticamente le verifiche con i risultati reali

API: football-data.org (free per top 5 leagues)
Uso: python3 realtime_verifier.py [--force]
"""

import os
import sys
import json
import requests
from datetime import datetime, timedelta
import time
import logging

# Setup logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s [%(levelname)s] %(message)s',
    handlers=[
        logging.FileHandler('/var/www/html/bet.cuttalo.com/logs/realtime_verifier.log'),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DATA_DIR = os.path.join(BASE_DIR, '..', 'data')
LOGS_DIR = os.path.join(BASE_DIR, '..', 'logs')

# Ensure directories exist
os.makedirs(DATA_DIR, exist_ok=True)
os.makedirs(LOGS_DIR, exist_ok=True)

# Load API key from .env
API_KEY = os.environ.get('FOOTBALL_DATA_API_KEY', '')
if not API_KEY:
    env_path = os.path.join(BASE_DIR, '..', '.env')
    if os.path.exists(env_path):
        with open(env_path) as f:
            for line in f:
                if line.startswith('FOOTBALL_DATA_API_KEY='):
                    API_KEY = line.strip().split('=', 1)[1]
                    break

# Football-data.org competition codes
COMPETITIONS = {
    'E0': 'PL',    # Premier League
    'D1': 'BL1',   # Bundesliga
    'I1': 'SA',    # Serie A
    'SP1': 'PD',   # La Liga (Primera Division)
    'F1': 'FL1',   # Ligue 1
}

COMPETITION_NAMES = {
    'PL': 'Premier League',
    'BL1': 'Bundesliga',
    'SA': 'Serie A',
    'PD': 'La Liga',
    'FL1': 'Ligue 1'
}

# Match status codes from API
MATCH_STATUS = {
    'SCHEDULED': 'scheduled',
    'TIMED': 'scheduled',
    'LIVE': 'live',
    'IN_PLAY': 'live',
    'PAUSED': 'halftime',
    'FINISHED': 'finished',
    'POSTPONED': 'postponed',
    'SUSPENDED': 'suspended',
    'CANCELLED': 'cancelled',
    'AWARDED': 'finished',
    'EXTRA_TIME': 'extra_time',
    'PENALTY_SHOOTOUT': 'penalties'
}

# Timing constants (in minutes)
REGULAR_TIME = 90
HALFTIME_BUFFER = 15
STOPPAGE_TIME_BUFFER = 10
EXTRA_TIME = 30
PENALTY_BUFFER = 20
TOTAL_BUFFER_REGULAR = REGULAR_TIME + HALFTIME_BUFFER + STOPPAGE_TIME_BUFFER  # 115 min
TOTAL_BUFFER_EXTRA = TOTAL_BUFFER_REGULAR + EXTRA_TIME + PENALTY_BUFFER  # 165 min


def get_api_headers():
    """Get headers for football-data.org API"""
    return {
        'X-Auth-Token': API_KEY
    } if API_KEY else {}


def fetch_live_matches(days_back=3):
    """Fetch matches from football-data.org for the last N days"""
    logger.info(f"Fetching matches from football-data.org (last {days_back} days)...")

    if not API_KEY:
        logger.warning("No API key configured! Set FOOTBALL_DATA_API_KEY in .env")
        return []

    all_matches = []
    today = datetime.now()
    date_from = (today - timedelta(days=days_back)).strftime('%Y-%m-%d')
    date_to = today.strftime('%Y-%m-%d')

    logger.info(f"  Date range: {date_from} to {date_to}")

    for our_code, api_code in COMPETITIONS.items():
        url = f"https://api.football-data.org/v4/competitions/{api_code}/matches"
        params = {
            'dateFrom': date_from,
            'dateTo': date_to
        }

        try:
            response = requests.get(url, headers=get_api_headers(), params=params, timeout=10)

            if response.status_code == 200:
                data = response.json()
                matches = data.get('matches', [])

                for match in matches:
                    match['our_league_code'] = our_code

                all_matches.extend(matches)
                logger.info(f"  {COMPETITION_NAMES.get(api_code, api_code)}: {len(matches)} matches")

            elif response.status_code == 429:
                logger.warning(f"  Rate limited for {api_code}, waiting...")
                time.sleep(60)
            else:
                logger.error(f"  Error fetching {api_code}: {response.status_code}")

            time.sleep(1)  # Rate limiting

        except Exception as e:
            logger.error(f"  Failed to fetch {api_code}: {e}")

    return all_matches


def fetch_match_result(match_id):
    """Fetch specific match result"""
    if not API_KEY:
        return None

    url = f"https://api.football-data.org/v4/matches/{match_id}"

    try:
        response = requests.get(url, headers=get_api_headers(), timeout=10)
        if response.status_code == 200:
            return response.json()
    except Exception as e:
        logger.error(f"Failed to fetch match {match_id}: {e}")

    return None


def should_check_result(kickoff_time_str, current_time=None):
    """
    Determine if we should check for match result based on kickoff time.

    Returns: (should_check, is_extra_time_window)
    """
    if current_time is None:
        current_time = datetime.now()

    try:
        # Parse kickoff time (ISO format from API)
        kickoff = datetime.fromisoformat(kickoff_time_str.replace('Z', '+00:00'))
        kickoff = kickoff.replace(tzinfo=None)  # Remove timezone for comparison

        elapsed_minutes = (current_time - kickoff).total_seconds() / 60

        # Match should be finished after regular time + buffer
        if elapsed_minutes >= TOTAL_BUFFER_REGULAR:
            is_extra_time_window = elapsed_minutes < TOTAL_BUFFER_EXTRA
            return True, is_extra_time_window

        return False, False

    except Exception as e:
        logger.error(f"Error parsing kickoff time {kickoff_time_str}: {e}")
        return False, False


def get_match_result_outcome(score):
    """Determine match outcome from score"""
    if not score:
        return None

    home = score.get('fullTime', {}).get('home')
    away = score.get('fullTime', {}).get('away')

    if home is None or away is None:
        return None

    if home > away:
        return 'HOME'
    elif away > home:
        return 'AWAY'
    else:
        return 'DRAW'


def load_pending_predictions():
    """Load predictions that need result verification"""
    predictions_path = os.path.join(DATA_DIR, 'predictions_upcoming.json')

    if not os.path.exists(predictions_path):
        logger.info("No predictions file found")
        return []

    try:
        with open(predictions_path) as f:
            predictions = json.load(f)
        return predictions
    except Exception as e:
        logger.error(f"Error loading predictions: {e}")
        return []


def load_verification_results():
    """Load current verification results"""
    verification_path = os.path.join(DATA_DIR, 'verification_results.json')

    if os.path.exists(verification_path):
        with open(verification_path) as f:
            return json.load(f)

    return {
        'generated_at': datetime.now().isoformat(),
        'model_version': 'V4-Advanced',
        'summary': {'total': 0, 'correct': 0, 'accuracy': 0},
        'by_confidence': {},
        'by_league': {},
        'results': [],
        'top_verified': []
    }


def save_verification_results(data):
    """Save verification results"""
    data['generated_at'] = datetime.now().isoformat()

    # Recalculate summary
    results = data.get('results', [])
    total = len(results)
    correct = sum(1 for r in results if r.get('correct', False))

    data['summary'] = {
        'total': total,
        'correct': correct,
        'accuracy': round(100 * correct / total, 1) if total > 0 else 0
    }

    # Recalculate by confidence
    by_confidence = {}
    for threshold in [40, 45, 50, 55, 60, 65, 70]:
        high_conf = [r for r in results if r.get('confidence', 0) >= threshold]
        if high_conf:
            high_conf_correct = sum(1 for r in high_conf if r.get('correct', False))
            by_confidence[threshold] = {
                'total': len(high_conf),
                'correct': high_conf_correct,
                'accuracy': round(100 * high_conf_correct / len(high_conf), 1)
            }
    data['by_confidence'] = by_confidence

    # Recalculate by league
    leagues = set(r.get('league') for r in results if r.get('league'))
    by_league = {}
    for league in leagues:
        league_results = [r for r in results if r.get('league') == league]
        if league_results:
            league_correct = sum(1 for r in league_results if r.get('correct', False))
            by_league[league] = {
                'name': league_results[0].get('league_name', league),
                'total': len(league_results),
                'correct': league_correct,
                'accuracy': round(100 * league_correct / len(league_results), 1)
            }
    data['by_league'] = by_league

    # Update top verified
    data['top_verified'] = sorted(
        [r for r in results if r.get('correct', False)],
        key=lambda x: x.get('confidence', 0),
        reverse=True
    )[:20]

    # Save
    output_path = os.path.join(DATA_DIR, 'verification_results.json')
    with open(output_path, 'w') as f:
        json.dump(data, f, indent=2)

    logger.info(f"Saved verification: {correct}/{total} correct ({data['summary']['accuracy']}%)")


def create_match_tracking_file():
    """Create/update match tracking file for pending verifications"""
    tracking_path = os.path.join(DATA_DIR, 'match_tracking.json')

    if os.path.exists(tracking_path):
        with open(tracking_path) as f:
            tracking = json.load(f)
    else:
        tracking = {
            'last_updated': datetime.now().isoformat(),
            'pending_matches': [],
            'checked_matches': []
        }

    return tracking


def save_match_tracking(tracking):
    """Save match tracking data"""
    tracking['last_updated'] = datetime.now().isoformat()
    tracking_path = os.path.join(DATA_DIR, 'match_tracking.json')
    with open(tracking_path, 'w') as f:
        json.dump(tracking, f, indent=2)


def verify_matches_realtime(live_matches=None):
    """Main function to verify matches in real-time"""
    logger.info("=" * 60)
    logger.info("Real-Time Match Verification Started")
    logger.info(f"Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    logger.info("=" * 60)

    if not API_KEY:
        logger.error("FOOTBALL_DATA_API_KEY not set! Please add it to .env")
        logger.info("Get your free key at: https://www.football-data.org/client/register")
        return

    # Use provided matches or fetch new ones
    if live_matches is None:
        live_matches = fetch_live_matches(days_back=3)
    logger.info(f"Total matches found: {len(live_matches)}")

    # Load verification results
    verification = load_verification_results()
    existing_ids = set()
    for r in verification.get('results', []):
        match_key = f"{r.get('date')}_{r.get('home_team')}_{r.get('away_team')}"
        existing_ids.add(match_key)

    # Load match tracking
    tracking = create_match_tracking_file()

    # Process each match
    verified_count = 0
    pending_count = 0

    for match in live_matches:
        match_id = match.get('id')
        status = match.get('status', 'SCHEDULED')
        kickoff = match.get('utcDate', '')

        home_team = match.get('homeTeam', {}).get('shortName', match.get('homeTeam', {}).get('name', 'Unknown'))
        away_team = match.get('awayTeam', {}).get('shortName', match.get('awayTeam', {}).get('name', 'Unknown'))

        match_date = kickoff[:10] if kickoff else datetime.now().strftime('%Y-%m-%d')
        match_key = f"{match_date}_{home_team}_{away_team}"

        # Skip if already verified
        if match_key in existing_ids:
            continue

        our_status = MATCH_STATUS.get(status, 'unknown')

        logger.info(f"\nMatch: {home_team} vs {away_team}")
        logger.info(f"  Status: {status} ({our_status})")
        logger.info(f"  Kickoff: {kickoff}")

        # Check if match is finished
        if our_status == 'finished':
            score = match.get('score', {})
            home_goals = score.get('fullTime', {}).get('home', 0)
            away_goals = score.get('fullTime', {}).get('away', 0)

            outcome = get_match_result_outcome(score)

            if outcome:
                logger.info(f"  Result: {home_goals}-{away_goals} ({outcome})")

                # Add to verification (we need to match with our prediction)
                # For now, just log it - we'll integrate with predictions later
                verified_count += 1

                # Create verification entry
                new_result = {
                    'match_id': match_id,
                    'league': match.get('our_league_code', ''),
                    'league_name': COMPETITION_NAMES.get(match.get('competition', {}).get('code', ''), ''),
                    'date': match_date,
                    'time': kickoff[11:16] if len(kickoff) > 16 else '15:00',
                    'home_team': home_team,
                    'away_team': away_team,
                    'home_goals': home_goals,
                    'away_goals': away_goals,
                    'actual': outcome,
                    'actual_code': 2 if outcome == 'HOME' else (1 if outcome == 'DRAW' else 0),
                    'verified_at': datetime.now().isoformat(),
                    'match_status': status
                }

                # Add to tracking for later matching with predictions
                tracking.setdefault('verified_today', []).append(new_result)

        elif our_status in ['live', 'halftime', 'extra_time', 'penalties']:
            # Match is still in progress
            should_check, is_extra = should_check_result(kickoff)

            if should_check and our_status in ['extra_time', 'penalties']:
                logger.info(f"  Match in {our_status}, waiting for final result...")
            else:
                logger.info(f"  Match in progress, will check later...")

            pending_count += 1

        elif our_status == 'scheduled':
            # Match hasn't started yet
            should_check, _ = should_check_result(kickoff)

            if should_check:
                # Match should have finished but API says scheduled - might be delayed
                logger.warning(f"  Match should have finished but status is {status}")
                pending_count += 1

    # Save tracking
    save_match_tracking(tracking)

    logger.info("\n" + "=" * 60)
    logger.info(f"Verification Complete")
    logger.info(f"  Verified: {verified_count}")
    logger.info(f"  Pending: {pending_count}")
    logger.info("=" * 60)


def integrate_with_predictions():
    """
    Match verified results with our predictions and update verification file.
    Run this after verify_matches_realtime() to update accuracy stats.
    """
    logger.info("\nIntegrating results with predictions...")

    tracking_path = os.path.join(DATA_DIR, 'match_tracking.json')
    if not os.path.exists(tracking_path):
        logger.info("No tracking data to integrate")
        return

    with open(tracking_path) as f:
        tracking = json.load(f)

    verified_today = tracking.get('verified_today', [])
    if not verified_today:
        logger.info("No new verified matches to integrate")
        return

    # Load predictions
    predictions_path = os.path.join(DATA_DIR, 'predictions_upcoming.json')
    predictions = []
    if os.path.exists(predictions_path):
        with open(predictions_path) as f:
            predictions = json.load(f)

    # Load verification
    verification = load_verification_results()

    # Match verified results with predictions
    integrated_count = 0

    for verified in verified_today:
        home = verified['home_team']
        away = verified['away_team']
        date = verified['date']

        # Find matching prediction
        for pred in predictions:
            pred_home = pred.get('home_team', '')
            pred_away = pred.get('away_team', '')
            pred_date = pred.get('date', '')

            # Fuzzy match (team names might differ slightly)
            if (date == pred_date and
                (home.lower() in pred_home.lower() or pred_home.lower() in home.lower()) and
                (away.lower() in pred_away.lower() or pred_away.lower() in away.lower())):

                # Found match!
                predicted = pred.get('prediction', '')
                predicted_code = 2 if predicted == 'HOME' else (1 if predicted == 'DRAW' else 0)

                result_entry = {
                    'league': verified['league'],
                    'league_name': verified['league_name'],
                    'date': date,
                    'time': verified.get('time', pred.get('time', '15:00')),
                    'home_team': home,
                    'away_team': away,
                    'home_goals': verified['home_goals'],
                    'away_goals': verified['away_goals'],
                    'actual': verified['actual'],
                    'actual_code': verified['actual_code'],
                    'predicted': predicted,
                    'predicted_code': predicted_code,
                    'confidence': pred.get('confidence', 50),
                    'home_prob': pred.get('home_prob', 33),
                    'draw_prob': pred.get('draw_prob', 33),
                    'away_prob': pred.get('away_prob', 33),
                    'correct': verified['actual_code'] == predicted_code,
                    'verified_at': verified.get('verified_at', datetime.now().isoformat())
                }

                verification['results'].append(result_entry)
                integrated_count += 1

                logger.info(f"  Integrated: {home} vs {away} - {'CORRECT' if result_entry['correct'] else 'WRONG'}")
                break

    if integrated_count > 0:
        # Sort by date descending
        verification['results'] = sorted(
            verification['results'],
            key=lambda x: x.get('date', ''),
            reverse=True
        )

        # Save updated verification
        save_verification_results(verification)

        # Clear integrated matches from tracking
        tracking['verified_today'] = []
        save_match_tracking(tracking)

    logger.info(f"Integrated {integrated_count} new results")


def cleanup_past_predictions():
    """
    Remove finished matches from predictions_upcoming.json
    Keep only future matches and today's matches that haven't started
    """
    logger.info("\nCleaning up past predictions...")

    predictions_path = os.path.join(DATA_DIR, 'predictions_upcoming.json')
    if not os.path.exists(predictions_path):
        logger.info("No predictions file found")
        return

    with open(predictions_path) as f:
        predictions = json.load(f)

    original_count = len(predictions)
    now = datetime.now()
    today = now.strftime('%Y-%m-%d')
    current_time = now.strftime('%H:%M')

    # Keep only:
    # - Future dates
    # - Today's matches that haven't started yet (with 2h buffer for delays)
    cleaned = []
    removed = []

    for p in predictions:
        match_date = p.get('date', '')
        match_time = p.get('time', '15:00')

        if match_date > today:
            # Future match - keep
            cleaned.append(p)
        elif match_date == today:
            # Today's match - check if it started
            try:
                match_dt = datetime.strptime(f"{match_date} {match_time}", "%Y-%m-%d %H:%M")
                # Keep if match hasn't finished yet (kickoff + 2h)
                match_end = match_dt + timedelta(hours=2)
                if now < match_end:
                    cleaned.append(p)
                else:
                    removed.append(p)
            except:
                cleaned.append(p)  # Keep if can't parse
        else:
            # Past date - remove
            removed.append(p)

    # Save cleaned predictions
    if len(cleaned) != original_count:
        with open(predictions_path, 'w') as f:
            json.dump(cleaned, f, indent=2, ensure_ascii=False)

        logger.info(f"  Removed {len(removed)} past matches")
        logger.info(f"  Kept {len(cleaned)} upcoming matches")

        # Log removed matches
        for r in removed[:5]:
            logger.info(f"    Removed: {r['date']} {r['time']} - {r['home_team']} vs {r['away_team']}")
        if len(removed) > 5:
            logger.info(f"    ... and {len(removed) - 5} more")
    else:
        logger.info("  No past matches to remove")


def update_predictions_with_results(live_matches):
    """
    Update predictions_upcoming.json with real results from API
    """
    logger.info("\nUpdating predictions with real results...")

    predictions_path = os.path.join(DATA_DIR, 'predictions_upcoming.json')
    if not os.path.exists(predictions_path):
        return

    with open(predictions_path) as f:
        predictions = json.load(f)

    updated_count = 0

    # Create lookup from live matches
    for match in live_matches:
        if match.get('status') != 'FINISHED':
            continue

        home_team = match.get('homeTeam', {}).get('shortName', match.get('homeTeam', {}).get('name', ''))
        away_team = match.get('awayTeam', {}).get('shortName', match.get('awayTeam', {}).get('name', ''))
        kickoff = match.get('utcDate', '')
        match_date = kickoff[:10] if kickoff else ''

        score = match.get('score', {})
        home_goals = score.get('fullTime', {}).get('home')
        away_goals = score.get('fullTime', {}).get('away')

        if home_goals is None or away_goals is None:
            continue

        # Find matching prediction
        for pred in predictions:
            pred_home = pred.get('home_team', '').lower()
            pred_away = pred.get('away_team', '').lower()
            pred_date = pred.get('date', '')

            # Fuzzy match
            if (pred_date == match_date and
                (home_team.lower() in pred_home or pred_home in home_team.lower()) and
                (away_team.lower() in pred_away or pred_away in away_team.lower())):

                # Update with result
                pred['status'] = 'FINISHED'
                pred['home_goals'] = home_goals
                pred['away_goals'] = away_goals
                pred['actual_result'] = 'HOME' if home_goals > away_goals else ('AWAY' if away_goals > home_goals else 'DRAW')
                pred['is_correct'] = pred['actual_result'] == pred.get('prediction', '')
                pred['verified_at'] = datetime.now().isoformat()

                updated_count += 1
                logger.info(f"  Updated: {pred['home_team']} {home_goals}-{away_goals} {pred['away_team']} "
                           f"({'✓' if pred['is_correct'] else '✗'} pred: {pred.get('prediction', '')})")
                break

    if updated_count > 0:
        with open(predictions_path, 'w') as f:
            json.dump(predictions, f, indent=2, ensure_ascii=False)
        logger.info(f"  Updated {updated_count} predictions with results")
    else:
        logger.info("  No predictions updated")


def main():
    """Main entry point"""
    force = '--force' in sys.argv

    if force:
        logger.info("Force mode: checking all matches")

    # Step 1: Fetch matches from API (last 3 days)
    live_matches = fetch_live_matches(days_back=3)

    # Step 2: Update predictions with real results
    update_predictions_with_results(live_matches)

    # Step 3: Verify matches and integrate with predictions
    verify_matches_realtime(live_matches)
    integrate_with_predictions()

    # Step 4: Cleanup past predictions
    cleanup_past_predictions()


if __name__ == '__main__':
    main()
