"""
Strategy Generator — Senin Excel mantığını DB üzerinde otomatize eder.

Mantık:
1. Ev sahibi takım X, evinde oran bandı Y'de oynadığında → OU1.5/OU2.5/BTTS oranları
2. Deplasman takım Z, deplasmanda oran bandı W'de oynadığında → OU1.5/OU2.5/BTTS oranları
3. İkisi de yüksekse → STRATEJİ ÜRET

Çıktı: Her maç için hangi bahis oynanabilir, neden, ve geçmiş başarı oranı
"""
import psycopg2
import pandas as pd
import numpy as np
from collections import defaultdict
from datetime import datetime

# DB connection
conn = psycopg2.connect(
    host="localhost",
    port=15432,
    dbname="boilerplate_db",
    user="suggestbet",
    password="SuGGesT2026SecuRe"
)

print("=" * 70)
print("  STRATEGY GENERATOR — Veritabanından Strateji Üretimi")
print("=" * 70)

# 1. Tüm biten maçları, takım adları ve MS oranlarıyla çek
query = """
SELECT 
    m.id as match_id,
    m.home_team_id,
    m.away_team_id,
    m.league_id,
    m.score_home,
    m.score_away,
    m.mst_utc,
    ht.name as home_team,
    at.name as away_team,
    l.name as league_name
FROM matches m
JOIN teams ht ON m.home_team_id = ht.id
JOIN teams at ON m.away_team_id = at.id
JOIN leagues l ON m.league_id = l.id
WHERE m.status = 'FT' 
AND m.score_home IS NOT NULL
ORDER BY m.mst_utc ASC
"""
df = pd.read_sql(query, conn)
print(f"\nToplam biten maç: {len(df):,}")

# 2. Tüm oranları çek (MS, OU25, BTTS, OU15)
odds_query = """
SELECT 
    oc.match_id,
    oc.name as market,
    os.name as selection,
    CAST(os.odd_value AS DECIMAL) as odds
FROM odd_categories oc
JOIN odd_selections os ON os.odd_category_db_id = oc.db_id
WHERE oc.name IN (
    'Maç Sonucu', 
    '2,5 Alt/Üst', 
    '1,5 Alt/Üst',
    '3,5 Alt/Üst',
    'Karşılıklı Gol'
)
"""
odds_df = pd.read_sql(odds_query, conn)
print(f"Toplam oran kaydı: {len(odds_df):,}")

# Pivot: her maç için oranları sütunlara çevir
def get_odds(match_id, market, selection):
    mask = (odds_df.match_id == match_id) & (odds_df.market == market) & (odds_df.selection == selection)
    vals = odds_df.loc[mask, 'odds']
    return float(vals.iloc[0]) if len(vals) > 0 else None

# Daha verimli: oran lookup dict oluştur
print("Oran lookup oluşturuluyor...")
odds_lookup = {}
for _, row in odds_df.iterrows():
    key = (row.match_id, row.market, row.selection)
    odds_lookup[key] = float(row.odds)

def get_o(mid, market, sel):
    return odds_lookup.get((mid, market, sel))

# 3. Her maça oranları ekle
print("Maçlara oranlar ekleniyor...")
df['odds_ms_h'] = df.match_id.map(lambda x: get_o(x, 'Maç Sonucu', '1'))
df['odds_ms_a'] = df.match_id.map(lambda x: get_o(x, 'Maç Sonucu', '2'))
df['odds_ms_d'] = df.match_id.map(lambda x: get_o(x, 'Maç Sonucu', '0'))
df['odds_ou25_o'] = df.match_id.map(lambda x: get_o(x, '2,5 Alt/Üst', 'Üst'))
df['odds_ou25_u'] = df.match_id.map(lambda x: get_o(x, '2,5 Alt/Üst', 'Alt'))
df['odds_ou15_o'] = df.match_id.map(lambda x: get_o(x, '1,5 Alt/Üst', 'Üst'))
df['odds_ou15_u'] = df.match_id.map(lambda x: get_o(x, '1,5 Alt/Üst', 'Alt'))
df['odds_ou35_o'] = df.match_id.map(lambda x: get_o(x, '3,5 Alt/Üst', 'Üst'))
df['odds_ou35_u'] = df.match_id.map(lambda x: get_o(x, '3,5 Alt/Üst', 'Alt'))
df['odds_btts_y'] = df.match_id.map(lambda x: get_o(x, 'Karşılıklı Gol', 'Var'))
df['odds_btts_n'] = df.match_id.map(lambda x: get_o(x, 'Karşılıklı Gol', 'Yok'))

# Sonuç hesapla
df['total_goals'] = df.score_home + df.score_away
df['ou15'] = (df.total_goals > 1).astype(int)
df['ou25'] = (df.total_goals > 2).astype(int)
df['ou35'] = (df.total_goals > 3).astype(int)
df['btts'] = ((df.score_home > 0) & (df.score_away > 0)).astype(int)

