import logging
import sys
import os
import json
from datetime import datetime

sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))

from flask import Flask, render_template, jsonify, request
from apscheduler.schedulers.background import BackgroundScheduler

from scrapers.sportybet import SportyBetScraper
from scrapers.msport import MSportScraper
from scrapers.betking import BetKingScraper
from scrapers.nairabet import NairaBetScraper
from scrapers.betway import BetwayScraper
from scrapers.bet9ja import Bet9jaScraper
from scrapers.oneXbet import OneXBetScraper
from scrapers.bcgame import BCGameScraper
from core.calculator import find_arb_opportunities, group_events_by_match, arb_margin
import config

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s [%(levelname)s] %(name)s: %(message)s',
    datefmt='%H:%M:%S',
)
logger = logging.getLogger(__name__)

app = Flask(__name__)
application = app
# ── Global state ──────────────────────────────────────────────────────────────
state = {
    'opportunities': [],
    'last_updated': None,
    'stats': {
        'total_events': 0,
        'opportunities': 0,
        'best_arb': 0.0,
        'bookmakers_online': 0,
    },
    'errors': [],
}

# All scraper instances (always initialised; toggled at runtime via enabled dict)
scrapers = {
    'SportyBet': SportyBetScraper(),
    'MSport':    MSportScraper(),
    'BetKing':   BetKingScraper(),
    'NairaBet':  NairaBetScraper(),
    'Betway':    BetwayScraper(),
    '1xBet':     OneXBetScraper(),
    'Bet9ja':    Bet9jaScraper(),
    'BCGame':    BCGameScraper(),
}

# ── Toggle state persistence ──────────────────────────────────────────────────
TOGGLES_FILE = os.path.join(os.path.dirname(__file__), '..', 'bookmakers_state.json')

def _load_toggles() -> dict:
    """Load persisted toggle state, falling back to config defaults."""
    defaults = {
        name: cfg.get('enabled', False)
        for cfg in config.BOOKMAKERS.values()
        for name in [cfg['name']]
        if name in scrapers
    }
    try:
        with open(TOGGLES_FILE) as f:
            saved = json.load(f)
        # Merge: saved values override defaults, new scrapers get their default
        return {name: saved.get(name, defaults[name]) for name in defaults}
    except (FileNotFoundError, json.JSONDecodeError):
        return defaults

def _save_toggles(state: dict) -> None:
    try:
        with open(TOGGLES_FILE, 'w') as f:
            json.dump(state, f, indent=2)
    except Exception as ex:
        logger.warning(f'Could not save toggle state: {ex}')

# Runtime enabled state — loaded from file (or config defaults on first run)
bookmakers_enabled = _load_toggles()


# ── Refresh logic ─────────────────────────────────────────────────────────────
def refresh_odds():
    logger.info("── Odds refresh started ──")
    events_by_bm = {}
    errors = []
    online = 0

    for name, scraper in scrapers.items():
        if not bookmakers_enabled.get(name, False):
            continue
        try:
            events = scraper.get_all_events()
            if events:
                events_by_bm[name] = events
                online += 1
        except Exception as ex:
            msg = f"{name}: {ex}"
            errors.append(msg)
            logger.error(msg)

    total_events = sum(len(v) for v in events_by_bm.values())
    opps = find_arb_opportunities(events_by_bm)

    state['opportunities'] = [o.to_dict() for o in opps]
    state['last_updated'] = datetime.now().strftime('%H:%M:%S')
    state['errors'] = errors
    state['stats'] = {
        'total_events':      total_events,
        'opportunities':     len(opps),
        'best_arb':          round(opps[0].arb_percentage, 2) if opps else 0.0,
        'bookmakers_online': online,
    }
    logger.info(f"── Done: {len(opps)} arb opportunities | {total_events} events ──")


# ── Routes ────────────────────────────────────────────────────────────────────
@app.route('/')
def dashboard():
    return render_template('dashboard.html', refresh_interval=config.REFRESH_INTERVAL)


@app.route('/api/opportunities')
def api_opportunities():
    sport_filter = request.args.get('sport', 'all')
    opps = state['opportunities']
    if sport_filter != 'all':
        opps = [o for o in opps if o['sport'] == sport_filter]
    return jsonify({
        'opportunities': opps,
        'last_updated':  state['last_updated'],
        'stats':         state['stats'],
        'errors':        state['errors'],
    })


@app.route('/api/bookmakers')
def api_bookmakers():
    return jsonify([
        {'name': name, 'enabled': bookmakers_enabled.get(name, False)}
        for name in scrapers
    ])


@app.route('/api/bookmakers/<name>/toggle', methods=['POST'])
def api_toggle_bookmaker(name):
    if name not in scrapers:
        return jsonify({'error': 'unknown bookmaker'}), 404
    bookmakers_enabled[name] = not bookmakers_enabled.get(name, False)
    _save_toggles(bookmakers_enabled)
    logger.info(f"[toggle] {name} → {'ON' if bookmakers_enabled[name] else 'OFF'}")
    return jsonify({'name': name, 'enabled': bookmakers_enabled[name]})


@app.route('/api/debug/near-misses')
def api_near_misses():
    """Show matched events sorted by how close they are to arbitrage (sum of inverse odds)."""
    all_events = [e for events in
                  {name: scraper.get_all_events()
                   for name, scraper in scrapers.items()
                   if bookmakers_enabled.get(name)}.values()
                  for e in events]
    groups = group_events_by_match(all_events)

    rows = []
    for match_key, events in groups.items():
        bm_set = {e.bookmaker for e in events}
        if len(bm_set) < 2:
            continue
        markets = {e.market for e in events}
        for market in markets:
            me = [e for e in events if e.market == market]
            if len({e.bookmaker for e in me}) < 2:
                continue
            outcome_names = {o.name for e in me for o in e.outcomes}
            best = {}
            for name in outcome_names:
                for event in me:
                    for outcome in event.outcomes:
                        if outcome.name == name:
                            if name not in best or outcome.odds > best[name].odds:
                                best[name] = outcome
            if len(best) != len(outcome_names):
                continue
            inv_sum = sum(1.0 / o.odds for o in best.values())
            ref = me[0]
            rows.append({
                'event': f"{ref.home_team} vs {ref.away_team}",
                'sport': ref.sport,
                'market': market,
                'bookmakers': list({e.bookmaker for e in me}),
                'inverse_sum': round(inv_sum, 4),
                'margin_pct': round((1 / inv_sum - 1) * 100, 3),
                'best_odds': {o.name: {'odds': o.odds, 'bm': o.bookmaker} for o in best.values()},
            })

    rows.sort(key=lambda x: x['inverse_sum'])
    return jsonify({'total_matched': len(rows), 'near_misses': rows[:50]})


@app.route('/api/refresh', methods=['POST'])
def api_refresh():
    refresh_odds()
    return jsonify({'status': 'ok', 'last_updated': state['last_updated']})


# ── Entry point ───────────────────────────────────────────────────────────────
if __name__ == '__main__':
    refresh_odds()

    scheduler = BackgroundScheduler(daemon=True)
    scheduler.add_job(refresh_odds, 'interval', seconds=config.REFRESH_INTERVAL)
    scheduler.start()

    logger.info("Dashboard running at http://localhost:5000")
    app.run(host='0.0.0.0', port=5000, debug=False)
