/*
AI ASSISTANT INTEGRATION GUIDE:
-----------------------------
To have the AI assistant automatically implement this API handler for your game:

1. Share your game's details with the AI:
   - Game name
   - Base URL (if different from default)
   - Any specific requirements for score tracking
   - Any special game states or events that need API integration

2. The AI will:
   - Replace "GAME_NAME" with your actual game name
   - Update the base URL if needed
   - Add any game-specific score tracking
   - Integrate with your game's existing code
   - Add necessary event listeners
   - Set up proper score submission points

3. The AI will also:
   - Check your game's code structure
   - Identify where to add API calls
   - Ensure proper initialization
   - Add necessary logging
   - Handle any game-specific edge cases

4. After implementation, the AI will:
   - Verify the integration
   - Test the score submission flow
   - Ensure proper error handling
   - Check for any conflicts with existing code

Example prompt for the AI:
"I need to implement the API handler for my game [GAME_NAME]. 
The game uses [FRAMEWORK/ENGINE] and tracks scores in [LOCATION].
Please help me integrate the API handler and ensure proper score submission."

The AI will then:
1. Analyze your game's code
2. Make necessary modifications
3. Add the API handler
4. Ensure everything works together
*/

// API Handler for Ninja Knife Pro
// -----------------------------------------
// HOW TO USE:
// 1. Include this file in your HTML before your main game script
// 2. The API handler will initialize automatically when the page loads
// 3. Call apiHandler.submitScoreIfNeeded(score, level) when the game ends or when score changes

class APIHandler {
    constructor(baseUrl = 'https://cgames.unlimitedgames.info/ninjaknifepro') {
        this.baseUrl = baseUrl; // Base URL without /api.php
        this.session_id = Date.now().toString();
        this.gameStartTime = Date.now(); // When the game session started - initialize immediately
        this.lastActivityTime = Date.now(); // Initialize with current time
        this.scoreSubmitted = false; // Flag to track if score has been submitted
        this.gameToken = null; // Will store the verified token

        // Clear any previous session data
        this.clearSessionData();
        
        // Start tracking activity immediately
        this.setupGlobalActivityTracking();
        
        // Set up session cleanup on page unload/reload
        window.addEventListener('beforeunload', () => {
            this.clearSessionData();
        });
        
        console.log('API Handler initialized with session_id:', this.session_id);
        console.log('Using base URL:', this.baseUrl);
    }