print(f"Oranı olan maç sayısı: {df.odds_ms_h.notna().sum():,}")

# 4. ORAN BANDI fonksiyonu
def odds_band(odds):
    if pd.isna(odds): return None
    if odds < 1.30: return '1.00-1.30'
    if odds < 1.50: return '1.30-1.50'
    if odds < 1.80: return '1.50-1.80'
    if odds < 2.20: return '1.80-2.20'
    if odds < 2.80: return '2.20-2.80'
    if odds < 4.00: return '2.80-4.00'
    if odds < 6.00: return '4.00-6.00'
    return '6.00+'

# 5. STRATEJİ: Expanding window — sadece geçmiş veriye bakarak tahmin
print("\n" + "=" * 70)
print("  STRATEJİ BACKTEST — Expanding Window")
print("=" * 70)

# Ev sahibi geçmişi: {team_id: {odds_band: [ou15, ou25, btts, ou35, ...]}}
home_history = defaultdict(lambda: defaultdict(list))
away_history = defaultdict(lambda: defaultdict(list))

MIN_MATCHES = 8  # Minimum geçmiş maç sayısı
TEST_PCT = 0.30  # Son %30 test
N = len(df)
test_start = int(N * (1 - TEST_PCT))

results = {
    'ou15_over': [], 'ou25_over': [], 'ou35_over': [],
    'btts_yes': [], 'btts_no': [],
    'ou25_under': [], 'ou15_under': [],
    'ms_home': []
}

for i in range(N):
    row = df.iloc[i]
    h_odds = row.odds_ms_h
    a_odds = row.odds_ms_a
    
    if pd.isna(h_odds) or pd.isna(a_odds):
        continue
    
    h_band = odds_band(h_odds)
    a_band = odds_band(a_odds)
    
    # TEST: sadece test bölümünde bahis yap
    if i >= test_start:
        h_hist = home_history[row.home_team_id][h_band]
        a_hist = away_history[row.away_team_id][a_band]
        
        if len(h_hist) >= MIN_MATCHES and len(a_hist) >= MIN_MATCHES:
            # Ev sahibi bu oran bandında ne yapmış?
            h_ou15 = np.mean([x[0] for x in h_hist])
            h_ou25 = np.mean([x[1] for x in h_hist])
            h_ou35 = np.mean([x[2] for x in h_hist])
            h_btts = np.mean([x[3] for x in h_hist])
            h_win  = np.mean([x[4] for x in h_hist])
            
            # Deplasman bu oran bandında ne yapmış?
            a_ou15 = np.mean([x[0] for x in a_hist])
            a_ou25 = np.mean([x[1] for x in a_hist])
            a_ou35 = np.mean([x[2] for x in a_hist])
            a_btts = np.mean([x[3] for x in a_hist])
            a_loss = np.mean([x[4] for x in a_hist])  # deplasman kaybetme oranı
            
            # KOMBİNE SİNYAL
            sig_ou15 = (h_ou15 + a_ou15) / 2
            sig_ou25 = (h_ou25 + a_ou25) / 2
            sig_ou35 = (h_ou35 + a_ou35) / 2
            sig_btts = (h_btts + a_btts) / 2
            sig_hw = (h_win + a_loss) / 2  # ev kazanma + deplasman kaybetme
            
            base = {
                'match': f"{row.home_team} vs {row.away_team}",
                'league': row.league_name,
                'home_team': row.home_team,
                'away_team': row.away_team,
                'h_band': h_band,
                'a_band': a_band,
                'h_n': len(h_hist),
                'a_n': len(a_hist),
            }
            
            # OU 1.5 OVER
            if sig_ou15 >= 0.85 and row.odds_ou15_o and row.odds_ou15_o > 1.01:
                results['ou15_over'].append({
                    **base, 'signal': sig_ou15, 'odds': row.odds_ou15_o,
                    'won': row.ou15 == 1, 'actual_goals': row.total_goals,
                    'h_sig': h_ou15, 'a_sig': a_ou15
                })
            
            # OU 2.5 OVER
            if sig_ou25 >= 0.70 and row.odds_ou25_o and row.odds_ou25_o > 1.10:
                results['ou25_over'].append({
                    **base, 'signal': sig_ou25, 'odds': row.odds_ou25_o,
                    'won': row.ou25 == 1, 'actual_goals': row.total_goals,
                    'h_sig': h_ou25, 'a_sig': a_ou25
                })
            
            # OU 3.5 OVER
            if sig_ou35 >= 0.60 and row.odds_ou35_o and row.odds_ou35_o > 1.20:
                results['ou35_over'].append({
                    **base, 'signal': sig_ou35, 'odds': row.odds_ou35_o,
                    'won': row.ou35 == 1, 'actual_goals': row.total_goals,
                    'h_sig': h_ou35, 'a_sig': a_ou35
                })
            
            # BTTS YES
            if sig_btts >= 0.70 and row.odds_btts_y and row.odds_btts_y > 1.10:
                results['btts_yes'].append({
                    **base, 'signal': sig_btts, 'odds': row.odds_btts_y,
                    'won': row.btts == 1, 'actual_goals': row.total_goals,
                    'h_sig': h_btts, 'a_sig': a_btts
                })
            
            # OU 2.5 UNDER (düşük gol beklentisi)
            if sig_ou25 <= 0.30 and row.odds_ou25_u and row.odds_ou25_u > 1.10:
                results['ou25_under'].append({
                    **base, 'signal': 1-sig_ou25, 'odds': row.odds_ou25_u,
                    'won': row.ou25 == 0, 'actual_goals': row.total_goals,
                    'h_sig': 1-h_ou25, 'a_sig': 1-a_ou25
                })
            
            # MS HOME WIN (ev sahibi kazanma)
            if sig_hw >= 0.75 and row.odds_ms_h and 1.10 < row.odds_ms_h < 3.50:
                results['ms_home'].append({
                    **base, 'signal': sig_hw, 'odds': row.odds_ms_h,
                    'won': row.score_home > row.score_away,
                    'actual_goals': row.total_goals,
                    'h_sig': h_win, 'a_sig': a_loss
                })
    
    # History güncelle (her zaman)
    home_history[row.home_team_id][h_band].append((
        row.ou15, row.ou25, row.ou35, row.btts,
        int(row.score_home > row.score_away)
    ))
    away_history[row.away_team_id][a_band].append((
        row.ou15, row.ou25, row.ou35, row.btts,
        int(row.score_away < row.score_home)  # deplasman kaybetme
    ))

