"""
BET.CUTTALO.COM - API SERVER
Backend Flask per predizioni calcistiche con rete neurale
"""

from flask import Flask, jsonify, request
from flask_cors import CORS
import pandas as pd
import numpy as np
import torch
import torch.nn as nn
import joblib
import json
import os
import xgboost as xgb
from datetime import datetime, timedelta
import threading
import time
import hashlib
import secrets
from functools import wraps

app = Flask(__name__)
CORS(app, supports_credentials=True)

# ========== AUTH CONFIG ==========
JWT_SECRET = os.environ.get('JWT_SECRET', 'betpredictai_secret_key_2026')
JWT_EXPIRY_HOURS = 24 * 7  # 7 days

# Simple user storage (in production, use a database)
USERS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'users.json')

def load_users():
    if os.path.exists(USERS_FILE):
        with open(USERS_FILE) as f:
            return json.load(f)
    return {
        'admin': {
            'password_hash': hashlib.sha256('admin123'.encode()).hexdigest(),
            'role': 'admin',
            'created_at': datetime.now().isoformat()
        }
    }

def save_users(users):
    os.makedirs(os.path.dirname(USERS_FILE), exist_ok=True)
    with open(USERS_FILE, 'w') as f:
        json.dump(users, f, indent=2)

def hash_password(password):
    return hashlib.sha256(password.encode()).hexdigest()

def generate_token(username, role):
    import base64
    payload = {
        'username': username,
        'role': role,
        'exp': (datetime.now() + timedelta(hours=JWT_EXPIRY_HOURS)).isoformat()
    }
    token_data = json.dumps(payload).encode()
    signature = hashlib.sha256((json.dumps(payload) + JWT_SECRET).encode()).hexdigest()[:16]
    return base64.b64encode(token_data).decode() + '.' + signature

def verify_token(token):
    import base64
    try:
        parts = token.split('.')
        if len(parts) != 2:
            return None
        token_data = base64.b64decode(parts[0]).decode()
        payload = json.loads(token_data)

        # Verify signature
        expected_sig = hashlib.sha256((token_data + JWT_SECRET).encode()).hexdigest()[:16]
        if parts[1] != expected_sig:
            return None

        # Check expiry
        exp = datetime.fromisoformat(payload['exp'])
        if datetime.now() > exp:
            return None

        return payload
    except:
        return None

