import requests
import urllib.parse
import os
from datetime import datetime

CLIENT_ID = "00000000402b5328"
REDIRECT_URI = "https://login.live.com/oauth20_desktop.srf"
TOKEN_FILE = "account.txt"

def load_existing_tokens():
    """Load existing tokens from account.txt"""
    if not os.path.exists(TOKEN_FILE):
        return []
    
    tokens = []
    try:
        with open(TOKEN_FILE, 'r') as f:
            for line in f:
                line = line.strip()
                if line and line.startswith("eyJ"):  # JWT tokens start with eyJ
                    tokens.append(line)
    except Exception as e:
        print(f"⚠️ Error reading token file: {e}")
    
    return tokens

def save_token(token):
    """Save new token to account.txt"""
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    
    try:
        with open(TOKEN_FILE, 'a') as f:
            f.write(f"# Added: {timestamp}\n")
            f.write(f"{token}\n")
        print(f"✅ Token saved to {TOKEN_FILE}")
    except Exception as e:
        print(f"❌ Error saving token: {e}")

def prompt_for_url():
    print("Open the following URL and log in:")
    url = (
        "https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize?"
        f"client_id={CLIENT_ID}"
        "&response_type=code"
        f"&redirect_uri={urllib.parse.quote(REDIRECT_URI)}"
        "&scope=XboxLive.signin%20offline_access"
    )
    print(url)
    print()
    return input("\nPaste the full URL after login (with ?code=...): ").strip()

def get_minecraft_token(auth_code):
    """Exchange auth code for Minecraft access token"""
    # Step 2: Exchange code for Microsoft access token
    token_resp = requests.post(
        "https://login.live.com/oauth20_token.srf",
        data={
            "client_id": CLIENT_ID,
            "redirect_uri": REDIRECT_URI,
            "grant_type": "authorization_code",
            "code": auth_code,
        },
    ).json()
    ms_token = token_resp.get("access_token")
    if not ms_token:
        print("❌ Failed to get Microsoft token:", token_resp)
        return None

    # Step 3: Authenticate with Xbox Live
    xbl = requests.post(
        "https://user.auth.xboxlive.com/user/authenticate",
        json={
            "Properties": {"AuthMethod": "RPS", "SiteName": "user.auth.xboxlive.com", "RpsTicket": f"d={ms_token}"},
            "RelyingParty": "http://auth.xboxlive.com",
            "TokenType": "JWT"
        },
    ).json()
    xbl_token = xbl.get("Token")
    if not xbl_token:
        print("❌ Failed to get Xbox Live token:", xbl)
        return None

    # Step 4: Authenticate with XSTS
    xsts = requests.post(
        "https://xsts.auth.xboxlive.com/xsts/authorize",
        json={"Properties": {"SandboxId": "RETAIL", "UserTokens": [xbl_token]}, "RelyingParty": "rp://api.minecraftservices.com/", "TokenType": "JWT"},
    ).json()
    
    user_hash = xsts.get("DisplayClaims", {}).get("xui", [{}])[0].get("uhs")
    xsts_token = xsts.get("Token")
    
    if not user_hash or not xsts_token:
        print("❌ Failed to get XSTS token:", xsts)
        return None

    # Step 5: Get Minecraft Access Token
    mc = requests.post(
        "https://api.minecraftservices.com/authentication/login_with_xbox",
        json={"identityToken": f"XBL3.0 x={user_hash};{xsts_token}"},
    ).json()

    return mc.get("access_token")

def main():
    print("=" * 60)
    print("Minecraft Token Generator & Manager")
    print("=" * 60)
    print()
    
    # Show existing tokens
    existing_tokens = load_existing_tokens()
    if existing_tokens:
        print(f"📋 Found {len(existing_tokens)} existing token(s) in {TOKEN_FILE}")
        for i, token in enumerate(existing_tokens, 1):
            print(f"   Token {i}: {token[:50]}...")
        print()
    
    # Prompt for new token
    print("Generate new token? (y/n)")
    choice = input("> ").strip().lower()
    
    if choice != 'y':
        print("❌ No new token generated.")
        return
    
    print()
    redirected = prompt_for_url()
    
    # Extract auth code
    params = urllib.parse.urlparse(redirected).query
    auth_code = urllib.parse.parse_qs(params).get("code", [None])[0]
    
    if not auth_code:
        print("❌ Invalid URL or missing code parameter.")
        return
    
    print("\n⏳ Exchanging code for Minecraft token...")
    
    # Get Minecraft token
    mc_token = get_minecraft_token(auth_code)
    
    if not mc_token:
        print("❌ Failed to get Minecraft access token.")
        return
    
    print("\n✅ Minecraft Access Token:")
    print(mc_token)
    
    # Save to file
    save_token(mc_token)
    
    print()
    print("=" * 60)
    print(f"🎉 Success! Total tokens in {TOKEN_FILE}: {len(existing_tokens) + 1}")
    print("=" * 60)

if __name__ == "__main__":
    main()