# 6. SONUÇLARI YAZIDIR
print(f"\nTest bölümü: son {TEST_PCT*100:.0f}% ({N - test_start:,} maç)")
print(f"Minimum geçmiş: {MIN_MATCHES} maç\n")

for market_name, bets in results.items():
    if not bets:
        print(f"\n  {market_name}: sinyal yok")
        continue
    
    bdf = pd.DataFrame(bets)
    total = len(bdf)
    wins = bdf.won.sum()
    hit = wins / total * 100
    pnl = (bdf.won * (bdf.odds - 1) - (~bdf.won) * 1).sum()
    roi = pnl / total * 100
    avg_odds = bdf.odds.mean()
    
    print(f"\n{'='*60}")
    print(f"  {market_name.upper()}")
    print(f"{'='*60}")
    print(f"  Toplam bahis: {total}")
    print(f"  Kazanan: {wins} ({hit:.1f}%)")
    print(f"  Ortalama odds: {avg_odds:.2f}")
    print(f"  PnL: {pnl:+.1f} birim")
    print(f"  ROI: {roi:+.1f}%")
    
    # Farklı sinyal eşiklerinde performans
    print(f"\n  Sinyal eşik analizi:")
    for threshold in [0.70, 0.75, 0.80, 0.85, 0.90, 0.95]:
        sub = bdf[bdf.signal >= threshold]
        if len(sub) < 5: continue
        w = sub.won.sum()
        p = (sub.won * (sub.odds - 1) - (~sub.won) * 1).sum()
        r = p / len(sub) * 100
        star = ' ✅ PROFIT' if r > 0 else (' ⚖️  BE' if r > -3 else '')
        print(f"    ≥{threshold:.2f}: {len(sub):5d} bahis, hit={w/len(sub)*100:.1f}%, ROI={r:+.1f}%{star}")
    
    # En iyi 10 örnek (kazanan)
    if wins > 0:
        best = bdf[bdf.won].nlargest(min(5, wins), 'signal')
        print(f"\n  Örnek kazanan bahisler:")
        for _, b in best.iterrows():
            print(f"    {b.home_team} vs {b.away_team} ({b.league})")
            print(f"      Ev {b.h_band} ({b.h_sig:.0%}) + Dep {b.a_band} ({b.a_sig:.0%}) → sinyal={b.signal:.0%}, odds={b.odds:.2f}, gol={b.actual_goals:.0f}")

# 7. ÖZET TABLO
print("\n\n" + "=" * 70)
print("  ÖZET TABLO")
print("=" * 70)
print(f"{'Market':<15} {'Bahis':>6} {'Hit':>7} {'ROI':>8} {'Avg Odds':>9}")
print("-" * 50)
for market_name, bets in results.items():
    if not bets: continue
    bdf = pd.DataFrame(bets)
    total = len(bdf)
    wins = bdf.won.sum()
    hit = wins / total * 100
    pnl = (bdf.won * (bdf.odds - 1) - (~bdf.won) * 1).sum()
    roi = pnl / total * 100
    avg_odds = bdf.odds.mean()
    print(f"{market_name:<15} {total:>6} {hit:>6.1f}% {roi:>+7.1f}% {avg_odds:>8.2f}")

conn.close()
print("\n✅ Tamamlandı!")