    // Generate a new token for the game session
    async generateToken() {
        console.log('Starting token generation...');
        
        // Check if we have a cached token
        const cachedToken = localStorage.getItem('gameToken');
        if (cachedToken) {
            console.log('Found cached token, validating...');
            const isValid = await this.validateToken(cachedToken).catch(() => false);
            
            if (isValid) {
                console.log('Using cached token');
                this.cachedToken = cachedToken;
                this.gameToken = cachedToken;
                return cachedToken;
            } else {
                console.log('Cached token invalid, generating new token');
                localStorage.removeItem('gameToken');
                this.cachedToken = null;
            }
        }
        
        // Get device info
        console.log('Getting device info...');
        const deviceInfo = await this._getDeviceInfo();
        console.log('Device info:', JSON.stringify(deviceInfo, null, 2));
        
        // Default values for additional required parameters
        const msisdn = '9800000000'; // Default phone number for web
        const country = 'US';         // Default country
        const operator = deviceInfo.device_brand || 'web';
        
        // Construct token request URL with all required parameters
        const url = `${this.baseUrl}/api.php/protoken?` + new URLSearchParams({
            handset_os: deviceInfo.handset_os || 'unknown',
            device_brand: deviceInfo.device_brand || 'unknown',
            device_model: deviceInfo.device_model || 'web_browser',
            msisdn: msisdn,
            _country: country,
            _operator: operator
        });
        
        console.log('Generating token from URL:', url);
        
        try {
            const response = await fetch(url, {
                method: 'GET',
                headers: {
                    'Accept': 'application/json',
                    'Cache-Control': 'no-cache'
                }
            });
            
            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }
            
            // First try to get response as text and clean it up
            let responseText = await response.text();
            console.log('Raw token response:', responseText);
            
            // Clean up the response text (remove any whitespace, quotes, etc.)
            responseText = responseText.trim().replace(/^['"]|['"]$/g, '');
            console.log('Cleaned token response:', responseText);
            
            let token = null;
            
            // First, try to use the response as-is if it looks like a token
            if (responseText && responseText.length >= 10) {
                console.log('Response looks like a token, using it directly');
                token = responseText;
            }
            
            // If we don't have a token yet, try to parse as JSON
            if (!token) {
                try {
                    console.log('Attempting to parse as JSON...');
                    const responseData = JSON.parse(responseText);
                    if (responseData && responseData.token) {
                        token = responseData.token;
                    } else if (responseData && responseData.data && responseData.data.token) {
                        token = responseData.data.token;
                    }
                } catch (jsonError) {
                    console.log('Not a JSON response, continuing with direct token');
                    // Not a JSON error is okay here, we'll use the direct token
                }
            }
            
            // If we still don't have a token, try to extract it using regex
            if (!token) {
                console.log('Attempting to extract token using regex...');
                const tokenMatch = responseText.match(/[a-zA-Z0-9_-]{20,}/);
                if (tokenMatch) {
                    token = tokenMatch[0];
                    console.log('Extracted token using regex');
                }
            }
            
            // If we still don't have a token, use the response as-is (last resort)
            if (!token && responseText) {
                console.log('Using response text as token (last resort)');
                token = responseText;
            }
            
            if (!token) {
                throw new Error('Could not extract token from response');
            }
            
            console.log('Token generated successfully');
            
            // Store token and update instance
            localStorage.setItem('gameToken', token);
            this.cachedToken = token;
            this.gameToken = token;
            
            return token;
            
        } catch (error) {
            console.error('Error generating token:', error);
            
            // Fallback to a local token if API call fails
            const fallbackToken = 'fallback_' + Date.now();
            console.warn('Using fallback token:', fallbackToken);
            
            this.cachedToken = fallbackToken;
            this.gameToken = fallbackToken;
            
            return fallbackToken;
        }
    }
    
    // Clear session-specific data
    clearSessionData() {
        // Clear all session-specific data
        localStorage.removeItem('lastSubmittedData');
        localStorage.removeItem('pendingScore');
        localStorage.removeItem('lastScoreSubmissionTime');
        
        // Reset instance variables
        this.lastScoreSubmissionTime = 0;
        this.lastSubmittedData = { score: 0, level: 1 };
        this.pendingScore = { score: 0, level: 1 };
        this.scoreSubmitted = false;
        
        console.log('Session data cleared');
    }
    
    // Get device information
    _getDeviceInfo() {
        const userAgent = navigator.userAgent;
        let handset_os = 'unknown';
        let device_brand = 'unknown';
        let device_model = 'web_browser';
        
        // Detect operating system
        if (userAgent.match(/Android/i)) {
            handset_os = 'Android';
            // Try to extract Android version
            const androidMatch = userAgent.match(/Android (\d+(\.\d+)*)/);
            if (androidMatch) {
                handset_os = `Android ${androidMatch[1]}`;
            }
        } else if (userAgent.match(/iPhone|iPad|iPod/i)) {
            handset_os = 'iOS';
            const iosMatch = userAgent.match(/OS (\d+_\d+_\d+)/);
            if (iosMatch) {
                handset_os = `iOS ${iosMatch[1].replace(/_/g, '.')}`;
            }
        } else if (userAgent.match(/Windows/i)) {
            handset_os = 'Windows';
        } else if (userAgent.match(/Mac/i)) {
            handset_os = 'Mac OS';
        } else if (userAgent.match(/Linux/i)) {
            handset_os = 'Linux';
        }
        
        // Try to detect device brand and model
        if (userAgent.match(/Samsung/i)) {
            device_brand = 'Samsung';
            const samsungModel = userAgent.match(/SM-[A-Z0-9]+/);
            if (samsungModel) {
                device_model = samsungModel[0];
            }
        } else if (userAgent.match(/iPhone/i)) {
            device_brand = 'Apple';
            device_model = 'iPhone';
        } else if (userAgent.match(/iPad/i)) {
            device_brand = 'Apple';
            device_model = 'iPad';
        } else if (userAgent.match(/Pixel/i)) {
            device_brand = 'Google';
            device_model = 'Pixel';
        } else if (userAgent.match(/Xiaomi/i)) {
            device_brand = 'Xiaomi';
        } else if (userAgent.match(/Huawei/i)) {
            device_brand = 'Huawei';
        } else if (userAgent.match(/Windows Phone/i)) {
            device_brand = 'Microsoft';
            device_model = 'Windows Phone';
        }
        
        console.log('Device info detected:', { handset_os, device_brand, device_model });
        return { handset_os, device_brand, device_model };
    }
    
    // Verify token at game start
    async verifyTokenAtStart() {
        try {
            this.gameToken = await this.generateToken();
            console.log('Token verified at game start:', this.gameToken ? this.gameToken.substring(0, 10) + '...' : 'null');
            return this.gameToken;
        } catch (error) {
            console.error('Failed to verify token at game start:', error);
            
            // Create an emergency token even if verification fails
            console.log('Generating emergency token due to verification failure');
            this.gameToken = 'emergency_token_' + Date.now();
            return this.gameToken;
        }
    }

    // Submit score to the API
    async submitScoreIfNeeded(currentScore, level = 1) {
        if (!currentScore) {
            console.log('Score invalid, skipping submission');
            return false;
        }

        // First, ensure we have a valid token
        if (!this.gameToken) {
            console.log('No token found, generating new token...');
            this.gameToken = await this.generateToken();
            if (!this.gameToken) {
                console.error('Failed to generate token, cannot submit score');
                return false;
            }
        }

        // Validate existing token
        console.log('Validating token before submission...');
        const isValid = await this.validateToken(this.gameToken).catch(() => false);
        if (!isValid) {
            console.log('Token invalid, generating new token...');
            this.gameToken = await this.generateToken();
            if (!this.gameToken) {
                console.error('Failed to generate new token after validation failed');
                return false;
            }
        }

        // Store the level with the score
        const scoreData = { score: currentScore, level: level };
        
        // Get last submitted data
        const lastSubmittedData = localStorage.getItem('lastSubmittedData');
        const lastData = lastSubmittedData ? JSON.parse(lastSubmittedData) : { score: 0, level: 1 };
        
        if (currentScore === lastData.score && level === lastData.level) {
            console.log('Score and level unchanged, skipping submission');
            return false;
        }

        const now = Date.now();
        const timeSinceLastSubmission = now - this.lastScoreSubmissionTime;
        
        // If we have a pending score and enough time has passed, try to submit it first
        if (this.pendingScore.score > 0 && timeSinceLastSubmission >= 600000) {
            console.log('Attempting to submit pending score:', this.pendingScore.score, 'level:', this.pendingScore.level);
            // Submit directly to avoid recursion
            const result = await this.submitFinalScore(
                this.gameToken,
                this.pendingScore.score,
                Math.floor((now - this.gameStartTime) / 1000),
                this.pendingScore.level
            );
            if (result) {
                console.log('Successfully submitted pending score');
                this.pendingScore = { score: 0, level: 1 };
                localStorage.removeItem('pendingScore');
            }
        }

        // Prevent too frequent submissions (minimum 10 minutes between submissions)
        // Always store the current score as pending if it's higher
        if (currentScore > (this.pendingScore?.score || 0)) {
            console.log('Storing new high score - Score:', currentScore, 'Level:', level);
            this.pendingScore = scoreData;
            localStorage.setItem('pendingScore', JSON.stringify(scoreData));
        }
        
        // Check cooldown
        if (timeSinceLastSubmission < 600000) { // 10 minutes = 600000 milliseconds
            console.log('Too soon to submit again, using cached score for later...');
            return false;
        }

        try {
            const formattedStartTime = new Date(this.gameStartTime).toISOString();
            const formattedEndTime = new Date(now).toISOString();
            const totalDuration = Math.floor((now - this.gameStartTime) / 1000);

            // Get device info
            const deviceInfo = await this._getDeviceInfo();
            const { handset_os, device_brand, device_model } = deviceInfo;
            
            const params = [
                `handset_os=${encodeURIComponent(handset_os || navigator.platform)}`,
                `device_brand=${encodeURIComponent(device_brand || navigator.vendor || 'web')}`,
                `device_model=${encodeURIComponent(device_model || navigator.userAgent)}`,
                `gamename=ninjaknifepro`,
                `gamelevel=${encodeURIComponent(level.toString())}`,
                `gamestarttime=${encodeURIComponent(formattedStartTime)}`,
                `gameendtime=${encodeURIComponent(formattedEndTime)}`,
                `gduration=${totalDuration}`,
                `gscore=${currentScore}`,
                `session_id=${this.session_id}`
            ];

            const url = `${this.baseUrl}/api.php/scorepost?${params.join('&')}`;
            console.log('Submitting score:', currentScore);
            console.log('Using token for submission:', this.gameToken ? this.gameToken.substring(0, 10) + '...' : 'null');
            console.log('Submitting to URL:', url);
            
            // Create headers with Authorization
            const headers = new Headers();
            headers.append('Authorization', `Bearer ${this.gameToken}`);
            headers.append('Accept', 'application/json');
            headers.append('Content-Type', 'application/json');
            headers.append('Cache-Control', 'no-cache, no-store, must-revalidate');
            
            // Log the headers
            console.log('Request headers:', {
                'Authorization': `Bearer ${this.gameToken.substring(0, 10)}...`,
                'Content-Type': 'application/json'
            });
            
            const response = await fetch(url, {
                method: 'GET',
                headers: headers,
                credentials: 'include',
                mode: 'cors',
                cache: 'no-cache'
            });

            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }

            this.lastScoreSubmissionTime = now;
            localStorage.setItem('lastScoreSubmissionTime', now);
            // Store last submitted data
            const submittedData = { score: currentScore, level: level };
            localStorage.setItem('lastSubmittedData', JSON.stringify(submittedData));
            
            // Clear any pending score since we successfully submitted
            this.pendingScore = { score: 0, level: 1 };
            localStorage.removeItem('pendingScore');
            console.log('Score submitted successfully');
            return true;
        } catch (error) {
            console.error('Error submitting score:', error);
            return false;
        }
    }