def auth_required(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        token = request.headers.get('Authorization', '').replace('Bearer ', '')
        if not token:
            token = request.cookies.get('auth_token', '')

        payload = verify_token(token)
        if not payload:
            return jsonify({'error': 'Unauthorized'}), 401

        request.user = payload
        return f(*args, **kwargs)
    return decorated

def admin_required(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        token = request.headers.get('Authorization', '').replace('Bearer ', '')
        if not token:
            token = request.cookies.get('auth_token', '')

        payload = verify_token(token)
        if not payload or payload.get('role') != 'admin':
            return jsonify({'error': 'Admin access required'}), 403

        request.user = payload
        return f(*args, **kwargs)
    return decorated

# Paths
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DATA_DIR = os.path.join(BASE_DIR, '..', 'data')
MODELS_DIR = os.path.join(BASE_DIR, '..', 'models')

# Model definitions
class BettingNetV2(nn.Module):
    def __init__(self, input_size):
        super().__init__()
        self.input_size = input_size
        self.net = nn.Sequential(
            nn.Linear(input_size, 256), nn.BatchNorm1d(256), nn.LeakyReLU(0.1), nn.Dropout(0.4),
            nn.Linear(256, 512), nn.BatchNorm1d(512), nn.LeakyReLU(0.1), nn.Dropout(0.4),
            nn.Linear(512, 256), nn.BatchNorm1d(256), nn.LeakyReLU(0.1), nn.Dropout(0.3),
            nn.Linear(256, 128), nn.BatchNorm1d(128), nn.LeakyReLU(0.1), nn.Dropout(0.2),
            nn.Linear(128, 64), nn.ReLU(), nn.Linear(64, 3)
        )
    def forward(self, x): return self.net(x)

class BettingNetV3(nn.Module):
    """Advanced model V3 with 51 features"""
    def __init__(self, input_size, hidden_sizes=[512, 256, 256, 128, 64], dropout=0.3):
        super().__init__()
        layers = []
        prev_size = input_size
        for i, hidden_size in enumerate(hidden_sizes):
            layers.append(nn.Linear(prev_size, hidden_size))
            layers.append(nn.BatchNorm1d(hidden_size))
            layers.append(nn.LeakyReLU(0.1))
            layers.append(nn.Dropout(dropout if i < len(hidden_sizes) - 1 else dropout * 0.5))
            prev_size = hidden_size
        self.feature_extractor = nn.Sequential(*layers)
        self.classifier = nn.Linear(prev_size, 3)

    def forward(self, x):
        features = self.feature_extractor(x)
        return self.classifier(features)

class AdvancedBettingNetV4(nn.Module):
    """V4 Advanced model with attention mechanism"""
    def __init__(self, input_size, hidden_sizes=[256, 256, 128, 64], dropout=0.3):
        super().__init__()
        self.attention = nn.Sequential(
            nn.Linear(input_size, input_size // 2),
            nn.ReLU(),
            nn.Linear(input_size // 2, input_size),
            nn.Sigmoid()
        )
        layers = []
        prev_size = input_size
        for i, hidden_size in enumerate(hidden_sizes):
            layers.append(nn.Linear(prev_size, hidden_size))
            layers.append(nn.BatchNorm1d(hidden_size))
            layers.append(nn.LeakyReLU(0.1))
            layers.append(nn.Dropout(dropout if i < len(hidden_sizes) - 1 else dropout * 0.5))
            prev_size = hidden_size
        self.feature_extractor = nn.Sequential(*layers)
        self.classifier = nn.Linear(prev_size, 3)

    def forward(self, x):
        attention_weights = self.attention(x)
        x = x * attention_weights
        features = self.feature_extractor(x)
        return self.classifier(features)

# Global models
model = None
scaler = None
meta = None
historical_df = None

# V4 Ensemble models
xgb_model_v4 = None
nn_model_v4 = None
scaler_v4 = None
meta_v4 = None
elo_ratings = None
model_version = 'v2'

LEAGUE_INFO = {
    'E0': {'name': 'Premier League', 'country': 'England', 'flag': '🏴󠁧󠁢󠁥󠁮󠁧󠁿', 'color': '#3D195B'},
    'D1': {'name': 'Bundesliga', 'country': 'Germany', 'flag': '🇩🇪', 'color': '#D20515'},
    'I1': {'name': 'Serie A', 'country': 'Italy', 'flag': '🇮🇹', 'color': '#024494'},
    'SP1': {'name': 'La Liga', 'country': 'Spain', 'flag': '🇪🇸', 'color': '#EE324E'},
    'F1': {'name': 'Ligue 1', 'country': 'France', 'flag': '🇫🇷', 'color': '#091C3E'},
}

RESULT_MAP = {0: 'AWAY', 1: 'DRAW', 2: 'HOME'}
RESULT_LABELS = {0: 'Away Win', 1: 'Draw', 2: 'Home Win'}


def load_model():
    """Load the trained model - tries V4 ensemble first, falls back to V3/V2"""
    global model, scaler, meta, historical_df, model_version
    global xgb_model_v4, nn_model_v4, scaler_v4, meta_v4, elo_ratings

    try:
        # Try V4 ensemble model first
        v4_meta_path = os.path.join(MODELS_DIR, 'model_v4_meta.json')
        v4_xgb_path = os.path.join(MODELS_DIR, 'xgb_model_v4.json')
        v4_nn_path = os.path.join(MODELS_DIR, 'nn_model_v4.pth')
        v4_scaler_path = os.path.join(MODELS_DIR, 'scaler_v4.npy')
        v4_elo_path = os.path.join(MODELS_DIR, 'elo_ratings.json')

        if all(os.path.exists(p) for p in [v4_meta_path, v4_xgb_path, v4_nn_path, v4_scaler_path, v4_elo_path]):
            print("Loading V4 Ensemble Model...")

            # Load V4 metadata
            with open(v4_meta_path) as f:
                meta_v4 = json.load(f)
            meta = meta_v4

            # Load XGBoost model
            xgb_model_v4 = xgb.XGBClassifier()
            xgb_model_v4.load_model(v4_xgb_path)
            print("  ✓ XGBoost loaded")

            # Load Neural Network
            input_size = len(meta_v4.get('feature_columns', []))
            nn_model_v4 = AdvancedBettingNetV4(input_size)
            nn_model_v4.load_state_dict(torch.load(v4_nn_path, map_location='cpu', weights_only=True))
            nn_model_v4.eval()
            print("  ✓ Neural Network loaded")

            # Load V4 scaler
            scaler_v4 = np.load(v4_scaler_path, allow_pickle=True).item()
            print("  ✓ Scaler loaded")

            # Load ELO ratings
            with open(v4_elo_path) as f:
                elo_ratings = json.load(f)
            print(f"  ✓ ELO ratings loaded ({len(elo_ratings)} teams)")

            model_version = 'v4'
            print(f"✅ Model V4 Ensemble loaded successfully!")

        else:
            # Fallback to older models
            v3_path = os.path.join(MODELS_DIR, 'betting_model_v3.pth')
            v3_meta_path = os.path.join(MODELS_DIR, 'betting_model_v3_meta.json')

            if os.path.exists(v3_path) and os.path.exists(v3_meta_path):
                with open(v3_meta_path) as f:
                    meta = json.load(f)
                input_size = len(meta.get('feature_columns', []))
                model = BettingNetV3(input_size)
                model.load_state_dict(torch.load(v3_path, map_location='cpu', weights_only=True))
                model.eval()
                model_version = 'v3'
                print(f"Model V3 loaded")
            else:
                checkpoint = torch.load(os.path.join(MODELS_DIR, 'betting_model_v2.pth'), map_location='cpu', weights_only=False)
                model = BettingNetV2(checkpoint['input_size'])
                model.load_state_dict(checkpoint['model_state_dict'])
                model.eval()
                scaler = joblib.load(os.path.join(MODELS_DIR, 'betting_model_v2_scaler.pkl'))
                with open(os.path.join(MODELS_DIR, 'betting_model_v2_meta.json')) as f:
                    meta = json.load(f)
                model_version = 'v2'
                print(f"Model V2 loaded")

        # Load historical data
        historical_path = os.path.join(DATA_DIR, 'historical_matches.csv')
        if os.path.exists(historical_path):
            historical_df = pd.read_csv(historical_path)
            historical_df['Date'] = pd.to_datetime(historical_df['Date'], errors='coerce')
            historical_df = historical_df.sort_values('Date').reset_index(drop=True)

        print(f"Model version: {model_version}")
        return True
    except Exception as e:
        print(f"Error loading model: {e}")
        import traceback
        traceback.print_exc()
        return False


def calc_team_stats(matches_df, team, is_home=None, n=5):
    """Calculate team statistics"""
    if is_home is True:
        team_matches = matches_df[matches_df['home_team'] == team]
    elif is_home is False:
        team_matches = matches_df[matches_df['away_team'] == team]
    else:
        team_matches = matches_df[(matches_df['home_team'] == team) | (matches_df['away_team'] == team)]

    if len(team_matches) < 1:
        return {'ppg': 1.0, 'gpg': 1.0, 'gapg': 1.0, 'win_rate': 0.33}

    recent = team_matches.tail(n)
    pts, gf, ga, wins = 0, 0, 0, 0

    for _, m in recent.iterrows():
        if m['home_team'] == team:
            gf += m['home_goals']; ga += m['away_goals']
            if m['result'] == 2: pts += 3; wins += 1
            elif m['result'] == 1: pts += 1
        else:
            gf += m['away_goals']; ga += m['home_goals']
            if m['result'] == 0: pts += 3; wins += 1
            elif m['result'] == 1: pts += 1

    n_m = len(recent)
    return {'ppg': pts/n_m, 'gpg': gf/n_m, 'gapg': ga/n_m, 'win_rate': wins/n_m}


def calc_h2h(matches_df, home, away, n=5):
    """Calculate head-to-head statistics"""
    h2h = matches_df[
        ((matches_df['home_team'] == home) & (matches_df['away_team'] == away)) |
        ((matches_df['home_team'] == away) & (matches_df['away_team'] == home))
    ].tail(n)

    if len(h2h) < 1:
        return {'home_h2h': 0.5, 'avg_goals': 2.5}

    home_wins, total_goals = 0, 0
    for _, m in h2h.iterrows():
        total_goals += m['home_goals'] + m['away_goals']
        if m['home_team'] == home and m['result'] == 2: home_wins += 1
        elif m['away_team'] == home and m['result'] == 0: home_wins += 1

    return {'home_h2h': home_wins/len(h2h), 'avg_goals': total_goals/len(h2h)}


def predict_match(home_team, away_team, league_code):
    """Make prediction for a single match using V4 ensemble or fallback"""

    # Calculate basic form stats (used for both V4 and fallback)
    home_form = {'ppg': 1.5, 'gpg': 1.3, 'gapg': 1.2, 'win_rate': 0.45}
    away_form = {'ppg': 1.4, 'gpg': 1.2, 'gapg': 1.3, 'win_rate': 0.40}

    if historical_df is not None and len(historical_df) > 0:
        league_df = historical_df[historical_df['league_code'] == league_code]
        if len(league_df) > 0:
            home_form = calc_team_stats(league_df, home_team, n=5)
            away_form = calc_team_stats(league_df, away_team, n=5)

    # Use V4 Ensemble if available
    if model_version == 'v4' and xgb_model_v4 is not None and nn_model_v4 is not None:
        return predict_match_v4(home_team, away_team, league_code, home_form, away_form)

    # Fallback to V2/V3
    if model is None:
        return None

    league_df = historical_df[historical_df['league_code'] == league_code] if historical_df is not None else pd.DataFrame()
    season = league_df['season'].iloc[-1] if len(league_df) > 0 else '2024/2025'
    season_df = league_df[league_df['season'] == season] if len(league_df) > 0 else pd.DataFrame()

    home_home = calc_team_stats(league_df, home_team, is_home=True, n=5) if len(league_df) > 0 else home_form
    away_away = calc_team_stats(league_df, away_team, is_home=False, n=5) if len(league_df) > 0 else away_form
    home_season = calc_team_stats(season_df, home_team, n=20) if len(season_df) > 0 else home_form
    away_season = calc_team_stats(season_df, away_team, n=20) if len(season_df) > 0 else away_form
    h2h = calc_h2h(league_df, home_team, away_team) if len(league_df) > 0 else {'home_h2h': 0.5, 'avg_goals': 2.5}

    impl_home, impl_draw, impl_away = 0.45, 0.27, 0.28

    features = np.array([[
        home_form['ppg'], home_form['gpg'], home_form['gapg'], home_form['win_rate'],
        away_form['ppg'], away_form['gpg'], away_form['gapg'], away_form['win_rate'],
        home_home['ppg'], home_home['gpg'], away_away['ppg'], away_away['gpg'],
        home_season['ppg'], away_season['ppg'],
        h2h['home_h2h'], h2h['avg_goals'],
        impl_home, impl_draw, impl_away,
        home_form['ppg'] - away_form['ppg'],
        home_form['gpg'] - away_form['gpg'],
        away_form['gapg'] - home_form['gapg']
    ]])

    features = scaler.transform(features)

    with torch.no_grad():
        logits = model(torch.FloatTensor(features))
        probs = torch.softmax(logits, dim=1).numpy()[0]

    pred = int(np.argmax(probs))

    return {
        'prediction': RESULT_MAP[pred],
        'prediction_label': RESULT_LABELS[pred],
        'prediction_code': pred,
        'confidence': float(max(probs) * 100),
        'home_prob': float(probs[2] * 100),
        'draw_prob': float(probs[1] * 100),
        'away_prob': float(probs[0] * 100),
        'home_form': home_form,
        'away_form': away_form
    }


def predict_match_v4(home_team, away_team, league_code, home_form, away_form):
    """Make prediction using V4 ensemble (60% XGBoost + 40% Neural Network)"""
    global elo_ratings, xgb_model_v4, nn_model_v4, scaler_v4, meta_v4

    # Get ELO ratings
    home_elo = elo_ratings.get(home_team, 1500)
    away_elo = elo_ratings.get(away_team, 1500)
    home_elo_adj = home_elo + 100  # Home advantage

    # Calculate ELO expected result
    elo_expected = 1 / (1 + 10 ** ((away_elo - home_elo_adj) / 400))

    # Default implied probabilities (from typical odds)
    impl_home = 0.45
    impl_draw = 0.27
    impl_away = 0.28

    # Build V4 feature vector (28 features)
    feature_columns = meta_v4.get('feature_columns', [])
    feature_row = {
        'elo_home': home_elo_adj,
        'elo_away': away_elo,
        'elo_diff': home_elo_adj - away_elo,
        'elo_expected_home': elo_expected,
        'home_form': home_form['ppg'] / 3,  # Normalize to 0-1
        'away_form': away_form['ppg'] / 3,
        'form_diff': (home_form['ppg'] - away_form['ppg']) / 3,
        'home_gpg': home_form['gpg'],
        'away_gpg': away_form['gpg'],
        'gpg_diff': home_form['gpg'] - away_form['gpg'],
        'home_gapg': home_form['gapg'],
        'away_gapg': away_form['gapg'],
        'defense_diff': away_form['gapg'] - home_form['gapg'],
        'home_win_rate': home_form['win_rate'],
        'away_win_rate': away_form['win_rate'],
        'win_rate_diff': home_form['win_rate'] - away_form['win_rate'],
        'home_home_ppg': home_form['ppg'] * 1.1,  # Home boost
        'away_away_ppg': away_form['ppg'] * 0.9,  # Away penalty
        'home_away_diff': home_form['ppg'] * 1.1 - away_form['ppg'] * 0.9,
        'h2h_home_wins': 0.5,  # Default
        'h2h_matches': 0.5,
        'impl_home': impl_home,
        'impl_draw': impl_draw,
        'impl_away': impl_away,
        'attack_vs_defense_home': home_form['gpg'] - away_form['gapg'],
        'attack_vs_defense_away': away_form['gpg'] - home_form['gapg'],
        'strength_composite': (home_elo_adj - away_elo) / 400 + (home_form['ppg'] - away_form['ppg']) / 2,
        'form_momentum': (home_form['win_rate'] - 0.33) - (away_form['win_rate'] - 0.33)
    }

    # Create feature vector in correct order
    X = np.array([[feature_row.get(f, 0) for f in feature_columns]])
    X = np.nan_to_num(X, nan=0, posinf=10, neginf=-10)

    # Scale features
    X_scaled = (X - scaler_v4['mean']) / scaler_v4['scale']

    # XGBoost prediction
    xgb_probs = xgb_model_v4.predict_proba(X)

    # Neural Network prediction
    with torch.no_grad():
        nn_probs = torch.softmax(nn_model_v4(torch.FloatTensor(X_scaled)), dim=1).numpy()

    # Ensemble: 60% XGBoost + 40% Neural Network
    probs = 0.6 * xgb_probs + 0.4 * nn_probs
    probs = probs[0]

    pred = int(probs.argmax())
    confidence = float(probs.max() * 100)

    return {
        'prediction': RESULT_MAP[pred],
        'prediction_label': RESULT_LABELS[pred],
        'prediction_code': pred,
        'confidence': confidence,
        'home_prob': float(probs[2] * 100),
        'draw_prob': float(probs[1] * 100),
        'away_prob': float(probs[0] * 100),
        'home_form': home_form,
        'away_form': away_form,
        'home_elo': home_elo,
        'away_elo': away_elo,
        'model_version': 'v4_ensemble'
    }


# === AUTH ROUTES ===

@app.route('/api/auth/login', methods=['POST'])
def login():
    """User login"""
    try:
        data = request.get_json()
        username = data.get('username', '').strip().lower()
        password = data.get('password', '')

        if not username or not password:
            return jsonify({'error': 'Username and password required'}), 400

        users = load_users()
        user = users.get(username)

        if not user or user['password_hash'] != hash_password(password):
            return jsonify({'error': 'Invalid credentials'}), 401

        token = generate_token(username, user['role'])

        response = jsonify({
            'success': True,
            'token': token,
            'user': {
                'username': username,
                'role': user['role']
            }
        })
        response.set_cookie('auth_token', token, httponly=True, samesite='Lax', max_age=JWT_EXPIRY_HOURS * 3600)
        return response

    except Exception as e:
        return jsonify({'error': str(e)}), 500


@app.route('/api/auth/register', methods=['POST'])
def register():
    """User registration"""
    try:
        data = request.get_json()
        username = data.get('username', '').strip().lower()
        password = data.get('password', '')
        email = data.get('email', '').strip().lower()

        if not username or not password:
            return jsonify({'error': 'Username and password required'}), 400

        if len(username) < 3:
            return jsonify({'error': 'Username must be at least 3 characters'}), 400

        if len(password) < 6:
            return jsonify({'error': 'Password must be at least 6 characters'}), 400

        users = load_users()

        if username in users:
            return jsonify({'error': 'Username already exists'}), 400

        users[username] = {
            'password_hash': hash_password(password),
            'email': email,
            'role': 'user',
            'created_at': datetime.now().isoformat()
        }

        save_users(users)

        token = generate_token(username, 'user')

        response = jsonify({
            'success': True,
            'token': token,
            'user': {
                'username': username,
                'role': 'user'
            }
        })
        response.set_cookie('auth_token', token, httponly=True, samesite='Lax', max_age=JWT_EXPIRY_HOURS * 3600)
        return response

    except Exception as e:
        return jsonify({'error': str(e)}), 500


@app.route('/api/auth/logout', methods=['POST'])
def logout():
    """User logout"""
    response = jsonify({'success': True})
    response.delete_cookie('auth_token')
    return response


@app.route('/api/auth/me', methods=['GET'])
@auth_required
def me():
    """Get current user info"""
    return jsonify({
        'username': request.user['username'],
        'role': request.user['role']
    })


@app.route('/api/admin/users', methods=['GET'])
@admin_required
def admin_users():
    """Get all users (admin only)"""
    users = load_users()
    return jsonify({
        'users': [
            {
                'username': u,
                'role': data['role'],
                'email': data.get('email', ''),
                'created_at': data.get('created_at', '')
            }
            for u, data in users.items()
        ]
    })


@app.route('/api/admin/stats', methods=['GET'])
@admin_required
def admin_stats():
    """Get admin dashboard stats"""
    users = load_users()
    total_users = len(users)
    admin_count = sum(1 for u in users.values() if u['role'] == 'admin')

    # Get prediction stats
    verification_path = os.path.join(DATA_DIR, 'verification_results.json')
    verification = {}
    if os.path.exists(verification_path):
        with open(verification_path) as f:
            verification = json.load(f)

    return jsonify({
        'users': {
            'total': total_users,
            'admins': admin_count,
            'regular': total_users - admin_count
        },
        'model': {
            'version': meta.get('model_version', 'V4') if meta else 'N/A',
            'accuracy': verification.get('summary', {}).get('accuracy', 0),
            'total_predictions': verification.get('summary', {}).get('total', 0)
        },
        'system': {
            'status': 'online',
            'last_update': datetime.now().isoformat()
        }
    })


# === API ROUTES ===

@app.route('/api/health', methods=['GET'])
def health():
    """Health check"""
    return jsonify({
        'status': 'ok',
        'model_loaded': model is not None,
        'timestamp': datetime.now().isoformat()
    })


@app.route('/api/model/stats', methods=['GET'])
def model_stats():
    """Get model statistics"""
    if meta is None:
        return jsonify({'error': 'Model not loaded'}), 500

    return jsonify({
        'trained_at': meta.get('trained_at'),
        'accuracy': meta.get('best_val_acc'),
        'class_accuracy': {
            'away': meta.get('class_accuracy', [0,0,0])[0],
            'draw': meta.get('class_accuracy', [0,0,0])[1],
            'home': meta.get('class_accuracy', [0,0,0])[2]
        },
        'total_matches': meta.get('total_matches'),
        'features': len(meta.get('feature_columns', []))
    })


@app.route('/api/leagues', methods=['GET'])
def get_leagues():
    """Get available leagues"""
    return jsonify(LEAGUE_INFO)


@app.route('/api/matches/recent', methods=['GET'])
def recent_matches():
    """Get recent matches with predictions vs results"""
    if historical_df is None:
        return jsonify({'error': 'Data not loaded'}), 500

    league = request.args.get('league', None)
    limit = int(request.args.get('limit', 100))

    df = historical_df.copy()
    if league:
        df = df[df['league_code'] == league]

    # Get recent matches
    recent = df.tail(limit).iloc[::-1]  # Reverse to show newest first

    results = []
    for _, row in recent.iterrows():
        # Get prediction for this match
        pred = predict_match(row['home_team'], row['away_team'], row['league_code'])

        results.append({
            'id': str(row['match_id']),
            'date': str(row['Date'])[:10] if pd.notna(row['Date']) else None,
            'league_code': row['league_code'],
            'league_name': LEAGUE_INFO.get(row['league_code'], {}).get('name', row['league_code']),
            'league_color': LEAGUE_INFO.get(row['league_code'], {}).get('color', '#333'),
            'flag': LEAGUE_INFO.get(row['league_code'], {}).get('flag', ''),
            'home_team': row['home_team'],
            'away_team': row['away_team'],
            'home_goals': int(row['home_goals']) if pd.notna(row['home_goals']) else None,
            'away_goals': int(row['away_goals']) if pd.notna(row['away_goals']) else None,
            'actual_result': RESULT_MAP.get(int(row['result'])) if pd.notna(row['result']) else None,
            'actual_result_label': RESULT_LABELS.get(int(row['result'])) if pd.notna(row['result']) else None,
            'predicted_result': pred['prediction'] if pred else None,
            'predicted_label': pred['prediction_label'] if pred else None,
            'confidence': round(pred['confidence'], 1) if pred else 0,
            'home_prob': round(pred['home_prob'], 1) if pred else 33,
            'draw_prob': round(pred['draw_prob'], 1) if pred else 33,
            'away_prob': round(pred['away_prob'], 1) if pred else 33,
            'correct': (pred['prediction'] == RESULT_MAP.get(int(row['result']))) if pred and pd.notna(row['result']) else None
        })

    return jsonify({
        'matches': results,
        'total': len(results)
    })


@app.route('/api/verification', methods=['GET'])
def verification_results():
    """Get verification results (predictions vs actual)"""
    try:
        with open(os.path.join(DATA_DIR, 'verification_results.json')) as f:
            data = json.load(f)

        # Check if it's the new V4 format (has 'results' key)
        if isinstance(data, dict) and 'results' in data:
            # New V4 format - return as-is with all fields
            return jsonify(data)

        # Old format - data is a list of results
        results = data
        correct = sum(1 for r in results if r.get('correct', False))
        total = len(results)

        # Group by league
        by_league = {}
        for r in results:
            league = r.get('league', 'unknown')
            if league not in by_league:
                by_league[league] = {'correct': 0, 'total': 0, 'matches': []}
            by_league[league]['total'] += 1
            if r.get('correct', False):
                by_league[league]['correct'] += 1
            by_league[league]['matches'].append(r)

        for league in by_league:
            by_league[league]['accuracy'] = round(
                by_league[league]['correct'] / by_league[league]['total'] * 100, 1
            ) if by_league[league]['total'] > 0 else 0

        return jsonify({
            'results': results,
            'by_league': by_league,
            'summary': {
                'total': total,
                'correct': correct,
                'accuracy': round(correct / total * 100, 1) if total > 0 else 0
            }
        })
    except Exception as e:
        return jsonify({'error': str(e)}), 500


@app.route('/api/verification/live-status', methods=['GET'])
def live_verification_status():
    """Get real-time verification status - shows pending matches and recent verifications"""
    try:
        # 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 scheduler state
        state_path = os.path.join(DATA_DIR, 'scheduler_state.json')
        scheduler_state = {}
        if os.path.exists(state_path):
            with open(state_path) as f:
                scheduler_state = json.load(f)

        # Load verification
        verification_path = os.path.join(DATA_DIR, 'verification_results.json')
        verification = {'summary': {'total': 0, 'correct': 0, 'accuracy': 0}}
        if os.path.exists(verification_path):
            with open(verification_path) as f:
                verification = json.load(f)

        # Categorize predictions by status
        now = datetime.now()
        live_matches = []
        pending_verification = []
        upcoming = []

        for pred in predictions:
            try:
                match_dt_str = f"{pred.get('date', '')} {pred.get('time', '15:00')}"
                match_dt = datetime.strptime(match_dt_str, '%Y-%m-%d %H:%M')
                elapsed_minutes = (now - match_dt).total_seconds() / 60

                if elapsed_minutes < 0:
                    # Future match
                    upcoming.append({
                        'home_team': pred.get('home_team'),
                        'away_team': pred.get('away_team'),
                        'date': pred.get('date'),
                        'time': pred.get('time'),
                        'prediction': pred.get('prediction'),
                        'confidence': pred.get('confidence'),
                        'starts_in_minutes': int(-elapsed_minutes)
                    })
                elif elapsed_minutes < 115:
                    # In progress
                    live_matches.append({
                        'home_team': pred.get('home_team'),
                        'away_team': pred.get('away_team'),
                        'date': pred.get('date'),
                        'time': pred.get('time'),
                        'prediction': pred.get('prediction'),
                        'confidence': pred.get('confidence'),
                        'minutes_elapsed': int(elapsed_minutes),
                        'status': 'live' if elapsed_minutes < 95 else 'should_be_finished'
                    })
                elif elapsed_minutes < 1440:
                    # Should be finished, pending verification
                    pending_verification.append({
                        'home_team': pred.get('home_team'),
                        'away_team': pred.get('away_team'),
                        'date': pred.get('date'),
                        'time': pred.get('time'),
                        'prediction': pred.get('prediction'),
                        'confidence': pred.get('confidence'),
                        'finished_minutes_ago': int(elapsed_minutes - 95)
                    })
            except Exception:
                continue

        # Get recent verifications (last 24h)
        recent_verified = []
        for r in verification.get('results', [])[:20]:
            verified_at = r.get('verified_at', r.get('date'))
            recent_verified.append({
                'home_team': r.get('home_team'),
                'away_team': r.get('away_team'),
                'date': r.get('date'),
                'result': f"{r.get('home_goals', 0)}-{r.get('away_goals', 0)}",
                'predicted': r.get('predicted'),
                'actual': r.get('actual'),
                'correct': r.get('correct'),
                'confidence': r.get('confidence')
            })

        return jsonify({
            'timestamp': now.isoformat(),
            'scheduler': {
                'last_verify': scheduler_state.get('last_verify'),
                'last_predict': scheduler_state.get('last_predict'),
                'verify_count_today': scheduler_state.get('verify_count_today', 0)
            },
            'live_matches': live_matches,
            'pending_verification': pending_verification[:10],
            'upcoming_soon': [u for u in upcoming if u['starts_in_minutes'] < 180][:10],
            'recent_verified': recent_verified,
            'overall_stats': verification.get('summary', {})
        })

    except Exception as e:
        return jsonify({'error': str(e)}), 500


@app.route('/api/historical-bets', methods=['GET'])
def historical_bets():
    """Get historical betting results for verification display"""
    try:
        bets_path = os.path.join(DATA_DIR, 'historical_single_bets.json')

        if os.path.exists(bets_path):
            with open(bets_path) as f:
                data = json.load(f)
            return jsonify(data)

        return jsonify({'error': 'Historical data not available'}), 404

    except Exception as e:
        return jsonify({'error': str(e)}), 500


@app.route('/api/frontend-stats', methods=['GET'])
def frontend_stats():
    """Get aggregated statistics for frontend display"""
    try:
        stats_path = os.path.join(DATA_DIR, 'frontend_stats.json')

        if os.path.exists(stats_path):
            with open(stats_path) as f:
                stats = json.load(f)
            return jsonify(stats)

        # Fallback to verification_results if frontend_stats not available
        verification_path = os.path.join(DATA_DIR, 'verification_results.json')
        if os.path.exists(verification_path):
            with open(verification_path) as f:
                verification = json.load(f)

            summary = verification.get('summary', {})
            by_confidence = verification.get('by_confidence', {})

            return jsonify({
                'single_bets': {
                    'win_rate': by_confidence.get('60', {}).get('accuracy', 67.8),
                    'total': by_confidence.get('60', {}).get('total', 143)
                },
                'model_accuracy': {
                    'overall': summary.get('accuracy', 53.8),
                    'training_matches': verification.get('training_info', {}).get('training_matches', 17611),
                    'test_matches': verification.get('training_info', {}).get('test_matches', 400),
                    'by_confidence': by_confidence
                },
                'improvement_over_random': {
                    'random_probability': 33.3,
                    'ai_probability': by_confidence.get('60', {}).get('accuracy', 67.8),
                    'improvement_factor': round(by_confidence.get('60', {}).get('accuracy', 67.8) / 33.3, 2)
                }
            })

        # Default fallback
        return jsonify({
            'single_bets': {'win_rate': 67.8, 'total': 143},
            'model_accuracy': {'overall': 53.8, 'training_matches': 17611, 'test_matches': 400},
            'improvement_over_random': {'random_probability': 33.3, 'ai_probability': 67.8, 'improvement_factor': 2.04}
        })

    except Exception as e:
        return jsonify({'error': str(e)}), 500


@app.route('/api/stats/league/<league_code>', methods=['GET'])
def league_stats(league_code):
    """Get statistics for a specific league"""
    if historical_df is None:
        return jsonify({'error': 'Data not loaded'}), 500

    league_df = historical_df[historical_df['league_code'] == league_code]

    if league_df.empty:
        return jsonify({'error': 'League not found'}), 404

    # Calculate statistics
    total_matches = len(league_df)
    home_wins = int((league_df['result'] == 2).sum())
    draws = int((league_df['result'] == 1).sum())
    away_wins = int((league_df['result'] == 0).sum())

    avg_home_goals = float(league_df['home_goals'].mean())
    avg_away_goals = float(league_df['away_goals'].mean())

    # Team standings (current season)
    current_season = league_df['season'].iloc[-1]
    season_df = league_df[league_df['season'] == current_season]

    teams = {}
    for _, row in season_df.iterrows():
        home = row['home_team']
        away = row['away_team']

        if home not in teams:
            teams[home] = {'played': 0, 'won': 0, 'draw': 0, 'lost': 0, 'gf': 0, 'ga': 0, 'pts': 0}
        if away not in teams:
            teams[away] = {'played': 0, 'won': 0, 'draw': 0, 'lost': 0, 'gf': 0, 'ga': 0, 'pts': 0}

        teams[home]['played'] += 1
        teams[away]['played'] += 1
        teams[home]['gf'] += int(row['home_goals'])
        teams[home]['ga'] += int(row['away_goals'])
        teams[away]['gf'] += int(row['away_goals'])
        teams[away]['ga'] += int(row['home_goals'])

        if row['result'] == 2:
            teams[home]['won'] += 1
            teams[home]['pts'] += 3
            teams[away]['lost'] += 1
        elif row['result'] == 0:
            teams[away]['won'] += 1
            teams[away]['pts'] += 3
            teams[home]['lost'] += 1
        else:
            teams[home]['draw'] += 1
            teams[away]['draw'] += 1
            teams[home]['pts'] += 1
            teams[away]['pts'] += 1

    # Sort by points
    standings = sorted([
        {'team': k, **v, 'gd': v['gf'] - v['ga']}
        for k, v in teams.items()
    ], key=lambda x: (-x['pts'], -x['gd'], -x['gf']))

    # Add position
    for i, team in enumerate(standings):
        team['position'] = i + 1

    return jsonify({
        'league': LEAGUE_INFO.get(league_code, {'name': league_code}),
        'total_matches': total_matches,
        'distribution': {
            'home_wins': home_wins,
            'draws': draws,
            'away_wins': away_wins,
            'home_win_pct': round(home_wins / total_matches * 100, 1),
            'draw_pct': round(draws / total_matches * 100, 1),
            'away_win_pct': round(away_wins / total_matches * 100, 1)
        },
        'avg_goals': {
            'home': round(avg_home_goals, 2),
            'away': round(avg_away_goals, 2),
            'total': round(avg_home_goals + avg_away_goals, 2)
        },
        'current_season': current_season,
        'standings': standings[:20]
    })


@app.route('/api/stats/overall', methods=['GET'])
def overall_stats():
    """Get overall statistics"""
    if historical_df is None:
        return jsonify({'error': 'Data not loaded'}), 500

    total = len(historical_df)
    home_wins = int((historical_df['result'] == 2).sum())
    draws = int((historical_df['result'] == 1).sum())
    away_wins = int((historical_df['result'] == 0).sum())

    return jsonify({
        'total_matches': total,
        'distribution': {
            'home_wins': home_wins,
            'draws': draws,
            'away_wins': away_wins
        },
        'model_accuracy': meta.get('best_val_acc', 0) if meta else 0,
        'leagues': len(LEAGUE_INFO),
        'seasons': int(historical_df['season_year'].nunique()) if 'season_year' in historical_df.columns else 10
    })


@app.route('/api/predict', methods=['POST'])
def predict():
    """Predict a match"""
    data = request.get_json()

    home_team = data.get('home_team')
    away_team = data.get('away_team')
    league_code = data.get('league_code', 'E0')

    if not home_team or not away_team:
        return jsonify({'error': 'home_team and away_team required'}), 400

    pred = predict_match(home_team, away_team, league_code)

    if pred is None:
        return jsonify({'error': 'Prediction failed'}), 500

    return jsonify({
        'home_team': home_team,
        'away_team': away_team,
        'league': LEAGUE_INFO.get(league_code, {'name': league_code}),
        **pred
    })


@app.route('/api/teams/<league_code>', methods=['GET'])
def get_teams(league_code):
    """Get all teams for a league"""
    if historical_df is None:
        return jsonify({'error': 'Data not loaded'}), 500

    league_df = historical_df[historical_df['league_code'] == league_code]

    # Get teams from current season
    current_season = league_df['season'].iloc[-1] if len(league_df) > 0 else None
    if current_season:
        season_df = league_df[league_df['season'] == current_season]
        teams = set(season_df['home_team'].unique()) | set(season_df['away_team'].unique())
    else:
        teams = set(league_df['home_team'].unique()) | set(league_df['away_team'].unique())

    return jsonify({
        'league': LEAGUE_INFO.get(league_code, {'name': league_code}),
        'teams': sorted(list(teams)),
        'season': current_season
    })


@app.route('/api/predictions', methods=['GET'])
@app.route('/api/predictions/upcoming', methods=['GET'])
def upcoming_predictions():
    """Get upcoming match predictions"""
    try:
        predictions_path = os.path.join(DATA_DIR, 'predictions_upcoming.json')

        if not os.path.exists(predictions_path):
            return jsonify({'error': 'No predictions available', 'predictions': []}), 200

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

        # Filter by league if specified
        league = request.args.get('league')
        if league:
            predictions = [p for p in predictions if p['league_code'] == league]

        # Filter by date range
        date_from = request.args.get('from')
        date_to = request.args.get('to')

        if date_from:
            predictions = [p for p in predictions if p['date'] >= date_from]
        if date_to:
            predictions = [p for p in predictions if p['date'] <= date_to]

        # Add league info
        for p in predictions:
            league_info = LEAGUE_INFO.get(p['league_code'], {})
            p['flag'] = league_info.get('flag', '')
            p['league_color'] = league_info.get('color', '#333')

        return jsonify({
            'predictions': predictions,
            'total': len(predictions),
            'generated_at': predictions[0].get('generated_at') if predictions else None
        })

    except Exception as e:
        return jsonify({'error': str(e)}), 500


@app.route('/api/fixtures/refresh', methods=['POST'])
def refresh_fixtures():
    """Refresh fixtures and predictions"""
    try:
        from fixture_collector import FixtureCollector, generate_predictions_for_fixtures

        collector = FixtureCollector()
        fixtures = collector.collect_all_fixtures()
        predictions = generate_predictions_for_fixtures()

        return jsonify({
            'status': 'ok',
            'fixtures_collected': len(fixtures),
            'predictions_generated': len(predictions)
        })
    except Exception as e:
        return jsonify({'error': str(e)}), 500


@app.route('/api/predictions/by-date', methods=['GET'])
def predictions_by_date():
    """Get predictions grouped by date"""
    try:
        predictions_path = os.path.join(DATA_DIR, 'predictions_upcoming.json')

        if not os.path.exists(predictions_path):
            return jsonify({'dates': {}})

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

        # Filter by league if specified
        league = request.args.get('league')
        if league:
            predictions = [p for p in predictions if p['league_code'] == league]

        # Group by date
        by_date = {}
        for p in predictions:
            date = p['date']
            if date not in by_date:
                by_date[date] = []

            league_info = LEAGUE_INFO.get(p['league_code'], {})
            p['flag'] = league_info.get('flag', '')
            p['league_color'] = league_info.get('color', '#333')

            by_date[date].append(p)

        # Sort matches within each date by time
        for date in by_date:
            by_date[date].sort(key=lambda x: x['time'])

        return jsonify({
            'dates': by_date,
            'total_predictions': len(predictions)
        })

    except Exception as e:
        return jsonify({'error': str(e)}), 500


# === FEEDBACK ENDPOINTS ===

FEEDBACK_FILE = os.path.join(DATA_DIR, 'feedback.json')

@app.route('/api/feedback', methods=['POST'])
def submit_feedback():
    """Submit user feedback"""
    try:
        data = request.get_json()

        # Load existing feedback
        feedback_list = []
        if os.path.exists(FEEDBACK_FILE):
            with open(FEEDBACK_FILE) as f:
                feedback_list = json.load(f)

        # Add new feedback
        feedback_list.append({
            'id': len(feedback_list) + 1,
            'match_id': data.get('match_id'),
            'rating': data.get('rating'),
            'quick_feedback': data.get('quick_feedback'),
            'message': data.get('message'),
            'type': data.get('type', 'general'),
            'timestamp': data.get('timestamp', datetime.now().isoformat())
        })

        # Save
        with open(FEEDBACK_FILE, 'w') as f:
            json.dump(feedback_list, f, indent=2)

        return jsonify({'success': True})
    except Exception as e:
        return jsonify({'error': str(e)}), 500


@app.route('/api/feedback/quick', methods=['POST'])
def quick_feedback():
    """Submit quick thumbs up/down feedback"""
    try:
        data = request.get_json()

        feedback_list = []
        if os.path.exists(FEEDBACK_FILE):
            with open(FEEDBACK_FILE) as f:
                feedback_list = json.load(f)

        feedback_list.append({
            'id': len(feedback_list) + 1,
            'match_id': data.get('match_id'),
            'positive': data.get('positive'),
            'type': 'quick',
            'timestamp': data.get('timestamp', datetime.now().isoformat())
        })

        with open(FEEDBACK_FILE, 'w') as f:
            json.dump(feedback_list, f, indent=2)

        return jsonify({'success': True})
    except Exception as e:
        return jsonify({'error': str(e)}), 500


# === ADVANCED HISTORICAL BETS ===

@app.route('/api/historical-bets/advanced', methods=['GET'])
def historical_bets_advanced():
    """Get historical betting results with advanced filters and profit calculation"""
    try:
        verification_path = os.path.join(DATA_DIR, 'verification_results.json')

        if not os.path.exists(verification_path):
            return jsonify({'error': 'Data not available'}), 404

        with open(verification_path) as f:
            data = json.load(f)

        results = data.get('results', [])

        # Get filter parameters
        days = request.args.get('days', type=int)  # 1, 2, 3, 7, 30 etc
        min_confidence = request.args.get('min_confidence', 60, type=int)
        max_confidence = request.args.get('max_confidence', 100, type=int)
        league = request.args.get('league')
        only_wins = request.args.get('only_wins', 'false').lower() == 'true'
        sort_by = request.args.get('sort', 'date')  # date, confidence, profit

        # Filter by date range
        if days:
            cutoff = (datetime.now() - timedelta(days=days)).isoformat()[:10]
            results = [r for r in results if r.get('date', '') >= cutoff]

        # Filter by confidence
        results = [r for r in results if min_confidence <= r.get('confidence', 0) <= max_confidence]

        # Filter by league
        if league:
            results = [r for r in results if r.get('league') == league]

        # Filter only wins
        if only_wins:
            results = [r for r in results if r.get('correct', False)]

        # Calculate profit/loss for each match (flat stake of 10 units)
        STAKE = 10
        total_staked = 0
        total_profit = 0

        for r in results:
            total_staked += STAKE
            odds = r.get('odds', 1.9)  # Default odds if not available

            if r.get('correct', False):
                profit = (odds - 1) * STAKE
                r['profit'] = round(profit, 2)
                r['profit_display'] = f"+{profit:.2f}"
            else:
                r['profit'] = -STAKE
                r['profit_display'] = f"-{STAKE:.2f}"

            total_profit += r['profit']

        # Sort results
        if sort_by == 'confidence':
            results.sort(key=lambda x: x.get('confidence', 0), reverse=True)
        elif sort_by == 'profit':
            results.sort(key=lambda x: x.get('profit', 0), reverse=True)
        elif sort_by == 'date':
            results.sort(key=lambda x: x.get('date', ''), reverse=True)

        # Calculate statistics
        total = len(results)
        correct = sum(1 for r in results if r.get('correct', False))
        accuracy = round(correct / total * 100, 1) if total > 0 else 0
        roi = round(total_profit / total_staked * 100, 2) if total_staked > 0 else 0

        # Group by league
        by_league = {}
        for r in results:
            lg = r.get('league', 'Unknown')
            if lg not in by_league:
                by_league[lg] = {'wins': 0, 'total': 0, 'profit': 0}
            by_league[lg]['total'] += 1
            by_league[lg]['profit'] += r.get('profit', 0)
            if r.get('correct', False):
                by_league[lg]['wins'] += 1

        for lg in by_league:
            by_league[lg]['accuracy'] = round(by_league[lg]['wins'] / by_league[lg]['total'] * 100, 1)
            by_league[lg]['profit'] = round(by_league[lg]['profit'], 2)

        # Group by confidence bands
        by_confidence = {}
        for band in ['60-65', '65-70', '70-75', '75-80', '80+']:
            by_confidence[band] = {'wins': 0, 'total': 0, 'profit': 0}

        for r in results:
            conf = r.get('confidence', 0)
            if conf >= 80:
                band = '80+'
            elif conf >= 75:
                band = '75-80'
            elif conf >= 70:
                band = '70-75'
            elif conf >= 65:
                band = '65-70'
            else:
                band = '60-65'

            by_confidence[band]['total'] += 1
            by_confidence[band]['profit'] += r.get('profit', 0)
            if r.get('correct', False):
                by_confidence[band]['wins'] += 1

        for band in by_confidence:
            if by_confidence[band]['total'] > 0:
                by_confidence[band]['accuracy'] = round(
                    by_confidence[band]['wins'] / by_confidence[band]['total'] * 100, 1
                )
                by_confidence[band]['profit'] = round(by_confidence[band]['profit'], 2)

        # Best picks (highest confidence wins)
        best_picks = sorted(
            [r for r in results if r.get('correct', False)],
            key=lambda x: x.get('confidence', 0),
            reverse=True
        )[:10]

        return jsonify({
            'results': results,
            'summary': {
                'total_bets': total,
                'wins': correct,
                'losses': total - correct,
                'accuracy': accuracy,
                'total_staked': total_staked,
                'total_profit': round(total_profit, 2),
                'roi': roi,
                'improvement_over_random': round(accuracy / 33.3, 2) if accuracy > 0 else 0
            },
            'by_league': by_league,
            'by_confidence': by_confidence,
            'best_picks': best_picks,
            'filters_applied': {
                'days': days,
                'min_confidence': min_confidence,
                'max_confidence': max_confidence,
                'league': league,
                'only_wins': only_wins
            }
        })

    except Exception as e:
        return jsonify({'error': str(e)}), 500


@app.route('/api/betting-slips', methods=['GET'])
def get_betting_slips():
    """Get betting slip configurations with day-based completion"""
    try:
        predictions_path = os.path.join(DATA_DIR, 'predictions_upcoming.json')

        if not os.path.exists(predictions_path):
            return jsonify({'slips': []})

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

        # Get parameters
        days = request.args.get('days', 1, type=int)  # 1, 2, 3 days
        min_confidence = request.args.get('min_confidence', 65, type=int)
        max_matches = request.args.get('max_matches', 5, type=int)
        strategy = request.args.get('strategy', 'best')  # best, safe, risky

        # Filter by date
        today = datetime.now().date()
        valid_dates = [(today + timedelta(days=i)).isoformat() for i in range(days)]

        predictions = [p for p in predictions if p['date'] in valid_dates]

        # Filter by confidence
        predictions = [p for p in predictions if p.get('confidence', 0) >= min_confidence]

        # Apply strategy
        if strategy == 'safe':
            # High confidence, home wins preferred
            predictions.sort(key=lambda x: (x.get('confidence', 0), x.get('prediction') == 'H'), reverse=True)
        elif strategy == 'risky':
            # Mix of predictions, higher odds potential
            predictions.sort(key=lambda x: x.get('confidence', 0), reverse=True)
        else:
            # Best overall
            predictions.sort(key=lambda x: x.get('confidence', 0), reverse=True)

        # Select top matches
        selected = predictions[:max_matches]

        # Calculate potential returns
        combined_odds = 1.0
        for p in selected:
            odds = 1.8 if p.get('prediction') == 'H' else 3.0 if p.get('prediction') == 'D' else 2.5
            combined_odds *= odds

        return jsonify({
            'slip': {
                'matches': selected,
                'days': days,
                'total_matches': len(selected),
                'min_confidence': min_confidence,
                'strategy': strategy,
                'combined_odds': round(combined_odds, 2),
                'potential_return_10': round(10 * combined_odds, 2),
                'completion_date': valid_dates[-1] if valid_dates else None
            },
            'recommendations': {
                'single_bets': selected[:3],  # Top 3 for single bets (safest)
                'double': selected[:2] if len(selected) >= 2 else [],
                'treble': selected[:3] if len(selected) >= 3 else []
            },
            'stats': {
                'avg_confidence': round(sum(p.get('confidence', 0) for p in selected) / len(selected), 1) if selected else 0,
                'expected_wins': round(sum(p.get('confidence', 0)/100 for p in selected), 1) if selected else 0
            }
        })

    except Exception as e:
        return jsonify({'error': str(e)}), 500


@app.route('/api/leagues', methods=['GET'])
def get_all_leagues():
    """Get all available leagues with stats"""
    try:
        leagues = []
        for code, info in LEAGUE_INFO.items():
            league_data = {
                'code': code,
                'name': info.get('name', code),
                'country': info.get('country', 'Unknown'),
                'flag': info.get('flag', ''),
                'color': info.get('color', '#333')
            }

            # Get match count if data available
            if historical_df is not None:
                count = len(historical_df[historical_df['league_code'] == code])
                league_data['total_matches'] = int(count)

            leagues.append(league_data)

        # Sort by total matches
        leagues.sort(key=lambda x: x.get('total_matches', 0), reverse=True)

        return jsonify({'leagues': leagues})

    except Exception as e:
        return jsonify({'error': str(e)}), 500


# === CONTACT & ADMIN MESSAGES ===

MESSAGES_FILE = os.path.join(DATA_DIR, 'contact_messages.json')

def load_messages():
    if os.path.exists(MESSAGES_FILE):
        with open(MESSAGES_FILE) as f:
            return json.load(f)
    return []

def save_messages(messages):
    os.makedirs(os.path.dirname(MESSAGES_FILE), exist_ok=True)
    with open(MESSAGES_FILE, 'w') as f:
        json.dump(messages, f, indent=2)


@app.route('/api/contact', methods=['POST'])
def submit_contact():
    """Submit a contact form message"""
    try:
        data = request.get_json()

        messages = load_messages()

        message = {
            'id': f"msg_{len(messages) + 1}_{int(datetime.now().timestamp())}",
            'name': data.get('name', ''),
            'email': data.get('email', ''),
            'subject': data.get('subject', ''),
            'message': data.get('message', ''),
            'timestamp': data.get('timestamp', datetime.now().isoformat()),
            'read': False
        }

        messages.append(message)
        save_messages(messages)

        return jsonify({'success': True, 'message_id': message['id']})

    except Exception as e:
        return jsonify({'error': str(e)}), 500


@app.route('/api/admin/messages', methods=['GET'])
@auth_required
def get_admin_messages():
    """Get all contact messages (admin only)"""
    try:
        if request.user.get('role') != 'admin':
            return jsonify({'error': 'Admin access required'}), 403

        messages = load_messages()
        messages.sort(key=lambda x: x.get('timestamp', ''), reverse=True)

        return jsonify({'messages': messages})

    except Exception as e:
        return jsonify({'error': str(e)}), 500


@app.route('/api/admin/messages/<message_id>/read', methods=['PUT'])
@auth_required
def mark_message_read(message_id):
    """Mark a message as read (admin only)"""
    try:
        if request.user.get('role') != 'admin':
            return jsonify({'error': 'Admin access required'}), 403

        messages = load_messages()

        for msg in messages:
            if msg.get('id') == message_id:
                msg['read'] = True
                break

        save_messages(messages)
        return jsonify({'success': True})

    except Exception as e:
        return jsonify({'error': str(e)}), 500


@app.route('/api/admin/messages/<message_id>', methods=['DELETE'])
@auth_required
def delete_message(message_id):
    """Delete a message (admin only)"""
    try:
        if request.user.get('role') != 'admin':
            return jsonify({'error': 'Admin access required'}), 403

        messages = load_messages()
        messages = [m for m in messages if m.get('id') != message_id]
        save_messages(messages)

        return jsonify({'success': True})

    except Exception as e:
        return jsonify({'error': str(e)}), 500


@app.route('/api/feedback/comments', methods=['GET'])
def get_feedback_comments():
    """Get feedback comments for a specific match"""
    try:
        match_id = request.args.get('match_id')

        if not os.path.exists(FEEDBACK_FILE):
            return jsonify({'comments': []})

        with open(FEEDBACK_FILE) as f:
            all_feedback = json.load(f)

        # Filter by match_id and only return those with messages
        comments = [
            {
                'id': str(fb.get('id')),
                'username': fb.get('username', 'Utente'),
                'message': fb.get('message', ''),
                'rating': fb.get('rating', 0),
                'positive': fb.get('quick_feedback') == 'positive' or fb.get('positive', False),
                'timestamp': fb.get('timestamp', '')
            }
            for fb in all_feedback
            if fb.get('match_id') == match_id and fb.get('message')
        ]

        # Sort by timestamp, most recent first
        comments.sort(key=lambda x: x.get('timestamp', ''), reverse=True)

        return jsonify({'comments': comments[:50]})  # Limit to 50 comments

    except Exception as e:
        return jsonify({'error': str(e), 'comments': []}), 500


@app.route('/api/user/profile', methods=['GET'])
@auth_required
def get_user_profile():
    """Get current user's profile"""
    try:
        users = load_users()
        username = request.user.get('username')

        if username not in users:
            return jsonify({'error': 'User not found'}), 404

        user = users[username]
        return jsonify({
            'username': username,
            'email': user.get('email', ''),
            'role': user.get('role', 'user'),
            'profile': user.get('profile', {}),
            'created_at': user.get('created_at')
        })

    except Exception as e:
        return jsonify({'error': str(e)}), 500


@app.route('/api/user/profile', methods=['PUT'])
@auth_required
def update_user_profile():
    """Update current user's profile"""
    try:
        users = load_users()
        username = request.user.get('username')

        if username not in users:
            return jsonify({'error': 'User not found'}), 404

        data = request.get_json()

        # Update email if provided
        if 'email' in data:
            users[username]['email'] = data['email']

        # Update profile fields
        if 'profile' not in users[username]:
            users[username]['profile'] = {}

        profile = users[username]['profile']
        profile['full_name'] = data.get('full_name', profile.get('full_name', ''))
        profile['bio'] = data.get('bio', profile.get('bio', ''))
        profile['favorite_team'] = data.get('favorite_team', profile.get('favorite_team', ''))
        profile['favorite_team_league'] = data.get('favorite_team_league', profile.get('favorite_team_league', ''))

        save_users(users)

        return jsonify({'success': True, 'profile': users[username]})

    except Exception as e:
        return jsonify({'error': str(e)}), 500


# === VIRTUAL BETTING SYSTEM ===

WALLETS_FILE = os.path.join(DATA_DIR, 'virtual_wallets.json')
BETS_FILE = os.path.join(DATA_DIR, 'virtual_bets.json')
INITIAL_BALANCE = 1000.0  # Starting capital for each user

def load_wallets():
    if os.path.exists(WALLETS_FILE):
        with open(WALLETS_FILE) as f:
            return json.load(f)
    return {}

def save_wallets(wallets):
    os.makedirs(os.path.dirname(WALLETS_FILE), exist_ok=True)
    with open(WALLETS_FILE, 'w') as f:
        json.dump(wallets, f, indent=2)

def load_bets():
    if os.path.exists(BETS_FILE):
        with open(BETS_FILE) as f:
            return json.load(f)
    return {}

def save_bets(bets):
    os.makedirs(os.path.dirname(BETS_FILE), exist_ok=True)
    with open(BETS_FILE, 'w') as f:
        json.dump(bets, f, indent=2)

def get_user_wallet(username):
    wallets = load_wallets()
    if username not in wallets:
        wallets[username] = {
            'balance': INITIAL_BALANCE,
            'initial_balance': INITIAL_BALANCE,
            'total_wagered': 0,
            'total_won': 0,
            'total_lost': 0,
            'bets_placed': 0,
            'bets_won': 0,
            'bets_lost': 0,
            'created_at': datetime.now().isoformat()
        }
        save_wallets(wallets)
    return wallets[username]


@app.route('/api/wallet', methods=['GET'])
@auth_required
def get_wallet():
    """Get user's virtual wallet"""
    try:
        username = request.user.get('username')
        wallet = get_user_wallet(username)

        # Calculate stats
        profit_loss = wallet['total_won'] - wallet['total_lost']
        roi = (profit_loss / wallet['total_wagered'] * 100) if wallet['total_wagered'] > 0 else 0
        win_rate = (wallet['bets_won'] / wallet['bets_placed'] * 100) if wallet['bets_placed'] > 0 else 0

        return jsonify({
            'balance': round(wallet['balance'], 2),
            'initial_balance': wallet['initial_balance'],
            'profit_loss': round(profit_loss, 2),
            'roi': round(roi, 1),
            'total_wagered': round(wallet['total_wagered'], 2),
            'total_won': round(wallet['total_won'], 2),
            'total_lost': round(wallet['total_lost'], 2),
            'bets_placed': wallet['bets_placed'],
            'bets_won': wallet['bets_won'],
            'bets_lost': wallet['bets_lost'],
            'win_rate': round(win_rate, 1)
        })
    except Exception as e:
        return jsonify({'error': str(e)}), 500


@app.route('/api/wallet/reset', methods=['POST'])
@auth_required
def reset_wallet():
    """Reset user's wallet to initial balance"""
    try:
        username = request.user.get('username')
        wallets = load_wallets()

        wallets[username] = {
            'balance': INITIAL_BALANCE,
            'initial_balance': INITIAL_BALANCE,
            'total_wagered': 0,
            'total_won': 0,
            'total_lost': 0,
            'bets_placed': 0,
            'bets_won': 0,
            'bets_lost': 0,
            'created_at': datetime.now().isoformat()
        }
        save_wallets(wallets)

        # Also clear user's bets
        bets = load_bets()
        if username in bets:
            bets[username] = []
            save_bets(bets)

        return jsonify({'success': True, 'balance': INITIAL_BALANCE})
    except Exception as e:
        return jsonify({'error': str(e)}), 500


@app.route('/api/bets', methods=['GET'])
@auth_required
def get_user_bets():
    """Get user's betting history"""
    try:
        username = request.user.get('username')
        bets = load_bets()
        user_bets = bets.get(username, [])

        # Sort by created_at descending
        user_bets.sort(key=lambda x: x.get('created_at', ''), reverse=True)

        # Filter by status if provided
        status = request.args.get('status')  # pending, won, lost, all
        if status and status != 'all':
            user_bets = [b for b in user_bets if b.get('status') == status]

        return jsonify({
            'bets': user_bets,
            'total': len(user_bets)
        })
    except Exception as e:
        return jsonify({'error': str(e)}), 500


@app.route('/api/bets', methods=['POST'])
@auth_required
def create_bet():
    """Create a new virtual bet"""
    try:
        username = request.user.get('username')
        data = request.get_json()

        stake = float(data.get('stake', 10))
        matches = data.get('matches', [])
        strategy = data.get('strategy', 'custom')

        if not matches:
            return jsonify({'error': 'No matches provided'}), 400

        if stake <= 0:
            return jsonify({'error': 'Invalid stake amount'}), 400

        # Check wallet balance
        wallet = get_user_wallet(username)
        if wallet['balance'] < stake:
            return jsonify({'error': 'Insufficient balance', 'balance': wallet['balance']}), 400

        # Calculate total odds
        total_odds = 1.0
        for match in matches:
            total_odds *= float(match.get('odds', 1.0))

        potential_win = round(stake * total_odds, 2)

        # Create bet
        bet_id = f"{username}_{datetime.now().strftime('%Y%m%d%H%M%S')}_{secrets.token_hex(4)}"

        bet = {
            'id': bet_id,
            'matches': matches,
            'stake': stake,
            'total_odds': round(total_odds, 2),
            'potential_win': potential_win,
            'strategy': strategy,
            'status': 'pending',  # pending, won, lost, partial
            'created_at': datetime.now().isoformat(),
            'settled_at': None,
            'won_amount': 0,
            'matches_won': 0,
            'matches_lost': 0
        }

        # Deduct stake from wallet
        wallets = load_wallets()
        wallets[username]['balance'] -= stake
        wallets[username]['total_wagered'] += stake
        wallets[username]['bets_placed'] += 1
        save_wallets(wallets)

        # Save bet
        bets = load_bets()
        if username not in bets:
            bets[username] = []
        bets[username].append(bet)
        save_bets(bets)

        return jsonify({
            'success': True,
            'bet': bet,
            'new_balance': round(wallets[username]['balance'], 2)
        })
    except Exception as e:
        return jsonify({'error': str(e)}), 500


@app.route('/api/bets/<bet_id>/settle', methods=['POST'])
@auth_required
def settle_bet(bet_id):
    """Settle a bet with results"""
    try:
        username = request.user.get('username')
        data = request.get_json()

        bets = load_bets()
        user_bets = bets.get(username, [])

        # Find the bet
        bet_index = None
        for i, bet in enumerate(user_bets):
            if bet['id'] == bet_id:
                bet_index = i
                break

        if bet_index is None:
            return jsonify({'error': 'Bet not found'}), 404

        bet = user_bets[bet_index]

        if bet['status'] != 'pending':
            return jsonify({'error': 'Bet already settled'}), 400

        # Update match results from provided data
        match_results = data.get('results', {})  # {match_id: 'HOME'|'DRAW'|'AWAY'}

        matches_won = 0
        matches_lost = 0
        all_won = True

        for match in bet['matches']:
            match_id = match.get('id')
            actual_result = match_results.get(match_id)

            if actual_result:
                match['actual_result'] = actual_result
                if match['prediction'] == actual_result:
                    match['correct'] = True
                    matches_won += 1
                else:
                    match['correct'] = False
                    matches_lost += 1
                    all_won = False

        bet['matches_won'] = matches_won
        bet['matches_lost'] = matches_lost
        bet['settled_at'] = datetime.now().isoformat()

        # Update wallet
        wallets = load_wallets()

        if all_won and matches_won == len(bet['matches']):
            bet['status'] = 'won'
            bet['won_amount'] = bet['potential_win']
            wallets[username]['balance'] += bet['potential_win']
            wallets[username]['total_won'] += bet['potential_win']
            wallets[username]['bets_won'] += 1
        else:
            bet['status'] = 'lost'
            bet['won_amount'] = 0
            wallets[username]['total_lost'] += bet['stake']
            wallets[username]['bets_lost'] += 1

        save_wallets(wallets)

        user_bets[bet_index] = bet
        bets[username] = user_bets
        save_bets(bets)

        return jsonify({
            'success': True,
            'bet': bet,
            'new_balance': round(wallets[username]['balance'], 2)
        })
    except Exception as e:
        return jsonify({'error': str(e)}), 500


def normalize_team_name(name):
    """Normalize team name for fuzzy matching"""
    if not name:
        return ''
    # Lowercase and remove common prefixes/suffixes
    n = name.lower().strip()
    # Remove common prefixes
    prefixes = ['ac ', 'fc ', 'as ', 'ss ', 'sc ', 'rc ', 'rcd ', 'cd ', 'afc ', 'ssc ', 'us ', 'og ', 'vfl ', 'vfb ', '1.fc ', 'tsg ', 'bsc ', 'sv ', 'rb ', 'sc ', 'fk ', 'sk ']
    for prefix in prefixes:
        if n.startswith(prefix):
            n = n[len(prefix):]
    # Remove common suffixes
    suffixes = [' fc', ' cf', ' sc', ' united', ' city']
    for suffix in suffixes:
        if n.endswith(suffix):
            n = n[:-len(suffix)]
    # Normalize special characters
    n = n.replace("'", '').replace('-', ' ').replace('.', ' ')
    # Collapse multiple spaces
    n = ' '.join(n.split())
    return n

def teams_match(team1, team2):
    """Check if two team names match (fuzzy)"""
    if not team1 or not team2:
        return False
    n1 = normalize_team_name(team1)
    n2 = normalize_team_name(team2)
    # Exact match after normalization
    if n1 == n2:
        return True
    # One contains the other (for abbreviations like "Paris SG" vs "Paris")
    if n1 in n2 or n2 in n1:
        return True
    # First word match (for teams like "Inter" vs "Inter Milan")
    w1 = n1.split()[0] if n1 else ''
    w2 = n2.split()[0] if n2 else ''
    if len(w1) >= 4 and len(w2) >= 4 and (w1 == w2 or w1.startswith(w2) or w2.startswith(w1)):
        return True
    return False

def find_match_result(home_team, away_team, match_date, results_list):
    """Find match result using fuzzy matching"""
    for result in results_list:
        r_home = result.get('home_team', '')
        r_away = result.get('away_team', '')
        r_date = result.get('date', '')
        # Date must match exactly
        if r_date != match_date:
            continue
        # Fuzzy match teams
        if teams_match(home_team, r_home) and teams_match(away_team, r_away):
            return result.get('actual')
    return None

@app.route('/api/bets/auto-settle', methods=['POST'])
@auth_required
def auto_settle_bets():
    """Auto-settle bets based on verification results with fuzzy team matching"""
    try:
        username = request.user.get('username')

        # Load verification results
        verification_path = os.path.join(DATA_DIR, 'verification_results.json')
        if not os.path.exists(verification_path):
            return jsonify({'error': 'No verification results available'}), 404

        with open(verification_path) as f:
            verification_data = json.load(f)

        results_list = verification_data.get('results', [])

        bets = load_bets()
        user_bets = bets.get(username, [])
        wallets = load_wallets()

        settled_count = 0
        debug_info = []

        for bet in user_bets:
            if bet['status'] != 'pending':
                continue

            all_matches_have_results = True
            all_won = True
            matches_won = 0
            matches_lost = 0

            for match in bet['matches']:
                home = match.get('home_team', '')
                away = match.get('away_team', '')
                date = match.get('date', '')

                # Use fuzzy matching to find result
                actual = find_match_result(home, away, date, results_list)

                if actual:
                    match['actual_result'] = actual
                    if match['prediction'] == actual:
                        match['correct'] = True
                        matches_won += 1
                    else:
                        match['correct'] = False
                        matches_lost += 1
                        all_won = False
                    debug_info.append(f"FOUND: {home} vs {away} ({date}) -> {actual}")
                else:
                    all_matches_have_results = False
                    debug_info.append(f"NOT FOUND: {home} vs {away} ({date})")

            if all_matches_have_results and len(bet['matches']) > 0:
                bet['matches_won'] = matches_won
                bet['matches_lost'] = matches_lost
                bet['settled_at'] = datetime.now().isoformat()

                if all_won:
                    bet['status'] = 'won'
                    bet['won_amount'] = bet['potential_win']
                    wallets[username]['balance'] += bet['potential_win']
                    wallets[username]['total_won'] += bet['potential_win']
                    wallets[username]['bets_won'] += 1
                else:
                    bet['status'] = 'lost'
                    bet['won_amount'] = 0
                    wallets[username]['total_lost'] += bet['stake']
                    wallets[username]['bets_lost'] += 1

                settled_count += 1

        save_wallets(wallets)
        bets[username] = user_bets
        save_bets(bets)

        return jsonify({
            'success': True,
            'settled_count': settled_count,
            'new_balance': round(wallets[username]['balance'], 2),
            'debug': debug_info[:20]  # First 20 debug messages
        })
    except Exception as e:
        return jsonify({'error': str(e)}), 500


@app.route('/api/leaderboard', methods=['GET'])
def get_leaderboard():
    """Get leaderboard of all users"""
    try:
        wallets = load_wallets()

        leaderboard = []
        for username, wallet in wallets.items():
            profit_loss = wallet['total_won'] - wallet['total_lost']
            roi = (profit_loss / wallet['total_wagered'] * 100) if wallet['total_wagered'] > 0 else 0
            win_rate = (wallet['bets_won'] / wallet['bets_placed'] * 100) if wallet['bets_placed'] > 0 else 0

            leaderboard.append({
                'username': username,
                'balance': round(wallet['balance'], 2),
                'profit_loss': round(profit_loss, 2),
                'roi': round(roi, 1),
                'bets_placed': wallet['bets_placed'],
                'bets_won': wallet['bets_won'],
                'win_rate': round(win_rate, 1)
            })

        # Sort by profit_loss descending
        leaderboard.sort(key=lambda x: x['profit_loss'], reverse=True)

        # Add rank
        for i, entry in enumerate(leaderboard):
            entry['rank'] = i + 1

        return jsonify({
            'leaderboard': leaderboard[:50],  # Top 50
            'total_users': len(leaderboard)
        })
    except Exception as e:
        return jsonify({'error': str(e)}), 500


# === MAIN ===

if __name__ == '__main__':
    print("Loading model...")
    load_model()
    print("Starting API server on port 3098...")
    app.run(host='0.0.0.0', port=3098, debug=False)
