import sys
import traceback
"""
Beredskaqet Gaming API - Flask version (WSGI compatible for Namecheap)
"""

from flask import Flask, request, jsonify, redirect
from functools import lru_cache
from datetime import datetime
import requests
import os
from dotenv import load_dotenv
from auth import create_access_token, verify_token, get_steam_profile, authenticate_demo

load_dotenv()

app = Flask(__name__)

# Config
AIRTABLE_BASE_ID = "appZh8kPulBOY571R"
AIRTABLE_PAT = os.getenv("AIRTABLE_PAT") or os.getenv("AIRTABLE_API_KEY", "")
AIRTABLE_BASE_URL = f"https://api.airtable.com/v0/{AIRTABLE_BASE_ID}"

# CORS headers
@app.after_request
def add_cors_headers(response):
    response.headers['Access-Control-Allow-Origin'] = '*'
    response.headers['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
    response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
    return response

@app.before_request
def handle_preflight():
    if request.method == 'OPTIONS':
        return '', 200

# E1: Airtable API Wrapper with Cache
@lru_cache(maxsize=128)
def fetch_from_airtable(table_name: str, filter_formula=None):
    """Fetch data from Airtable with caching"""
    headers = {
        "Authorization": f"Bearer {AIRTABLE_PAT}",
        "Content-Type": "application/json",
    }

    url = f"{AIRTABLE_BASE_URL}/{table_name}"
    params = {}
    if filter_formula:
        params["filterByFormula"] = filter_formula

    try:
        response = requests.get(url, headers=headers, params=params, timeout=10)
        response.raise_for_status()
        return response.json().get("records", [])
    except requests.RequestException as e:
        import traceback
        traceback.print_exc()
        return []

# Health check (handle both /health and /api/health)
@app.route('/health', methods=['GET'])
@app.route('/api/health', methods=['GET'])
def health_check():
    return jsonify({"status": "healthy", "timestamp": datetime.now().isoformat()})

# F1: Steam Login (handle both paths)
@app.route('/auth/login', methods=['POST'])
@app.route('/api/auth/login', methods=['POST'])
def login():
    data = request.get_json()
    steam_id = data.get('steam_id')

    token = authenticate_demo(steam_id)
    if not token:
        return jsonify({"detail": "Invalid Steam ID"}), 401

    from auth import DEMO_USERS
    player_name = DEMO_USERS.get(steam_id, "Player")
    profile = get_steam_profile(steam_id)
    if profile:
        player_name = profile["player_name"]

    return jsonify({
        "access_token": token,
        "player_name": player_name,
        "avatar": profile["avatar"] if profile else None,
    })

# F2: Verify token
@app.route('/auth/verify', methods=['POST'])
@app.route('/api/auth/verify', methods=['POST'])
def verify():
    data = request.get_json()
    token = data.get('steam_id')
    payload = verify_token(token)

    if not payload:
        return jsonify({"detail": "Token expired or invalid"}), 401

    return jsonify({
        "valid": True,
        "steam_id": payload.get("steam_id"),
        "player_name": payload.get("player_name"),
        "expires_at": payload.get("exp"),
    })

# F2: Logout
@app.route('/auth/logout', methods=['POST'])
@app.route('/api/auth/logout', methods=['POST'])
def logout():
    from auth import logout_user
    data = request.get_json()
    logout_user(data.get('token', ''))
    return jsonify({"status": "logged_out"})

# Get player stats
@app.route('/player/<player_name>', methods=['GET'])
@app.route('/api/player/<player_name>', methods=['GET'])
def get_player_stats(player_name):
    records = fetch_from_airtable("Input%20Data", f"{{Spiller}}='{player_name}'")

    if not records:
        return jsonify({"detail": "Player not found"}), 404

    stats = [r["fields"] for r in records]
    return jsonify({
        "player_name": player_name,
        "total_matches": len(stats),
        "recent_matches": stats[:10],
        "avg_kills": sum(s.get("Kills", 0) for s in stats) / len(stats) if stats else 0,
        "avg_kd": sum(s.get("Kills", 0) / (s.get("Death", 1) + 1) for s in stats) / len(stats) if stats else 0,
    })

# Leaderboard
@app.route('/leaderboard', methods=['GET'])
@app.route('/api/leaderboard', methods=['GET'])
def get_leaderboard():
    limit = request.args.get('limit', 50, type=int)
    records = fetch_from_airtable("LeaderBoard", None)

    leaderboard = [
        {
            "rank": idx + 1,
            "player": r["fields"].get("Spiller"),
            "score": r["fields"].get("Endelig Score", 0),
            "matches": r["fields"].get("Antal kampe", 0),
        }
        for idx, r in enumerate(records[:limit])
    ]

    return jsonify({"leaderboard": leaderboard, "timestamp": datetime.now().isoformat()})

# Progression
@app.route('/player/<player_name>/progression', methods=['GET'])
@app.route('/api/player/<player_name>/progression', methods=['GET'])
def get_progression(player_name):
    records = fetch_from_airtable("Input%20Data", f"{{Spiller}}='{player_name}'")

    if not records:
        return jsonify({"detail": "Player not found"}), 404

    stats = [r["fields"] for r in records]
    progression = [
        {
            "match": idx + 1,
            "kills": s.get("Kills", 0),
            "kd": s.get("Kills", 0) / (s.get("Death", 1) + 1),
            "hs_pct": s.get("HS%", 0),
            "adr": s.get("ADR", 0),
            "date": s.get("DATO", ""),
        }
        for idx, s in enumerate(stats)
    ]

    return jsonify({"progression": progression, "player": player_name})

# Head-to-Head
@app.route('/player/<player_name>/h2h', methods=['GET'])
@app.route('/api/player/<player_name>/h2h', methods=['GET'])
def get_h2h(player_name):
    records = fetch_from_airtable("Head_to_Head", f"{{Player1}}='{player_name}'")

    h2h_data = [
        {
            "opponent": r["fields"].get("Player2"),
            "record": r["fields"].get("Record", "0-0"),
            "win_rate": r["fields"].get("Win_Rate_P1", 0),
        }
        for r in records
    ]

    return jsonify({"h2h": h2h_data, "player": player_name})

# Achievements
@app.route('/player/<player_name>/achievements', methods=['GET'])
@app.route('/api/player/<player_name>/achievements', methods=['GET'])
def get_achievements(player_name):
    records = fetch_from_airtable("Achievements", f"{{Player_Name}}='{player_name}'")

    badges = [r["fields"].get("Badge_Type") for r in records]

    return jsonify({"badges": badges, "player": player_name, "total": len(badges)})

# Fun facts
@app.route('/fun-facts', methods=['GET'])
@app.route('/api/fun-facts', methods=['GET'])
def get_fun_facts():
    limit = request.args.get('limit', 10, type=int)
    records = fetch_from_airtable("Input%20Data", None)

    facts = [
        {
            "player": r["fields"].get("Spiller"),
            "fact": r["fields"].get("Fun_Facts", ""),
            "date": r["fields"].get("DATO", ""),
        }
        for r in records[:limit]
        if r["fields"].get("Fun_Facts")
    ]

    return jsonify({"fun_facts": facts})

# Notifications
@app.route('/notifications/<player_name>', methods=['GET'])
@app.route('/api/notifications/<player_name>', methods=['GET'])
def get_notifications(player_name):
    return jsonify({
        "player": player_name,
        "notifications": [
            {"type": "badge_unlocked", "message": "You unlocked CARRY badge!", "date": datetime.now().isoformat()},
        ],
    })

# Weekly stats
@app.route('/stats/weekly', methods=['GET'])
@app.route('/api/stats/weekly', methods=['GET'])
def get_weekly_stats():
    records = fetch_from_airtable("LeaderBoard", None)

    stats = [
        {
            "player": r["fields"].get("Spiller"),
            "score": r["fields"].get("Endelig Score", 0),
        }
        for r in records
    ]

    return jsonify({
        "period": "weekly",
        "stats": sorted(stats, key=lambda x: x["score"], reverse=True)[:20],
        "generated": datetime.now().isoformat(),
    })

# Steam OAuth Login
@app.route('/auth/steam/login', methods=['GET'])
@app.route('/api/auth/steam/login', methods=['GET'])
@app.route('/api-server/auth/steam/login', methods=['GET'])
def steam_login():
    """Redirect to Steam OpenID login"""
    import sys
    import urllib.parse
    
    discord_id = request.args.get('discord_id', '')
    guild_id = request.args.get('guild_id', '')
    state_param = request.args.get('state', '')

    if state_param and not discord_id:
        parts = state_param.split('_')
        discord_id = parts[0] if len(parts) > 0 else ''
        guild_id = parts[1] if len(parts) > 1 else ''

    if not discord_id and request.referrer:
        parsed_url = urllib.parse.urlparse(request.referrer)
        query_params = urllib.parse.parse_qs(parsed_url.query)
        if 'discord_id' in query_params:
            discord_id = query_params['discord_id'][0]
        elif 'state' in query_params:
            parts = query_params['state'][0].split('_')
            discord_id = parts[0] if len(parts) > 0 else ''
            guild_id = parts[1] if len(parts) > 1 else ''

    if not discord_id:
        print(f"[STEAM_LOGIN WARNING] discord_id is empty. args: {dict(request.args)}, referrer: {request.referrer}", file=sys.stderr)

    # Steam OpenID endpoint
    steam_openid_url = "https://steamcommunity.com/openid/login"

    # Combine discord_id + guild_id into single state param
    state = f"{discord_id}_{guild_id}" if guild_id else discord_id
    return_to = f"https://godkendelse.beredskaqet.dk/auth/steam/callback?state={state}"

    params = {
        "openid.ns": "http://specs.openid.net/auth/2.0",
        "openid.identity": "http://specs.openid.net/auth/2.0/identifier_select",
        "openid.claimed_id": "http://specs.openid.net/auth/2.0/identifier_select",
        "openid.mode": "checkid_setup",
        "openid.return_to": return_to,
        "openid.realm": "https://godkendelse.beredskaqet.dk",
    }

    query_string = "&".join([f"{k}={v}" for k, v in params.items()])
    redirect_url = f"{steam_openid_url}?{query_string}"

    return redirect(redirect_url)

# Steam OAuth Callback
@app.route('/auth/steam/callback', methods=['GET'])
@app.route('/api/auth/steam/callback', methods=['GET'])
@app.route('/api-server/auth/steam/callback', methods=['GET'])
def steam_callback():
    import sys
    """Handle Steam OpenID callback"""
    from urllib.parse import urlencode

    # Extract and parse state parameter (format: discord_id_guild_id)
    state = request.args.get('state', '')
    state_parts = state.split('_') if state else []
    discord_id = state_parts[0] if len(state_parts) > 0 else ''
    guild_id = state_parts[1] if len(state_parts) > 1 else ''
    
    print(f"[STEAM_CALLBACK ENTRY] request.args: {dict(request.args)}", file=sys.stderr)
    print(f"[STEAM_CALLBACK ENTRY] state: {state} | discord_id: {discord_id} | guild_id: {guild_id}", file=sys.stderr)

    if not discord_id:
        print(f"[STEAM_CALLBACK ERROR] discord_id missing from state '{state}'. Attempting Airtable DogTags fallback...", file=sys.stderr)
        try:
            records = fetch_from_airtable("DogTags", None)
            if records:
                sorted_records = sorted(records, key=lambda r: r.get('createdTime', ''), reverse=True)
                if sorted_records:
                    latest = sorted_records[0]
                    discord_id = latest.get('fields', {}).get('Discord_ID', '')
                    print(f"[STEAM_CALLBACK FALLBACK] Recovered discord_id {discord_id} from latest DogTags record", file=sys.stderr)
        except Exception as e:
            import traceback
            traceback.print_exc(file=sys.stderr)

    if not discord_id:
        print(f"[STEAM_CALLBACK FATAL] Could not determine discord_id from state or Airtable fallback.", file=sys.stderr)

    # Verify OpenID response
    if request.args.get('openid.mode') != 'id_res':
        return jsonify({"error": "OpenID response validation failed"}), 400

    # Get Steam ID from OpenID response
    identity = request.args.get('openid.claimed_id', '')
    try:
        steam_id = identity.split('/')[-1]
        print(f"[STEAM_CALLBACK EXTRACT] steam_id: {steam_id} | discord_id: {discord_id}", file=sys.stderr)
    except:
        return jsonify({"error": "Could not extract Steam ID"}), 400

    # Verify OpenID signature with Steam
    verify_params = {}

    for key, value in request.args.items():
        if key.startswith('openid.'):
            verify_params[key] = value

    verify_params['openid.mode'] = 'check_authentication'

    try:
        verify_response = requests.post(
            "https://steamcommunity.com/openid/login",
            data=verify_params,
            timeout=10
        )

        if 'is_valid:true' not in verify_response.text:
            print(f"[DEBUG] Steam verify failed. Response: {verify_response.text[:100]}")
            return jsonify({"error": "Steam OpenID signature verification failed"}), 400
    except Exception as e:
        print(f"[DEBUG] OpenID verification error: {str(e)}")
        return jsonify({"error": f"OpenID verification error: {str(e)}"}), 500

    # Get Steam profile
    steam_profile = get_steam_profile(steam_id)
    player_name = steam_profile['player_name'] if steam_profile else f"Steam:{steam_id[-6:]}"

    # Create JWT token
    token = create_access_token(steam_id, player_name)

    # Save Steam_ID to Airtable DogTags
    if AIRTABLE_PAT and discord_id:
        try:
            search_url = f"{AIRTABLE_BASE_URL}/DogTags"
            search_params = {"filterByFormula": f'{{Discord_ID}}="{discord_id}"'}
            search_headers = {"Authorization": f"Bearer {AIRTABLE_PAT}"}
            search_res = requests.get(search_url, headers=search_headers, params=search_params, timeout=5)
            search_data = search_res.json()
            records = search_data.get("records", [])

            if records:
                rec_id = records[0]["id"]
                requests.patch(
                    f"{AIRTABLE_BASE_URL}/DogTags/{rec_id}",
                    headers={**search_headers, "Content-Type": "application/json"},
                    json={"fields": {"Steam_ID": steam_id}},
                    timeout=5
                )
                print(f"[Airtable] Updated Steam_ID for {discord_id}")
            else:
                requests.post(
                    f"{AIRTABLE_BASE_URL}/DogTags",
                    headers={**search_headers, "Content-Type": "application/json"},
                    json={"records": [{"fields": {
                        "Discord_ID": discord_id,
                        "Steam_ID": steam_id
                    }}]},
                    timeout=5
                )
                print(f"[Airtable] Created Steam_ID record for {discord_id}")
        except Exception as e:
            import traceback
            traceback.print_exc()
            print(f"[Airtable] Save error: {str(e)}")

   # Giv Steam_Verified rolle direkte via Discord API
    guild_id = "1472346100223574151"
    role_id = os.getenv('DISCORD_VERIFIED_ROLE_ID', '1553266951432704020')
    bot_token = os.getenv('DISCORD_BEREDSKAQET_TOKEN', '').strip()

    if role_id and bot_token and discord_id:
        try:
            role_url = f"https://discord.com/api/v10/guilds/{guild_id}/members/{discord_id}/roles/{role_id}"
            role_headers = {
                "Authorization": f"Bot {bot_token}",
                "Content-Type": "application/json"
            }
            role_res = requests.put(role_url, headers=role_headers, timeout=5)
            print(f"[Discord Role] Assigned Steam_Verified to {discord_id}: {role_res.status_code}", file=sys.stderr)
        except Exception as e:
            print(f"[Discord Role] Error assigning role: {str(e)}", file=sys.stderr)

    # Redirect directly to Discord channel
    discord_channel_url = "https://discord.com/channels/1472346100223574151/1553295479947927632"
    return redirect(discord_channel_url)

# Discord OAuth Callback
@app.route('/auth/discord/callback', methods=['GET'])
@app.route('/api/auth/discord/callback', methods=['GET'])
def discord_callback():
    """Handle Discord OAuth callback, pair with steam_id from state, and assign role"""
    code = request.args.get('code')
    steam_id = request.args.get('state')

    if not code or not steam_id:
        return "Fejl: Manglende autorisation eller Steam ID i state.", 400

    client_id = os.getenv('DISCORD_APP_ID', '1433018536908951582')
    client_secret = os.getenv('DISCORD_OAUTH_CLIENT_SECRET', '')
    redirect_uri = 'https://godkendelse.beredskaqet.dk/auth/discord/callback'

    token_url = "https://discord.com/api/oauth2/token"
    data = {
        "client_id": client_id,
        "client_secret": client_secret,
        "grant_type": "authorization_code",
        "code": code,
        "redirect_uri": redirect_uri
    }
    headers = {"Content-Type": "application/x-www-form-urlencoded"}

    try:
        token_res = requests.post(token_url, data=data, headers=headers, timeout=10)
        token_data = token_res.json()
        access_token = token_data.get("access_token")
        if not access_token:
            return f"Fejl ved Discord tokenveksling: {token_data}", 400

        user_res = requests.get("https://discord.com/api/users/@me", headers={"Authorization": f"Bearer {access_token}"}, timeout=10)
        user_data = user_res.json()
        discord_id = user_data.get("id")
        discord_username = user_data.get("username")

        if not discord_id:
            return "Fejl: Kunne ikke hente Discord bruger-ID.", 400

        guild_id = "1472346100223574151"
        role_id = os.getenv('DISCORD_VERIFIED_ROLE_ID', '1553266951432704020')
        bot_token = os.getenv('DISCORD_BEREDSKAQET_TOKEN', '').strip()

        if role_id and bot_token and discord_id:
            role_url = f"https://discord.com/api/v10/guilds/{guild_id}/members/{discord_id}/roles/{role_id}"
            role_headers = {
                "Authorization": f"Bot {bot_token}",
                "Content-Type": "application/json"
            }
            requests.put(role_url, headers=role_headers, timeout=5)

        discord_channel_url = "https://discord.com/channels/1472346100223574151/1553295479947927632"
        return redirect(discord_channel_url)

    except Exception as e:
        return f"Der opstod en fejl under Discord OAuth: {str(e)}", 500

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8000, debug=False)