    // Set up global activity tracking - called on initialization
    setupGlobalActivityTracking() {
        // Set up global inactivity checker if not already done
        if (!window.inactivityChecker) {
            window.inactivityChecker = setInterval(() => {
                // Check if game has been inactive for too long (15 minutes timeout)
                const inactiveTime = Date.now() - this.lastActivityTime;
                console.log('Inactive time:', Math.floor(inactiveTime/1000), 'seconds');
                
                if (this.isInactive(15 * 60 * 1000)) { // 15 minutes inactivity timeout
                    console.log('Inactivity detected after 15 minutes!');
                    // Log and get current score data
                    const storedData = {
                        pending: localStorage.getItem('pendingScore'),
                        last: localStorage.getItem('lastSubmittedData')
                    };
                    
                    const parsedData = {
                        pending: storedData.pending ? JSON.parse(storedData.pending) : null,
                        last: storedData.last ? JSON.parse(storedData.last) : null
                    };
                    
                    console.log('Current pending - Score:', parsedData.pending?.score || 'none', 'Level:', parsedData.pending?.level || 'none');
                    console.log('Last submitted - Score:', parsedData.last?.score || 'none', 'Level:', parsedData.last?.level || 'none');
                    
                    this.handleInactivity();
                    
                    // Submit score on inactivity using stored values
                    if (parsedData.pending) {
                        const { score, level } = parsedData.pending;
                        console.log('Submitting stored score on inactivity - Score:', score, 'Level:', level);
                        this.submitScoreIfNeeded(score, level);
                    } else {
                        console.log('No pending score to submit on inactivity');
                    }
                    
                    // Clear the interval after handling inactivity
                    clearInterval(window.inactivityChecker);
                    window.inactivityChecker = null;
                }
            }, 5000); // Check every 5 seconds for faster response
        }
        
        // Set up global activity event listeners
        if (!window.activityTrackingInitialized) {
            // Track common user interactions
            document.addEventListener('click', () => this.updateActivity());
            document.addEventListener('keydown', () => this.updateActivity());
            document.addEventListener('touchstart', () => this.updateActivity());
            document.addEventListener('mousemove', () => this.updateActivity());
            
            // Add visibility change listener for tab switching
            document.addEventListener('visibilitychange', () => {
                if (document.visibilityState === 'hidden') {
                    console.log('Tab visibility changed to hidden');
                    // Get stored score data
                    const storedData = {
                        pending: localStorage.getItem('pendingScore'),
                        last: localStorage.getItem('lastSubmittedData')
                    };
                    
                    const parsedData = {
                        pending: storedData.pending ? JSON.parse(storedData.pending) : null,
                        last: storedData.last ? JSON.parse(storedData.last) : null
                    };
                    
                    console.log('Current pending - Score:', parsedData.pending?.score || 'none', 'Level:', parsedData.pending?.level || 'none');
                    console.log('Last submitted - Score:', parsedData.last?.score || 'none', 'Level:', parsedData.last?.level || 'none');
                    
                    if (parsedData.pending) {
                        console.log('Submitting stored score on tab change - Score:', parsedData.pending.score, 'Level:', parsedData.pending.level);
                        this.submitScoreIfNeeded(parsedData.pending.score, parsedData.pending.level);
                    } else {
                        console.log('No pending score to submit on tab change');
                    }
                }
            });
            
            // Mark tracking as initialized to prevent duplicates
            window.activityTrackingInitialized = true;
        }
    }
    
    // Handle inactivity - directly shows message and terminates session
    handleInactivity() {
        // Don't handle multiple times
        if (document.getElementById('inactivity-overlay')) {
            return;
        }
        
        console.log('Session inactive for too long - displaying message');
        
        // Try to pause the game using available methods
        this.attemptPauseGame();
        
        // Ensure score is submitted
        this.submitScoreIfNeeded();
        
        // Add warning message through API system or show our own
        this.showInactivityMessage();
    }
    
    // Method to attempt pausing the game using various techniques
    attemptPauseGame() {
        try {
            // Method 1: Check for common game pause functions
            if (typeof window.pauseGame === 'function') {
                window.pauseGame();
                console.log('Game paused using window.pauseGame()');
                return true;
            }
            
            // Method 2: Check for global game object with pause function
            if (window.game && typeof window.game.pause === 'function') {
                window.game.pause();
                console.log('Game paused using game.pause()');
                return true;
            }
            
            // Method 3: Try to stop game loops by overriding requestAnimationFrame
            const originalRAF = window.requestAnimationFrame;
            window.requestAnimationFrame = function(callback) {
                console.log('RequestAnimationFrame intercepted due to inactivity');
                return null; // Return an ID that can never be canceled
            };
            
            // Store the original to potentially restore later
            window._originalRequestAnimationFrame = originalRAF;
            
            console.log('Game attempted to pause by overriding requestAnimationFrame');
            return true;
        } catch (error) {
            console.error('Failed to pause game:', error);
            return false;
        }
    }
    
    // Legacy method maintained for compatibility
    async submitScore(currentScore = window.playerData?.score || 0) {
        try {
            // If no token yet, try to get one
            if (!this.gameToken) {
                this.gameToken = await this.generateToken().catch(e => {
                    console.warn('Failed to generate token for score submission:', e);
                    return null;
                });
            }

            // Always validate the token before submitting the score
            let isValid = false;
            if (this.gameToken) {
                isValid = await this.validateToken(this.gameToken).catch(() => false);
            }
            if (!isValid) {
                console.warn('Token invalid before score submission, generating new token');
                this.gameToken = await this.generateToken().catch(e => {
                    console.warn('Failed to generate token for score submission:', e);
                    return null;
                });
            }
            // Don't continue if no valid token or already submitted
            if (!this.gameToken || this.scoreSubmitted) {
                console.log('Score not submitted: ', 
                    !this.gameToken ? 'No valid token' : 'Already submitted');
                return false;
            }
            // Get current player score
            console.log('Current score to submit:', currentScore);
            const now = Date.now();
            // Submit the score
            const result = await this.submitFinalScore(
                this.gameToken, 
                currentScore, 
                Math.floor((now - this.gameStartTime) / 1000),
                1);
            return result;
        } catch (error) {
            console.error('Error in submitScore:', error);
            return false;
        }
    }
    
    // Show inactivity message when timeout is reached
    showInactivityMessage() {
        console.log('Attempting to show inactivity message overlay...');
        
        try {
            // Force removal of any existing overlay first to avoid conflicts
            const existingOverlay = document.getElementById('inactivity-overlay');
            if (existingOverlay && existingOverlay.parentNode) {
                existingOverlay.parentNode.removeChild(existingOverlay);
                console.log('Removed existing overlay to create a new one');
            }
            
            // Create a new overlay container
            console.log('Creating inactivity overlay element');
            const overlay = document.createElement('div');
            overlay.id = 'inactivity-overlay';
            overlay.style.position = 'fixed';
            overlay.style.top = '0';
            overlay.style.left = '0';
            overlay.style.width = '100%';
            overlay.style.height = '100%';
            overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.9)';
            overlay.style.zIndex = '999999'; // Very high z-index to ensure visibility
            overlay.style.display = 'flex';
            overlay.style.flexDirection = 'column';
            overlay.style.alignItems = 'center';
            overlay.style.justifyContent = 'center';
            overlay.style.fontFamily = 'Arial, sans-serif';
            overlay.style.color = 'white';
            overlay.style.textAlign = 'center';
            overlay.style.padding = '20px';
            
            // Create message elements
            const message = document.createElement('div');
            message.style.fontSize = '24px';
            message.style.marginBottom = '20px';
            message.style.maxWidth = '80%';
            message.innerHTML = '<strong>Your game session has timed out due to inactivity</strong>';
            
            const submessage = document.createElement('div');
            submessage.style.fontSize = '18px';
            submessage.style.marginBottom = '30px';
            submessage.style.maxWidth = '80%';
            submessage.innerHTML = 'Your progress has been saved. Click the button below to return to the game.';
            
            // Create button
            const button = document.createElement('button');
            button.innerText = 'Refresh';
            button.style.padding = '15px 30px';
            button.style.fontSize = '18px';
            button.style.backgroundColor = '#4CAF50';
            button.style.color = 'white';
            button.style.border = 'none';
            button.style.borderRadius = '4px';
            button.style.cursor = 'pointer';
            button.style.fontWeight = 'bold';
            button.style.boxShadow = '0 4px 6px rgba(0,0,0,0.1)';
            
            // Hover effect
            button.onmouseover = () => {
                button.style.backgroundColor = '#45a049';
            };
            button.onmouseout = () => {
                button.style.backgroundColor = '#4CAF50';
            };
            
            // Click handler
            button.onclick = () => {
                console.log('Inactivity overlay button clicked - performing full page refresh');
                
                // Force a complete refresh with no cache
                window.location.href = window.location.href.split('#')[0] + '?refresh=' + Date.now();
                
                // As a fallback, also use the standard reload with cache bypass
                setTimeout(() => {
                    console.log('Using fallback reload method');
                    window.location.reload(true);
                }, 100);
            };
            
            // Assemble the overlay
            overlay.appendChild(message);
            overlay.appendChild(submessage);
            overlay.appendChild(button);
            
            // Add to document
            document.body.appendChild(overlay);
            console.log('Inactivity message overlay added to document.body');
            
            // Add a subtle fade-in animation
            overlay.style.opacity = '0';
            setTimeout(() => {
                overlay.style.transition = 'opacity 0.5s ease-in-out';
                overlay.style.opacity = '1';
                console.log('Inactivity overlay fade-in animation applied');
            }, 10);
            
            return true;
        } catch (error) {
            console.error('Error in showInactivityMessage:', error);
            // Fallback method if the fancy overlay fails
            try {
                alert('Your game session has timed out due to inactivity. The page will now reload.');
                window.location.reload();
            } catch (alertError) {
                console.error('Even the alert fallback failed:', alertError);
            }
            return false;
        }
    }
    
    // Check if game is inactive for the specified duration (in milliseconds)
    isInactive(durationMs = 60 * 60 * 1000) { // Default to 1 hour
        const inactiveTime = Date.now() - this.lastActivityTime;
        return inactiveTime > durationMs;
    }
    
    // Update the last activity timestamp whenever user interaction is detected
    updateActivity() {
        this.lastActivityTime = Date.now();
    }
    
    // Get device info, using cache if available
    async _getDeviceInfo() {
        // Default values for browser environment
        const deviceInfo = {
            handset_os: 'unknown',
            device_brand: 'unknown',
            device_model: 'browser'
        };
        
        try {
            // Try to detect operating system and device info
            const userAgent = navigator.userAgent || '';
            console.log('User Agent:', userAgent);
            
            // Detect operating system
            if (/Windows/.test(userAgent)) {
                deviceInfo.handset_os = 'windows';
                // Try to get Windows version
                const winMatch = userAgent.match(/Windows NT (\d+\.\d+)/);
                if (winMatch) {
                    deviceInfo.handset_os = `windows_${winMatch[1].replace(/\./g, '_')}`;
                }
            } else if (/Android/.test(userAgent)) {
                deviceInfo.handset_os = 'android';
                const androidMatch = userAgent.match(/Android (\d+(?:\.\d+)*)/);
                if (androidMatch) {
                    deviceInfo.handset_os = `android_${androidMatch[1].replace(/\./g, '_')}`;
                }
            } else if (/iPhone|iPad|iPod/.test(userAgent)) {
                deviceInfo.handset_os = 'ios';
                const iosMatch = userAgent.match(/OS (\d+_\d+(?:_\d+)?)/);
                if (iosMatch) {
                    deviceInfo.handset_os = `ios_${iosMatch[1]}`;
                }
            } else if (/Mac OS X/.test(userAgent)) {
                deviceInfo.handset_os = 'macos';
                const macMatch = userAgent.match(/Mac OS X (\d+[._]\d+(?:[._]\d+)?)/);
                if (macMatch) {
                    deviceInfo.handset_os = `macos_${macMatch[1].replace(/\./g, '_').replace(/_/g, '.')}`;
                }
            } else if (/Linux/.test(userAgent)) {
                deviceInfo.handset_os = 'linux';
            }
            
            // Detect device type
            const isMobile = /Mobi|Android|iPhone|iPad|iPod/i.test(userAgent);
            
            // Detect browser/device brand
            if (/Chrome/.test(userAgent)) {
                deviceInfo.device_brand = 'chrome';
            } else if (/Firefox/.test(userAgent)) {
                deviceInfo.device_brand = 'firefox';
            } else if (/Edge/.test(userAgent)) {
                deviceInfo.device_brand = 'edge';
            } else if (/OPR|Opera/.test(userAgent)) {
                deviceInfo.device_brand = 'opera';
            } else if (/Safari/.test(userAgent)) {
                deviceInfo.device_brand = 'safari';
            } else if (/MSIE|Trident/.test(userAgent)) {
                deviceInfo.device_brand = 'ie';
            }
            
            // Detect specific devices
            if (/iPhone/.test(userAgent)) {
                deviceInfo.device_brand = 'apple';
                deviceInfo.device_model = 'iphone';
                // Try to get iPhone model
                const modelMatch = userAgent.match(/(iPhone\d+,[0-9]+)/);
                if (modelMatch) {
                    deviceInfo.device_model = modelMatch[1].toLowerCase();
                }
            } else if (/iPad/.test(userAgent)) {
                deviceInfo.device_brand = 'apple';
                deviceInfo.device_model = 'ipad';
                const modelMatch = userAgent.match(/(iPad\d+,[0-9]+)/);
                if (modelMatch) {
                    deviceInfo.device_model = modelMatch[1].toLowerCase();
                }
            } else if (/Android/.test(userAgent)) {
                // Try to extract manufacturer from user agent
                const modelMatch = userAgent.match(/Android.*?; ([^;)]+)(?:\)|;)/);
                if (modelMatch && modelMatch[1]) {
                    const modelInfo = modelMatch[1].trim();
                    const parts = modelInfo.split(' Build/');
                    deviceInfo.device_model = parts[0].toLowerCase().replace(/\s+/g, '_');
                    
                    // Extract brand if available (e.g., 'samsung SM-G950F')
                    const brandMatch = deviceInfo.device_model.match(/^([a-z]+)/i);
                    if (brandMatch) {
                        deviceInfo.device_brand = brandMatch[1].toLowerCase();
                    }
                }
            }
            
            // Set device model based on mobile/desktop if not specifically detected
            if (deviceInfo.device_model === 'browser') {
                deviceInfo.device_model = isMobile ? 'mobile_browser' : 'desktop_browser';
            }
            
            console.log('Detected device info:', JSON.stringify(deviceInfo, null, 2));
            
            // Cache the device info for future use
            try {
                localStorage.setItem('deviceInfo', JSON.stringify(deviceInfo));
            } catch (e) {
                console.warn('Could not cache device info:', e);
            }
            
            this.cachedDeviceInfo = deviceInfo;
            return deviceInfo;
        } catch (error) {
            
            // Construct token request URL with all required parameters
            const url = `${this.baseUrl}/api.php/protoken?handset_os=${encodeURIComponent(handset_os)}&device_brand=${encodeURIComponent(device_brand)}&device_model=${encodeURIComponent(device_model)}&msisdn=${encodeURIComponent(msisdn)}&_country=${encodeURIComponent(country)}&_operator=${encodeURIComponent(operator)}`;
            
            console.log('Generating token from URL:', url);
            
            try {
                const response = await fetch(url, {
                    method: 'GET',
                    headers: {
                        'Accept': 'application/json',
                        'Cache-Control': 'no-cache'
                    }
                });
                
                if (!response.ok) {
                    throw new Error(`HTTP error! status: ${response.status}`);
                }
                
                // Clone the response so we can read it multiple ways if needed
                const responseClone = response.clone();
                
                // First, try to get the response as text
                const textResponse = await response.text();
                console.log('Token API response received');
                
                // Check if the response is direct token text (no JSON formatting)
                if (textResponse && textResponse.length > 10 && !textResponse.includes('{') && !textResponse.includes(':')) {
                    // The response appears to be a raw token
                    const token = textResponse.trim();
                    console.log('Direct token received:', token.substring(0, 10) + '...');
                    
                    // Store token and reset game start time
                    localStorage.setItem('gameToken', token);
                    this.cachedToken = token;
                    this.gameToken = token;
                    this.gameStartTime = Date.now();
                    
                    return token;
                }
                
                // If not a direct token, try to parse as JSON
                try {
                    const data = JSON.parse(textResponse);
                    
                    if (data && data.token) {
                        console.log('Token extracted from JSON:', data.token.substring(0, 10) + '...');
                        
                        // Store token and reset game start time
                        localStorage.setItem('gameToken', data.token);
                        this.cachedToken = data.token;
                        this.gameToken = data.token;
                        this.gameStartTime = Date.now();
                        
                        return data.token;
                    }
                } catch (jsonError) {
                    // Not valid JSON, try to extract token using regex
                    const tokenMatch = textResponse.match(/"token"\s*:\s*"([^"]+)"/i);
                    if (tokenMatch && tokenMatch[1]) {
                        const extractedToken = tokenMatch[1];
                        console.log('Extracted token from text response:', extractedToken.substring(0, 10) + '...');
                        
                        // Store token and reset game start time
                        localStorage.setItem('gameToken', extractedToken);
                        this.cachedToken = extractedToken;
                        this.gameToken = extractedToken;
                        this.gameStartTime = Date.now();
                        
                        return extractedToken;
                    }
                }
                
                // If we've reached this point, couldn't extract a token
                console.log('Could not extract token from response, using fallback');
                const fallbackToken = 'fallback_token_' + Date.now();
                this.gameToken = fallbackToken;
                return fallbackToken;
            } catch (fetchError) {
                console.warn('API error during token generation:', fetchError.message);
                
                // Generate a development token if API fails
                const devToken = 'dev_token_' + Date.now();
                console.log('Using development token:', devToken);
                
                // Store token
                localStorage.setItem('gameToken', devToken);
                this.cachedToken = devToken;
                this.gameToken = devToken;
                
                return devToken;
            }
        } 
    }
    
    // Validate token with server
    async validateToken(token) {
        if (!token) {
            console.warn('No token provided for validation');
            return false;
        }
        try {
            const url = `${this.baseUrl}/api.php/chktoken?token=${encodeURIComponent(token)}`;
            console.log('Validating token at URL:', url);
            const response = await fetch(url, { 
                method: 'GET',
                headers: {
                    'Cache-Control': 'no-cache',
                    'Pragma': 'no-cache'
                }
            });
            
            if (!response.ok) {
                console.warn('Token validation failed with status:', response.status);
                return false;
            }
            
            const validationText = await response.text();
            const isValid = validationText.trim().toLowerCase() === 'valid';
            console.log('Token validation result:', isValid ? 'valid' : 'invalid');
            return isValid;
        } catch (error) {
            console.error('Error validating token:', error);
            return false;
        }
    }
    
    // Simple token check without async verification - only used for basic format validation
    isTokenValid(token) {
        // Check if token exists and has a reasonable format
        return token && 
               token.length > 10 && 
               !token.startsWith('emergency_token_') && 
               !token.startsWith('fallback_token_') && 
               !token.startsWith('dev_token_');
    }
    
    // Submit final score for the game
    async submitFinalScore(token, currentScore, totalDuration, level = 1) {
        try {
            // Check cooldown first
            const now = Date.now();
            const timeSinceLastSubmission = now - this.lastScoreSubmissionTime;
            if (timeSinceLastSubmission < 600000) { // 10 minutes cooldown
                console.log('Too soon to submit, cooldown active for', Math.floor((600000 - timeSinceLastSubmission)/1000), 'more seconds');
                return false;
            }

            // Prevent multiple score submissions with the same token
            if (this.scoreSubmitted) {
                console.log('Score already submitted with this token');
                return false;
            }

            // Track this submission
            this.lastScoreSubmissionTime = now;
            this.lastSubmittedScore = currentScore;

            if (!token || totalDuration === undefined) {
                console.warn('⚠️ Cannot submit score: missing token or duration');
                return { status: 'error', message: 'Missing token or duration' };
            }
            
            // ✅ Basic validation passed
            console.log('🔵 SUBMIT SCORE: Valid token and duration');
            
            // ✅ Continue only if checks passed
            console.log('🔵 SUBMIT SCORE: Starting submission for score:', currentScore);
            const deviceInfo = this._getDeviceInfo();
            const { handset_os, device_brand, device_model } = deviceInfo;
            console.log('🔵 SUBMIT SCORE: Device info:', { handset_os, device_brand, device_model });
            
            const gameStartTime = this.gameStartTime || (Date.now() - totalDuration * 1000);
            const gameEndTime = Date.now();

            // Format dates in exactly the format the API expects (yyyy-mm-dd hh:mm:ss)
            const formatDate = (date) => {
                const d = new Date(date);
                const local = new Date(d.getTime() - d.getTimezoneOffset() * 60000);
                return `${local.getFullYear()}-${String(local.getMonth() + 1).padStart(2, '0')}-${String(local.getDate()).padStart(2, '0')} ${String(local.getHours()).padStart(2, '0')}:${String(local.getMinutes()).padStart(2, '0')}:${String(local.getSeconds()).padStart(2, '0')}`;
            };

            // Format the timestamps in the requested format
            const formattedStartTime = formatDate(gameStartTime);
            const formattedEndTime = formatDate(gameEndTime);
            
            // Format and log the timestamps in the requested format
            console.log('gamestarttime');
            console.log(formattedStartTime);
            console.log('gameendtime');
            console.log(formattedEndTime);


            // Build API request parameters with EXACTLY the required fields in the exact order
            // Extract the game name from the base URL
            const gameNameMatch = this.baseUrl.match(/\/([^\/]+)$/);
            const gameName = gameNameMatch ? gameNameMatch[1] : 'bestglider';
            console.log('Using game name for submission:', gameName);
            
            const params = [
                // Matching exact order as specified in the API documentation
                `handset_os=${encodeURIComponent(handset_os || 'android')}`,
                `device_brand=${encodeURIComponent(device_brand || 'samsung')}`,
                `device_model=${encodeURIComponent(device_model || 'browser')}`,
                `gamename=ninjaknifepro`,
                `gamelevel=${encodeURIComponent(level)}`,
                `gamestarttime=${encodeURIComponent(formattedStartTime)}`,
                `gameendtime=${encodeURIComponent(formattedEndTime)}`,
                `gduration=${totalDuration}`,
                `gscore=${currentScore}`,
                `session_id=${this.session_id}`
            ];

            // Construct the URL using the correct endpoint format
            const url = `${this.baseUrl}/api.php/scorepost?${params.join('&')}`;
            console.log('SUBMIT SCORE: Submitting to API URL:', url);
            console.log('SUBMIT SCORE: Using token:', token ? token.substring(0, 10) + '...' : 'null');
            
            try {
                // Create headers object with Authorization
                const headers = new Headers();
                headers.append('Authorization', `Bearer ${token}`);
                headers.append('Content-Type', 'application/json');
                headers.append('Cache-Control', 'no-cache, no-store, must-revalidate');
                headers.append('Pragma', 'no-cache');
                headers.append('Expires', '0');
                
                // Log the headers to verify they're being set
                console.log('SUBMIT SCORE: Request headers:', {
                    'Authorization': `Bearer ${token.substring(0, 10)}...`,
                    'Content-Type': 'application/json'
                });
                
                const response = await fetch(url, {
                    method: 'GET',
                    headers: headers,
                    credentials: 'include',
                    mode: 'cors',
                    cache: 'no-cache'
                });
                
                if (!response.ok) {
                    throw new Error(`HTTP error! status: ${response.status}`);
                }

                // Mark score as submitted
                this.scoreSubmitted = true;
                
                // Update localStorage with submitted data
                const submittedData = { score: currentScore, level };
                localStorage.setItem('lastSubmittedData', JSON.stringify(submittedData));
                localStorage.setItem('lastScoreSubmissionTime', Date.now().toString());
                localStorage.removeItem('pendingScore'); // Clear pending since we submitted
                
                console.log('✅ SUBMIT SCORE: Score successfully submitted!');
                console.log('✅ SUBMIT SCORE: Updated localStorage - Last submitted:', submittedData);
                
                try {
                    const data = await response.json();
                    console.log('✅ SUBMIT SCORE: Server response:', data);
                    return data;
                } catch (parseError) {
                    const textResponse = await response.text();
                    console.log('✅ SUBMIT SCORE: Server text response:', textResponse);
                    return { status: 'success', message: textResponse };
                }
            } catch (fetchError) {
                console.warn('⚠️ API error during score submission:', fetchError.message);
                
                // For development: Create a success response if API fails
                console.log('✅ FALLBACK: Recording score locally');
                
                // Still mark as submitted for tracking purposes
                this.scoreSubmitted = true;
                
                // Update localStorage even in fallback case
                const submittedData = { score: currentScore, level };
                localStorage.setItem('lastSubmittedData', JSON.stringify(submittedData));
                localStorage.setItem('lastScoreSubmissionTime', Date.now().toString());
                localStorage.removeItem('pendingScore'); // Clear pending since we submitted
                
                // Return mock response
                return { 
                    status: 'success', 
                    message: 'Development mode: Score recorded locally', 
                    score: currentScore,
                    timestamp: new Date().toISOString()
                };
            }
        } catch (error) {
            console.error('❌ SUBMIT SCORE: Error in score submission:', error);
            return { status: 'error', message: error.message };
        }
    }

    // Legacy method maintained for compatibility
    async submitScore(score) {
        console.log('submitScore called with score:', score);
        return this.submitScoreIfNeeded(score);
    }
}

// ✅ Use updated base URL (without /api.php)
const API_BASE_URL = 'https://cgames.unlimitedgames.info/ninjaknifepro';

// Ninja Knife Pro API Wrapper
class NinjaKnifeAPIWrapper {
    constructor() {
        this.apiHandler = new APIHandler(API_BASE_URL);
        this.initialized = false;
        this.isSubmitting = false; // Track if we're currently submitting
        this.init();
    }

    async init() {
        if (!this.initialized) {
            await this.apiHandler.verifyTokenAtStart();
            this.initialized = true;
            console.log('Pirate Jumpiru API initialized');
        }
    }

    async submitScoreIfNeeded(score, level = 1) {
        if (this.isSubmitting) {
            console.log('Already submitting score, please wait...');
            return false;
        }
        
        this.isSubmitting = true;
        
        try {
            if (!this.initialized) {
                await this.init();
            }
            
            if (!score && score !== 0) {
                console.error('No score provided to submit');
                return false;
            }
            
            console.log(`Submitting score if needed: ${score}, level: ${level}`);
            
            // Use the apiHandler to submit the score if needed
            const result = await this.apiHandler.submitScoreIfNeeded(score, level);
            
            if (result) {
                console.log('Score submitted successfully');
                return true;
            } else {
                console.log('Score submission was not needed or failed');
                return false;
            }
        } catch (error) {
            console.error('Error in submitScoreIfNeeded:', error);
            return false;
        } finally {
            this.isSubmitting = false;
        }
    }
}

// Create apiHandler immediately when the script is loaded and ensure it's globally available
// Initialize the API handler
window.apiHandler = new APIHandler(API_BASE_URL);
window.ninjaKnifeAPI = new NinjaKnifeAPIWrapper();

// Initialize the handler when the window loads
window.addEventListener('load', function() {
    if (!window.apiHandler) {
        window.apiHandler = new APIHandler(API_BASE_URL);
    }
    window.apiHandler.verifyTokenAtStart();
});

// Export for module usage if needed
if (typeof module !== 'undefined' && module.exports) {
    module.exports = APIHandler;
}

document.addEventListener('DOMContentLoaded', () => {
    console.log("Page loaded - activity tracking initialized");
    if (window.apiHandler) {
        window.apiHandler.updateActivity();
    }
});

document.addEventListener('game:tabchange', (event) => {
    // This can be used to handle tab changes in the game scripts
    console.log('Tab change detected:', event.detail?.message || 'No details');
    // Attempt to submit score if a game is in progress
    if (window.apiHandler) {
        window.apiHandler.submitScoreIfNeeded();
    }
});

document.addEventListener('game:unload', (event) => {
    // This can be used to handle page unload in the game scripts
    console.log('Page unload detected:', event.detail?.message || 'No details');
    // Attempt to submit score if a game is in progress
    if (window.apiHandler) {
        window.apiHandler.submitScoreIfNeeded();
    }
});

/* 
INTEGRATION GUIDE:

1. In your HTML file, include this script before your main game script:
   <script src="apiHandler.js"></script>
   <script src="your-game-script.js"></script>

2. In your game initialization code, generate a token:
   if(window.apiHandler && typeof window.apiHandler.generateToken === 'function') {
     window.apiHandler.generateToken();
   }

3. In your game end function, submit the score:
   if(window.apiHandler && typeof window.apiHandler.submitScoreIfNeeded === 'function') {
     window.apiHandler.submitScoreIfNeeded(yourGameScore);
   }

4. Make sure your game exposes the score in a playerData object:
   window.playerData = { 
     score: 0,
     // other game data
   };

5. Update the score in both your game and playerData:
   function updateScore(newScore) {
     // Update your game's internal score
     yourGameScore = newScore;
     
     // Update the playerData object for the API handler
     if (window.playerData) {
       window.playerData.score = newScore;
     }
   }
*/
