const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreElement = document.getElementById('score');
const healthElement = document.getElementById('health');
const startMessage = document.getElementById('startMessage');
//const weaponSelector = document.getElementById('weaponSelector');
const playButton = document.getElementById('playButton');
const quitButton = document.getElementById('quitButton');
const imageCache = new Map();
const bulletImageCache = new Map();
const enemyImageCache = new Map();


canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

const MAP_WIDTH = 3000;
const MAP_HEIGHT = 2000;

let audioContext, analyser, source;
let audioElement;
let player, camera;
let floatingTexts = [];
let otherPlayers = {};
let serverEnemies = [];
let serverBullets = [];
let particles = [];
let score = 0, health = 100;
let gameStarted = false;
let joystick = { active: false, startX: 0, startY: 0, endX: 0, endY: 0 };
let isDebugging = document.getElementById('debugCheckbox').checked;
let socket;
let currentSongDuration = 180; // Default to 3 minutes
let backgroundCanvas, backgroundCtx;
let uiButton, uiWidget, menuButton;
let isWidgetVisible = false;
let audioData = new Uint8Array(128);
let currentUser = null;
let minimapCanvas, minimapCtx, minimapState = 0;
let playerLevel = 1;
let playerExperience = 0;
let playerMaxExperience = 100;
let isPlayerPaused = false;
let openInterfaces = {
    menu: false,
    levelUp: false
};
let selectedClassId = null;
const infoButton = document.getElementById('infoButton');
const infoWidget = document.getElementById('infoWidget');
let isInfoWidgetVisible = false;
let playerSynthCoins = 0;
let synthCoinsCounter;
let currentCoinFloatingText = null;
let shopButton;
let shopWidget;
let isShopVisible = false;
let playerWeapons = [];
let wasPausedBeforeHidden = false;
let isAutoFireEnabled = false;
let shootingJoystick = {
    active: false,
    startX: 0,
    startY: 0,
    endX: 0,
    endY: 0,
    outerRadius: 50,
    innerRadius: 0,
    maxInnerRadius: 40,
    shootThreshold: 0.5,
    growthRate: 200, // pixels per second
};
let lastUpdateTime = Date.now();
let impactEffects = [];





class NotificationSystem {
    constructor() {
        this.notificationContainer = null;
        this.createNotificationContainer();
    }

    createNotificationContainer() {
        this.notificationContainer = document.createElement('div');
        this.notificationContainer.id = 'notificationContainer';
        document.body.appendChild(this.notificationContainer);
    }

    showNotification(message, image = null) {
        const notificationElement = document.createElement('div');
        notificationElement.className = 'custom-notification draggable';
        
        let content = `<div class="notification-content">`;
        if (image) {
            content += `<img src="${image}" alt="Achievement" class="notification-image">`;
        }
        content += `
            <p>${message}</p>
            <button class="close-notification">Close</button>
        </div>`;
        
        notificationElement.innerHTML = content;
    
        const closeButton = notificationElement.querySelector('.close-notification');
        closeButton.addEventListener('click', () => this.closeNotification(notificationElement));
    
        this.notificationContainer.appendChild(notificationElement);
        setTimeout(() => notificationElement.classList.add('show'), 10);
    
        makeDraggable(notificationElement);
    }

    
    
    closeNotification(notificationElement) {
        notificationElement.classList.remove('show');
        setTimeout(() => notificationElement.remove(), 300);
    }
}

const notificationSystem = new NotificationSystem();

function handleAchievementUnlock(data) {
    const message = `Achievement Unlocked: ${data.name}\n${data.description}`;
    notificationSystem.showNotification(message, data.image);
    
}

function fetchUserAchievements() {
    const achievementsGrid = document.getElementById('achievementsGrid');
    const achievementInfoBox = document.getElementById('achievementInfoBox');
    
    if (!achievementsGrid) {
        console.error('Achievements grid not found');
        return;
    }

    if (!currentUser) {
        displaySignInMessage(achievementsGrid, 'achievements');
        if (achievementInfoBox) {
            achievementInfoBox.style.display = 'none';
        }
        return;
    }

    if (achievementInfoBox) {
        achievementInfoBox.style.display = 'block';
    }

    fetch('/get-user-achievements', {
        headers: {
            'Authorization': getSessionToken()
        }
    })
    .then(response => {
        if (!response.ok) {
            throw new Error('Network response was not ok');
        }
        return response.json();
    })
    .then(achievements => {
        if (Array.isArray(achievements) && achievements.length > 0) {
            displayAllAchievements(achievements);
        } else {
            displayNoAchievementsMessage(achievementsGrid);
        }
    })
    .catch(error => {
        console.error('Error fetching user achievements:', error);
        displayErrorMessage(achievementsGrid, 'Failed to load achievements. Please try again later.');
    });
}

function displaySignInMessage(container, feature) {
    container.innerHTML = `
        <div class="sign-in-message">
            <p>Please sign in to view your ${feature}.</p>
        </div>
    `;
}


function displayNoAchievementsMessage(container) {
    container.innerHTML = `
        <div class="no-achievements-message">
            <p>You haven't unlocked any achievements yet.</p>
            <p>Keep playing to earn achievements!</p>
        </div>
    `;
}

function displayErrorMessage(container, message) {
    container.innerHTML = `
        <div class="error-message">
            <p>${message}</p>
        </div>
    `;
}

function displayAllAchievements(achievements) {
    const achievementsGrid = document.getElementById('achievementsGrid');
    if (!achievementsGrid) {
        console.error('Achievements grid not found');
        return;
    }

    achievementsGrid.innerHTML = '';
    achievements.forEach(achievement => {
        const achievementElement = document.createElement('div');
        achievementElement.classList.add('achievement');
        if (!achievement.unlocked) {
            achievementElement.classList.add('locked');
        }
        achievementElement.innerHTML = `
            <img src="${achievement.image}" alt="${achievement.name}">
            ${!achievement.unlocked ? '<div class="lock-overlay"><i class="fas fa-lock"></i></div>' : ''}
        `;
        achievementElement.addEventListener('click', () => showAchievementInfo(achievement));
        achievementElement.addEventListener('mouseover', () => showAchievementInfo(achievement));
        achievementsGrid.appendChild(achievementElement);
    });

    // Show info for the first achievement by default
    if (achievements.length > 0) {
        showAchievementInfo(achievements[0]);
    }
}


function showAchievementInfo(achievement) {
    const image = document.getElementById('achievementImage');
    const name = document.getElementById('achievementName');
    const description = document.getElementById('achievementDescription');
    const unlockedClasses = document.getElementById('unlockedClasses');
    const unlockedSkins = document.getElementById('unlockedSkins');

    image.src = achievement.image;
    name.textContent = achievement.name;

    if (achievement.unlocked) {
        name.classList.remove('locked');
        description.textContent = achievement.description;
    } else {
        name.classList.add('locked');
        description.textContent = `Unlock Requirements: ${achievement.unlock_requirements}`;
    }

    // Display unlockable items for both locked and unlocked achievements
    unlockedClasses.innerHTML = '<h5>Classes Unlocked:</h5>';
    if (achievement.unlocked_classes && achievement.unlocked_classes.length > 0) {
        achievement.unlocked_classes.forEach(c => {
            unlockedClasses.innerHTML += `<div class="unlock-item"><img src="${c.image}" alt="${c.name}"><span>${c.name}</span></div>`;
        });
    } else {
        unlockedClasses.innerHTML += '<p>No classes unlocked</p>';
    }

    unlockedSkins.innerHTML = '<h5>Skins Unlocked:</h5>';
    if (achievement.unlocked_skins && achievement.unlocked_skins.length > 0) {
        achievement.unlocked_skins.forEach(s => {
            unlockedSkins.innerHTML += `<div class="unlock-item"><img src="${s.image}" alt="${s.name}"><span>${s.name}</span></div>`;
        });
    } else {
        unlockedSkins.innerHTML += '<p>No skins unlocked</p>';
    }

    unlockedClasses.style.display = 'block';
    unlockedSkins.style.display = 'block';
}

function hideAchievementInfo() {
    const infoBox = document.getElementById('achievementInfoBox');
    infoBox.classList.add('hidden');
}

document.addEventListener('click', (event) => {
    const achievementsTab = document.getElementById('achievements');
    if (achievementsTab && !achievementsTab.contains(event.target)) {
        // Optionally hide or reset achievement info here if needed
    }
});


function createAchievementsTab() {
    const achievementsTab = document.createElement('div');
    achievementsTab.id = 'achievements';
    achievementsTab.classList.add('tab-content');
    achievementsTab.innerHTML = `
        <div class="achievements-container">
            <div id="achievementsGrid" class="achievements-grid"></div>
            <div id="achievementInfoBox" class="achievement-info-box">
                <img id="achievementImage" src="" alt="Achievement">
                <h3 id="achievementName"></h3>
                <p id="achievementDescription"></p>
                <div id="achievementUnlocks">
                    <h4>Unlocks:</h4>
                    <div id="unlockedClasses"></div>
                    <div id="unlockedSkins"></div>
                </div>
            </div>
        </div>
    `;
    return achievementsTab;
}


function initShop() {
    let shopButton = document.getElementById('shopButton');
    if (!shopButton) {
        shopButton = document.createElement('button');
        shopButton.id = 'shopButton';
        shopButton.textContent = 'Shop';
        shopButton.classList.add('game-button');
        shopButton.style.display = 'none'; // Hide by default
        shopButton.addEventListener('click', toggleShop);
        document.body.appendChild(shopButton);
    }

    let shopWidget = document.getElementById('shopWidget');
    if (!shopWidget) {
        shopWidget = document.createElement('div');
        shopWidget.id = 'shopWidget';
        shopWidget.classList.add('hidden');
        shopWidget.innerHTML = `
            <div class="widget-tabs">
                <button class="tab-button active" data-tab="shop">Shop</button>
            </div>
            <div class="widget-content">
                <div id="shop" class="tab-content active">
                    <div id="weaponInfoBox">
                        <div id="weaponImage"></div>
                        <div id="weaponDetails">
                            <h3 id="weaponName"></h3>
                            <div id="weaponStats"></div>
                            <button id="buyWeaponButton" class="buy-button">Buy</button>
                        </div>
                    </div>
                    <div id="weaponSelector"></div>
                </div>
            </div>
            <button class="close-button">Close</button>
        `;
        document.body.appendChild(shopWidget);
    }

    shopWidget.querySelector('.close-button').addEventListener('click', hideShop);
    
    // Add event listener for the shop tab button
    const shopTabButton = shopWidget.querySelector('.tab-button[data-tab="shop"]');
    shopTabButton.addEventListener('click', () => showShopTab('shop'));
}

function showShopTab(tabName) {
    const shopWidget = document.getElementById('shopWidget');
    const tabContents = shopWidget.querySelectorAll('.tab-content');
    const tabButtons = shopWidget.querySelectorAll('.tab-button');

    tabContents.forEach(content => content.classList.remove('active'));
    tabButtons.forEach(button => button.classList.remove('active'));

    const selectedTab = shopWidget.querySelector(`#${tabName}`);
    const selectedButton = shopWidget.querySelector(`.tab-button[data-tab="${tabName}"]`);

    if (selectedTab && selectedButton) {
        selectedTab.classList.add('active');
        selectedButton.classList.add('active');
    }
}


function showShopButton() {
    const shopButton = document.getElementById('shopButton');
    if (shopButton) {
        shopButton.style.display = 'block';
    } else {
        console.error('Shop button not found in the DOM');
    }
}



function toggleShop() {
    const shopWidget = document.getElementById('shopWidget');
    if (shopWidget.classList.contains('visible')) {
        hideShop();
    } else {
        showShop();
    }
}

// Add this function to show the shop
function showShop() {
    const shopWidget = document.getElementById('shopWidget');
    shopWidget.classList.remove('hidden');
    shopWidget.classList.add('visible');
    
    // Force a refresh of the shop items
    fetchShopItems().then(() => {
        forceShowShopContent();
        debugShopWidget();
    });
    
    pausePlayer();
}

function forceShowShopContent() {
    const shopWidget = document.getElementById('shopWidget');
    const shopContent = shopWidget.querySelector('#shop');
    const shopTab = shopWidget.querySelector('.tab-button[data-tab="shop"]');

    // Hide all tab contents
    const allTabContents = shopWidget.querySelectorAll('.tab-content');
    allTabContents.forEach(content => content.style.display = 'none');

    // Deactivate all tabs
    const allTabs = shopWidget.querySelectorAll('.tab-button');
    allTabs.forEach(tab => tab.classList.remove('active'));

    // Show shop content and activate shop tab
    if (shopContent) {
        shopContent.style.display = 'block';
    }
    if (shopTab) {
        shopTab.classList.add('active');
    }
}



// Add this function to hide the shop
function hideShop() {
    const shopWidget = document.getElementById('shopWidget');
    shopWidget.classList.remove('visible');
    shopWidget.classList.add('hidden');
    unpausePlayer();
}

function fetchShopItems() {
    if (!player || !player.playerClass || !player.playerClass._id) {
        console.error('Player or player class not initialized');
        return Promise.resolve();
    }

    return fetch('/get-shop-items', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({ player_class: player.playerClass._id }),
    })
    .then(response => response.json())
    .then(weapons => {
        displayShopItems(weapons);
    })
    .catch(error => {
        console.error('Error fetching shop items:', error);
    });
}



// Add this function to display shop items
function displayShopItems(weapons) {
    const weaponSelector = document.getElementById('weaponSelector');
    if (!weaponSelector) {
        console.error('Weapon selector not found');
        return;
    }
    weaponSelector.innerHTML = ''; // Clear existing content

    weapons.forEach(weapon => {
        const weaponOption = document.createElement('div');
        weaponOption.classList.add('weapon-option');
        weaponOption.innerHTML = `<img src="${weapon.image_source}" alt="${weapon.name}">`;
        weaponOption.addEventListener('click', () => selectWeapon(weapon, weaponOption));
        weaponSelector.appendChild(weaponOption);
    });

    if (weapons.length > 0) {
        selectWeapon(weapons[0], weaponSelector.firstChild);
    } else {
        debugLog('No weapons available in the shop');
    }
}


function selectWeapon(weapon, selectedElement) {
    const weaponOptions = document.querySelectorAll('.weapon-option');
    weaponOptions.forEach(option => option.classList.remove('selected'));
    selectedElement.classList.add('selected');

    const weaponImage = document.getElementById('weaponImage');
    const weaponName = document.getElementById('weaponName');
    const weaponStats = document.getElementById('weaponStats');
    const buyButton = document.getElementById('buyWeaponButton');

    if (weaponImage && weaponName && weaponStats && buyButton) {
        weaponImage.innerHTML = `<img src="${weapon.image_source}" alt="${weapon.name}">`;
        weaponName.textContent = weapon.name;
        weaponStats.innerHTML = `
            <p>Damage: ${weapon.base_attributes.damage}</p>
            <p>Fire Rate: ${weapon.base_attributes.fire_rate}</p>
            <p>Bullet Speed: ${weapon.base_attributes.bullet_speed}</p>
            <p>Bullet Size: ${weapon.base_attributes.bullet_size}</p>
            <p>Price: ${weapon.price} Synth Coins</p>
        `;
        buyButton.onclick = () => buyWeapon(weapon);
    } else {
        console.error('One or more weapon info elements not found');
    }
}



// Add this function to create a shop item element
function createShopItemElement(weapon) {
    const itemElement = document.createElement('div');
    itemElement.classList.add('shop-item');
    itemElement.innerHTML = `
        <img src="${weapon.image_source}" alt="${weapon.name}">
        <h3>${weapon.name}</h3>
        <p>Price: ${weapon.price} Synth Coins</p>
        <button class="buy-button" data-weapon-id="${weapon._id}">Buy</button>
    `;

    const buyButton = itemElement.querySelector('.buy-button');
    buyButton.addEventListener('click', () => buyWeapon(weapon));

    return itemElement;
}

// Add this function to handle weapon purchase
function buyWeapon(weapon) {
    fetch('/buy-weapon', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            player_id: socket.id,
            weapon_id: weapon._id,
        }),
    })
    .then(response => response.json())
    .then(data => {
        if (data.success) {
            debugLog('Weapon purchase successful:', data);
            player.synthCoins = data.updatedPlayerData.synth_coins;
            player.weapons = data.updatedPlayerData.weapons;
            player.loadWeaponImages();
            player.weaponAngles = player.weapons.map(() => 0);
            player.lastShootTimes = player.weapons.map(() => 0);
            updateSynthCoinsDisplay();
            notificationSystem.showNotification('Weapon purchased successfully!');
            fetchShopItems(); // Refresh shop items
        } else {
            notificationSystem.showNotification(data.message);
        }
    })
    .catch(error => {
        console.error('Error buying weapon:', error);
        notificationSystem.showNotification('An error occurred while purchasing the weapon: ' + error.message);
    });
}





function loadAndCacheImage(src) {
    if (imageCache.has(src)) {
        return imageCache.get(src);
    }
    const img = new Image();
    img.src = src;
    img.onerror = () => {
        console.error(`Failed to load image: ${src}`);
        imageCache.set(src, null);
    };
    imageCache.set(src, img);
    return img;
}


function preloadBulletImage(src) {
    if (bulletImageCache.has(src)) {
        return bulletImageCache.get(src);
    }
    const img = new Image();
    img.src = src;
    bulletImageCache.set(src, img);
    return img;
}

function preloadEnemyImages() {
    fetch('/get-enemy-images')
        .then(response => response.json())
        .then(images => {
            images.forEach(imageSrc => {
                if (!enemyImageCache.has(imageSrc)) {
                    const img = new Image();
                    img.src = imageSrc;
                    enemyImageCache.set(imageSrc, img);
                }
            });
        })
        .catch(error => console.error('Error preloading enemy images:', error));
}


class Camera {
    constructor(width, height) {
        this.x = 0;
        this.y = 0;
        this.width = width;
        this.height = height;
    }

    follow(player) {
        this.x = Math.floor(player.x - this.width / 2);
        this.y = Math.floor(player.y - this.height / 2);
        this.x = Math.max(0, Math.min(this.x, MAP_WIDTH - this.width));
        this.y = Math.max(0, Math.min(this.y, MAP_HEIGHT - this.height));
    }

}

// Add this new class for managing trails
class Trail {
    constructor(maxLength = 10) {
        this.positions = [];
        this.maxLength = maxLength;
    }

    update(x, y) {
        this.positions.unshift({x, y});
        if (this.positions.length > this.maxLength) {
            this.positions.pop();
        }
    }

    draw(ctx, color) {
        if (!ctx) {
            console.error('Canvas context is undefined in Trail.draw');
            return;
        }
        for (let i = 0; i < this.positions.length; i++) {
            const alpha = 1 - (i / this.positions.length);
            ctx.beginPath();
            ctx.arc(this.positions[i].x, this.positions[i].y, 5, 0, Math.PI * 2);
            ctx.fillStyle = `rgba(${color[0]}, ${color[1]}, ${color[2]}, ${alpha})`;
            ctx.fill();
            ctx.closePath();
        }
    }
}

class Skin {
    constructor(type, color, shape) {
        this.type = type;
        this.color = color;
        this.shape = shape;
        this.animationPhase = 0;
    }

    update() {
        this.animationPhase = (this.animationPhase + 0.1) % (2 * Math.PI);
    }

    draw(ctx, x, y, radius) {
        ctx.save();
        ctx.translate(x, y);

        switch (this.shape) {
            case 'circle':
                this.drawCircle(ctx, radius);
                break;
            case 'triangle':
                this.drawTriangle(ctx, radius);
                break;
            case 'square':
                this.drawSquare(ctx, radius);
                break;
            default:
                this.drawCircle(ctx, radius);
        }

        ctx.restore();
    }

    drawCircle(ctx, radius) {
        ctx.beginPath();
        ctx.arc(0, 0, radius, 0, Math.PI * 2);
        ctx.fillStyle = this.color;
        ctx.fill();
        ctx.closePath();

        // Add pulsating effect
        const pulseRadius = radius * (1 + 0.1 * Math.sin(this.animationPhase));
        ctx.beginPath();
        ctx.arc(0, 0, pulseRadius, 0, Math.PI * 2);
        ctx.strokeStyle = this.color;
        ctx.lineWidth = 2;
        ctx.stroke();
        ctx.closePath();
    }

    drawTriangle(ctx, radius) {
        ctx.beginPath();
        ctx.moveTo(0, -radius);
        ctx.lineTo(-radius * Math.sqrt(3) / 2, radius / 2);
        ctx.lineTo(radius * Math.sqrt(3) / 2, radius / 2);
        ctx.closePath();
        ctx.fillStyle = this.color;
        ctx.fill();

        // Add rotating effect
        ctx.save();
        ctx.rotate(this.animationPhase);
        ctx.beginPath();
        ctx.moveTo(0, -radius * 1.2);
        ctx.lineTo(-radius * Math.sqrt(3) / 2 * 1.2, radius / 2 * 1.2);
        ctx.lineTo(radius * Math.sqrt(3) / 2 * 1.2, radius / 2 * 1.2);
        ctx.closePath();
        ctx.strokeStyle = this.color;
        ctx.lineWidth = 2;
        ctx.stroke();
        ctx.restore();
    }

    drawSquare(ctx, radius) {
        ctx.beginPath();
        ctx.rect(-radius, -radius, radius * 2, radius * 2);
        ctx.fillStyle = this.color;
        ctx.fill();
        ctx.closePath();

        // Add spinning effect
        ctx.save();
        ctx.rotate(this.animationPhase);
        ctx.beginPath();
        ctx.rect(-radius * 1.2, -radius * 1.2, radius * 2.4, radius * 2.4);
        ctx.strokeStyle = this.color;
        ctx.lineWidth = 2;
        ctx.stroke();
        ctx.restore();
    }
}


// Update the Player class
class Player {
    constructor(x, y, name, skinData, weapons, playerClass, ctx) {
        this.x = x;
        this.y = y;
        this.name = name;
        this.radius = 20;
        this.maxSpeed = playerClass?.base_attributes?.speed || 5; // Default to 5 if undefined
        this.velocityX = 0;
        this.velocityY = 0;
        this.keys = { up: false, down: false, left: false, right: false };
        this.trail = new Trail();
        this.setSkin(skinData);
        this.weapons = Array.isArray(weapons) ? weapons : (weapons ? [weapons] : []);
        this.lastShootTimes = this.weapons.map(() => 0);
        this.weaponImages = new Map();
        this.currentWeaponIndex = 0;
        this.weaponAngle = 0;
        this.weaponAngles = this.weapons.map(() => 0);
        this.orbitRadius = 40; // Distance of weapons from player center
        this.playerClass = playerClass || {}; // Default to empty object if undefined
        this.playerClassImage = playerClass ? loadAndCacheImage(playerClass.image_source) : null;
        this.health = playerClass?.base_attributes?.health || 100; // Default to 100 if undefined
        this.damageMultiplier = playerClass?.base_attributes?.damage_multiplier || 1; // Default to 1 if undefined
        this.level = 1;
        this.lastShootTime = 0;
        this.ctx = ctx;
        this.experience = 0;
        this.maxExperience = 100;
        this.isPaused = false;
        this.synthCoins = 0;
        this.maxHealth = playerClass.base_attributes.health;
        this.currentHealth = this.maxHealth;
        this.healthRegen = playerClass.base_attributes.health_regen || 1;
        this.isShooting = false;
        this.mouseX = 0;
        this.mouseY = 0;
        this.autoFireEnabled = false;

    }

    loadWeaponImages() {
        this.weapons.forEach(weapon => {
            if (weapon && weapon.image_source) {
                this.loadWeaponImage(weapon.image_source);
            }
        });
    }

    loadWeaponImage(imageSrc) {
        if (!this.weaponImages.has(imageSrc)) {
            const img = new Image();
            img.src = imageSrc;
            img.onload = () => {
                this.weaponImages.set(imageSrc, img);
            };
            img.onerror = () => {
                console.error(`Failed to load weapon image: ${imageSrc}`);
            };
        }
    }


    setSkin(skinData) {
        this.skin = skinData;
        if (this.skin && this.skin.hat) {
            this.loadHatImage();  // Call this method to load the hat image
        }
    }

    getCurrentWeapon() {
        return this.weapons[this.currentWeaponIndex];
    }

    upgradeWeapon(attribute, value) {
        const currentWeapon = this.getCurrentWeapon();
        if (currentWeapon && currentWeapon.base_attributes) {
            if (attribute in currentWeapon.base_attributes) {
                currentWeapon.base_attributes[attribute] += value;
                debugLog(`Upgraded ${attribute} to ${currentWeapon.base_attributes[attribute]}`);
            } else {
                console.error(`Attribute ${attribute} not found in weapon attributes`);
            }
        } else {
            console.error('Current weapon or base attributes not found');
        }
    }
    
    loadHatImage() {
        if (this.skin.hat && this.skin.hat.value) {
            this.hatImage = new Image();
            this.hatImage.src = this.skin.hat.value;
            this.hatImage.onload = () => {
                debugLog(`Hat image loaded for player ${this.name}`);
            };
        }
    }

    updateHealth() {
        // Health update logic will be handled by the server
        // This method is here for potential client-side predictions or interpolations
    }



    update() {
        if (this.keys.up) this.velocityY -= 0.5;
        if (this.keys.down) this.velocityY += 0.5;
        if (this.keys.left) this.velocityX -= 0.5;
        if (this.keys.right) this.velocityX += 0.5;

        this.velocityX *= 0.95;
        this.velocityY *= 0.95;

        const speed = Math.sqrt(this.velocityX * this.velocityX + this.velocityY * this.velocityY);
        if (speed > this.maxSpeed) {
            const ratio = this.maxSpeed / speed;
            this.velocityX *= ratio;
            this.velocityY *= ratio;
        }

        this.x += this.velocityX;
        this.y += this.velocityY;

        this.x = Math.max(this.radius, Math.min(MAP_WIDTH - this.radius, this.x));
        this.y = Math.max(this.radius, Math.min(MAP_HEIGHT - this.radius, this.y));

        this.trail.update(this.x, this.y);
        this.updateWeaponAngle();
        this.updateHealth();

    }

    updateWeaponAngle(nearestEnemy) {
        if (this.autoFireEnabled && nearestEnemy) {
            const targetAngle = Math.atan2(nearestEnemy.y - this.y, nearestEnemy.x - this.x);
            this.weaponAngles = this.weaponAngles.map((angle, index) => {
                const baseAngle = (index / this.weapons.length) * Math.PI * 2;
                return lerpAngle(angle, targetAngle + baseAngle, 0.1);
            });
        }
    }

    findNearestEnemy() {
        return findNearestEnemy();
    }

    draw() {
        if (!this.ctx) {
            console.error('Canvas context is undefined in Player.draw for player:', this.name);
            return;
        }
        this.trail.draw(this.ctx, [0, 255, 255]);
        
        // Apply color effect if any
        if (this.skin && this.skin.color && this.skin.color.effect === 'glow') {
            this.ctx.beginPath();
            this.ctx.arc(this.x, this.y, this.radius + 5, 0, Math.PI * 2);
            this.ctx.fillStyle = `${this.skin.color.value}33`;
            this.ctx.fill();
            this.ctx.closePath();
        }
    
        // Draw player class image
        if (this.playerClassImage && this.playerClassImage.complete) {
            this.ctx.save();
            this.ctx.translate(this.x, this.y);
            
            // Apply glow effect to the class image if present
            if (this.skin && this.skin.color && this.skin.color.effect === 'glow') {
                this.ctx.shadowColor = this.skin.color.value;
                this.ctx.shadowBlur = 10;
            }
            
            this.ctx.drawImage(this.playerClassImage, -this.radius, -this.radius, this.radius * 2, this.radius * 2);
            this.ctx.restore();
        }
    
        // Draw weapon
        if (this.weaponImage && this.weaponImage.complete) {
            this.ctx.drawImage(this.weaponImage, this.x + this.radius, this.y - this.radius / 2, this.radius, this.radius);
        }
    
        // Draw hat if present
        this.drawHat();
    
        // Set font for all text
        this.ctx.font = '12px Orbitron';
        this.ctx.textAlign = 'center';
        this.ctx.fillStyle = 'white';
    
        // Draw player name
        this.ctx.fillText(this.name, this.x, this.y - this.radius - 5);
    
        // Draw player level
        this.ctx.fillText(`Lvl ${this.level}`, this.x, this.y - this.radius - 20);
    
        // Draw paused indicator if the player is paused
        if (this.isPaused) {
            this.ctx.font = '16px Orbitron';
            this.ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
            this.ctx.fillText('PAUSED', this.x, this.y - this.radius - 30);
        }
    
        this.drawWeapons();
        this.drawHealthBar();
    }

    drawHealthBar() {
        const barWidth = this.radius * 2;
        const barHeight = 5;
        const x = this.x - this.radius;
        const y = this.y + this.radius + 5;

        // Draw background
        this.ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
        this.ctx.fillRect(x, y, barWidth, barHeight);

        // Draw health
        const healthPercentage = this.currentHealth / this.maxHealth;
        this.ctx.fillStyle = `rgb(${255 - healthPercentage * 255}, ${healthPercentage * 255}, 0)`;
        this.ctx.fillRect(x, y, barWidth * healthPercentage, barHeight);
    }


    addWeapon(weapon) {
        this.weapons.push(weapon);
        this.weaponAngles.push(0);
        this.lastShootTimes.push(0);
        if (weapon && weapon.image_source) {
            this.loadWeaponImage(weapon.image_source);
        }
    }

    updateWeaponPositions() {
        const angleStep = (2 * Math.PI) / this.weapons.length;
        this.weaponAngles = this.weapons.map((_, index) => index * angleStep);
    }



    drawWeapons() {
        this.weapons.forEach((weapon, index) => {
            if (weapon && weapon.image_source) {
                const angle = this.weaponAngles[index];
                const weaponX = this.x + Math.cos(angle) * this.orbitRadius;
                const weaponY = this.y + Math.sin(angle) * this.orbitRadius;
    
                const img = this.weaponImages.get(weapon.image_source);
                if (img && img.complete) {
                    this.ctx.save();
                    this.ctx.translate(weaponX, weaponY);
                    this.ctx.rotate(angle);
                    this.ctx.drawImage(img, -this.radius / 2, -this.radius / 2, this.radius, this.radius);
                    this.ctx.restore();
                }
            }
        });
    }

    setWeaponAngle(angle) {
        this.weaponAngle = angle;
        this.weaponAngles = this.weapons.map(() => angle);
    }

    drawHat() {
        if (this.hatImage && this.hatImage.complete) {
            const hatSize = this.radius * 1.5;
            const hatOffsetY = this.radius * 0.9; // Adjust this value to move the hat up or down
            this.ctx.drawImage(
                this.hatImage,
                this.x - hatSize / 2,
                this.y - this.radius - hatOffsetY, // Changed this line
                hatSize,
                hatSize
            );
        } else if (this.skin && this.skin.hat) {
            debugLog(`Hat image not loaded for player ${this.name}`);
        }
    }

    updateWeaponAngleToMouse() {
        if (this.mouseX && this.mouseY) {
            const dx = this.mouseX - this.x;
            const dy = this.mouseY - this.y;
            const angle = Math.atan2(dy, dx);
            this.setWeaponAngle(angle);
            
            // Send weapon angle update to server
            socket.emit('player_update', { 
                x: this.x, 
                y: this.y,
                weapon_angles: this.weaponAngles,
                auto_fire_enabled: isAutoFireEnabled
            });
        }
    }


    shoot(currentTime) {
        if (this.isPaused) return;

        const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);

        this.weapons.forEach((weapon, index) => {
            if (!weapon || !weapon.base_attributes) {
                console.error('Invalid weapon structure:', weapon);
                return;
            }

            const fireRate = weapon.base_attributes.fire_rate || 1;
            if (currentTime - this.lastShootTimes[index] > 1000 / fireRate) {
                let shootAngle;
                if (isAutoFireEnabled) {
                    const nearestEnemy = findNearestEnemy();
                    shootAngle = nearestEnemy ? Math.atan2(nearestEnemy.y - this.y, nearestEnemy.x - this.x) : this.weaponAngle;
                } else {
                    shootAngle = this.weaponAngle;
                }

                const weaponX = this.x + Math.cos(this.weaponAngles[index]) * this.orbitRadius;
                const weaponY = this.y + Math.sin(this.weaponAngles[index]) * this.orbitRadius;

                if ((isMobile && this.isShooting) || (!isMobile && (this.isShooting || isAutoFireEnabled))) {
                    socket.emit('player_shoot', { angle: shootAngle, weaponX, weaponY, weaponIndex: index });
                    this.lastShootTimes[index] = currentTime;
                }
            }
        });
    }
}

// Add this function to draw the UI
function drawUI() {
}



// Add a new Enemy class
class Enemy {
    constructor(data) {
        this.id = data.id;
        this.name = data.name;
        this.x = data.x;
        this.y = data.y;
        this.image = data.image;
        this.attributes = data.attributes;
        this.difficulty = data.difficulty;
        this.currentHealth = data.current_health;
        this.maxHealth = data.attributes.health;
        this.experience = data.experience;
        this.trail = new Trail();
        this.loadImage();
    }

    loadImage() {
        if (!enemyImageCache.has(this.image)) {
            const img = new Image();
            img.src = this.image;
            enemyImageCache.set(this.image, img);
        }
    }

    update() {
        this.trail.update(this.x, this.y);
    }

    draw(ctx) {
        this.trail.draw(ctx, [255, 0, 0]); // Red trail for enemies
        const img = enemyImageCache.get(this.image);
        if (img && img.complete) {
            ctx.drawImage(img, this.x - 15, this.y - 15, 30, 30); // Assuming enemy size is 30x30
        } else {
            // Fallback to a colored circle if image is not loaded
            ctx.beginPath();
            ctx.arc(this.x, this.y, 15, 0, Math.PI * 2);
            ctx.fillStyle = 'red';
            ctx.fill();
            ctx.closePath();
        }

        // Draw health bar
        const healthBarWidth = 30;
        const healthBarHeight = 4;
        const healthPercentage = this.currentHealth / this.maxHealth;
        ctx.fillStyle = 'red';
        ctx.fillRect(this.x - healthBarWidth / 2, this.y - 20, healthBarWidth, healthBarHeight);
        ctx.fillStyle = 'green';
        ctx.fillRect(this.x - healthBarWidth / 2, this.y - 20, healthBarWidth * healthPercentage, healthBarHeight);
    }
}


function init() {
    camera = new Camera(canvas.width, canvas.height);
    initAudio();
    initDraggableElements();

    const autoFireCheckbox = document.getElementById('autoFireCheckbox');
    autoFireCheckbox.addEventListener('change', (e) => {
        isAutoFireEnabled = e.target.checked;
        if (isDebugging) {
            console.log('[DEBUG] Auto Fire ' + (isAutoFireEnabled ? 'enabled' : 'disabled'));
        }
    });


    // Set up background canvas
    backgroundCanvas = document.createElement('canvas');
    backgroundCanvas.width = canvas.width;
    backgroundCanvas.height = canvas.height;
    backgroundCtx = backgroundCanvas.getContext('2d');
    backgroundCtx.fillStyle = 'rgb(18, 4, 88)';
    backgroundCtx.fillRect(0, 0, backgroundCanvas.width, backgroundCanvas.height);

    uiButton = document.getElementById('uiButton');
    uiWidget = document.getElementById('uiWidget');
    menuButton = document.getElementById('menuButton');

    if (uiButton) uiButton.addEventListener('click', toggleWidget);
    if (menuButton) menuButton.addEventListener('click', toggleWidget);


    uiButton.addEventListener('click', toggleWidget);
    menuButton.addEventListener('click', toggleWidget);

    minimapCanvas = document.getElementById('minimap');
    minimapCtx = minimapCanvas.getContext('2d');
    
    const toggleMinimapButton = document.getElementById('toggle-minimap');
    toggleMinimapButton.addEventListener('click', toggleMinimap);

    const debugCheckbox = document.getElementById('debugCheckbox');
    debugCheckbox.addEventListener('change', (e) => {
        isDebugging = e.target.checked;
        if (isDebugging) {
            console.log('[DEBUG] Debugging mode enabled');
        } else {
            console.log('Debugging mode disabled');
        }
    });

    canvas.addEventListener('mousedown', (e) => {
        if (!isAutoFireEnabled && player) {
            player.isShooting = true;
        }
    });

    canvas.addEventListener('mouseup', (e) => {
        if (!isAutoFireEnabled && player) {
            player.isShooting = false;
        }
    });

    canvas.addEventListener('mousemove', (e) => {
        if (!isAutoFireEnabled && player) {
            updatePlayerAim(e.clientX, e.clientY);
        }
    });
    
    
            
    const tabButtons = document.querySelectorAll('.tab-button');
    tabButtons.forEach(button => {
        button.addEventListener('click', () => {
            const tabName = button.getAttribute('data-tab');
            if (tabName === 'close') {
                hideWidget();
            } else {
                showTab(tabName);
            }
        });
    });

    const closeButtons = document.querySelectorAll('.close-button');
    closeButtons.forEach(button => {
        button.addEventListener('click', () => {
            hideClassSelector();
            hideWidget();
            hideInfoWidget();
        });
    });

    // Focus
    // document.addEventListener('click', handleOutsideClick);

    const classSelectorButton = document.getElementById('classSelectorButton');
    if (classSelectorButton) classSelectorButton.addEventListener('click', showClassSelector);
    classSelectorButton.addEventListener('click', showClassSelector);

    checkSession();
    initShop();


    // Add event listeners for auth buttons
    document.getElementById('signupButton').addEventListener('click', showSignupForm);
    document.getElementById('loginButton').addEventListener('click', showLoginForm);
    document.getElementById('logoutButton').addEventListener('click', logout);
    document.getElementById('submitSignup').addEventListener('click', signup);
    document.getElementById('submitLogin').addEventListener('click', login);

    // Add input validation listeners
    document.getElementById('signupUsername').addEventListener('input', validateSignupInput);
    document.getElementById('signupEmail').addEventListener('input', validateSignupInput);
    document.getElementById('signupPassword').addEventListener('input', validateSignupInput);
    
    infoButton.addEventListener('click', toggleInfoWidget);

    const classWidgetTabs = document.querySelectorAll('#classWidget .widget-tabs .tab-button');
    classWidgetTabs.forEach(tab => {
        tab.addEventListener('click', function() {
            const tabName = this.getAttribute('data-tab');
            showTab(tabName, 'classWidget');
        });
    });

    
    const infoTabButtons = infoWidget.querySelectorAll('.tab-button');
    infoTabButtons.forEach(button => {
        button.addEventListener('click', () => {
            const tabName = button.getAttribute('data-tab');
            showInfoTab(tabName);
        });
    });

    infoWidget.querySelector('.close-button').addEventListener('click', hideInfoWidget);
    stopPropagationOnUIElements();
}

function debugLog(...args) {
    if (isDebugging) {
        console.log('[DEBUG]', ...args);
    }
}




function updateSynthCoinsDisplay() {
    if (!gameStarted) return;

    const counter = document.getElementById('synthCoinsCounter');
    if (!counter) {
        const newCounter = document.createElement('canvas');
        newCounter.id = 'synthCoinsCounter';
        document.body.appendChild(newCounter);
    }

    const counterCanvas = document.getElementById('synthCoinsCounter');
    const counterCtx = counterCanvas.getContext('2d');

    const text = `Synth Coins: ${player ? player.synthCoins : 0}`;
    counterCtx.font = '16px Orbitron';
    const textWidth = counterCtx.measureText(text).width;

    counterCanvas.width = textWidth + 20;
    counterCanvas.height = 30;

    counterCtx.fillStyle = '#FFD700';
    counterCtx.font = '16px Orbitron';
    counterCtx.textAlign = 'left';
    counterCtx.textBaseline = 'middle';

    counterCtx.shadowColor = '#FFD700';
    counterCtx.shadowBlur = 5;
    counterCtx.fillText(text, 10, counterCanvas.height / 2);

    counterCtx.shadowBlur = 0;
}




function showClassSelector() {
    const classWidget = document.getElementById('classWidget');
    classWidget.classList.add('visible');
    selectClassesTab();
    fetchAndDisplayClasses();
}

function selectClassesTab() {
    // Select the "Classes" tab
    const classesTab = document.querySelector('.widget-tabs .tab-button[data-tab="classes"]');
    if (classesTab) {
        classesTab.classList.add('active'); // Add active class instead of simulating click
    }

    // Show the "Classes" content
    showTab('classes'); // Use the existing showTab function
}


function hideClassSelector() {
    const classWidget = document.getElementById('classWidget');
    classWidget.classList.remove('visible');
}

function fetchAndDisplayClasses() {
    fetch('/get-available-classes', {
        headers: {
            'Authorization': getSessionToken()
        }
    })
    .then(response => response.json())
    .then(classes => {
        // Sort classes: unlocked first, then locked
        classes.sort((a, b) => {
            if (a.unlocked === b.unlocked) return 0;
            return a.unlocked ? -1 : 1;
        });

        const classSelector = document.getElementById('classSelector');
        classSelector.innerHTML = '';
        
        classes.forEach(playerClass => {
            const classOption = document.createElement('div');
            classOption.classList.add('class-option');
            if (playerClass._id === selectedClassId) {
                classOption.classList.add('selected');
            }
            classOption.innerHTML = `<img src="${playerClass.image_source}" alt="${playerClass.name}">`;
            
            if (!playerClass.unlocked) {
                classOption.classList.add('locked');
                const lockOverlay = document.createElement('div');
                lockOverlay.classList.add('lock-overlay');
                lockOverlay.innerHTML = '<i class="fas fa-lock"></i>';
                classOption.appendChild(lockOverlay);
            }
            
            classOption.addEventListener('click', () => selectClass(playerClass));
            classOption.addEventListener('mouseover', () => displayClassInfo(playerClass));
            classSelector.appendChild(classOption);
        });
        
        // Display info for the first unlocked class by default
        const firstUnlockedClass = classes.find(c => c.unlocked);
        if (firstUnlockedClass) {
            displayClassInfo(firstUnlockedClass);
        } else if (classes.length > 0) {
            displayClassInfo(classes[0]);
        }
    })
    .catch(error => console.error('Error loading classes:', error));
}



function displayClassInfo(playerClass) {
    const classImage = document.getElementById('classImage');
    const className = document.getElementById('className');
    const classStats = document.getElementById('classStats');

    classImage.innerHTML = `<img src="${playerClass.image_source}" alt="${playerClass.name}">`;
    className.textContent = playerClass.name;
    classStats.innerHTML = `
        <p>Health: ${playerClass.base_attributes.health}</p>
        <p>Speed: ${playerClass.base_attributes.speed}</p>
        <p>Damage: ${playerClass.base_attributes.damage_multiplier}</p>
    `;

    // Remove the locked indicator if the class is unlocked
    if (playerClass.unlocked) {
        className.innerHTML = playerClass.name;
    } else {
        className.innerHTML = `${playerClass.name} <span class="locked-indicator">(Locked)</span>`;
    }
}




function handleLevelUp() {
    const upgradeOptions = getRandomUpgradeOptions(3);
    showLevelUpPopup(upgradeOptions);
}

function getRandomUpgradeOptions(count) {
    const allUpgrades = [
        { type: 'bullet_speed', name: 'Bullet Speed', value: 1 },
        { type: 'bullet_size', name: 'Bullet Size', value: 1 },
        { type: 'damage', name: 'Damage', value: 2 },
        { type: 'fire_rate', name: 'Fire Rate', value: 0.1 }
    ];
    return shuffleArray(allUpgrades).slice(0, count);
}


function shuffleArray(array) {
    for (let i = array.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [array[i], array[j]] = [array[j], array[i]];
    }
    return array;
}

function pausePlayer() {
    if (!isPlayerPaused) {
        isPlayerPaused = true;
        player.isPaused = true;
        socket.emit('player_paused', { isPaused: true });
    }
}

function unpausePlayer() {
    if (isPlayerPaused && !areInterfacesOpen()) {
        isPlayerPaused = false;
        player.isPaused = false;
        socket.emit('player_paused', { isPaused: false });
    }
}


function showLevelUpPopup(options) {
    openInterfaces.levelUp = true;
    pausePlayer();
    const popup = document.createElement('div');
    popup.id = 'levelUpPopup';
    popup.innerHTML = `
        <h2>Level Up!</h2>
        <p>Choose an upgrade:</p>
        <div id="upgradeOptions"></div>
    `;
    document.body.appendChild(popup);

    const upgradeOptions = document.getElementById('upgradeOptions');
    options.forEach((option, index) => {
        const button = document.createElement('button');
        button.classList.add('upgrade-button');
        button.innerHTML = `
            <span class="upgrade-name">${option.name}</span>
            <span class="upgrade-value">+${option.value}</span>
        `;
        button.onclick = () => selectUpgrade(option, index);
        upgradeOptions.appendChild(button);
    });

    // Add slot machine effect
    slotMachineEffect(options, upgradeOptions);
}

function slotMachineEffect(options, container) {
    const duration = 2000; // 2 seconds
    const interval = 100; // 0.1 second per change
    let elapsed = 0;

    const intervalId = setInterval(() => {
        elapsed += interval;
        if (elapsed < duration) {
            container.innerHTML = '';
            getRandomUpgradeOptions(3).forEach(option => {
                const div = document.createElement('div');
                div.classList.add('upgrade-option');
                div.innerHTML = `
                    <span class="upgrade-name">${option.name}</span>
                    <span class="upgrade-value">+${option.value}</span>
                `;
                container.appendChild(div);
            });
        } else {
            clearInterval(intervalId);
            container.innerHTML = '';
            options.forEach((option, index) => {
                const button = document.createElement('button');
                button.classList.add('upgrade-button');
                button.innerHTML = `
                    <span class="upgrade-name">${option.name}</span>
                    <span class="upgrade-value">+${option.value}</span>
                `;
                button.onclick = () => selectUpgrade(option, index);
                container.appendChild(button);
            });
        }
    }, interval);
}


function selectUpgrade(upgrade, index) {
    const popup = document.getElementById('levelUpPopup');
    popup.classList.add('fade-out');
    setTimeout(() => {
        popup.remove();
        openInterfaces.levelUp = false;
        unpausePlayer();
    }, 500);
    // Send both the upgrade details and the index
    socket.emit('upgrade_selected', { 
        upgradeIndex: index,
        upgradeType: upgrade.type,
        upgradeValue: upgrade.value
    });
}



function areInterfacesOpen() {
    return openInterfaces.menu || openInterfaces.levelUp || isShopVisible;
    // Add any other interface checks as needed
}


function drawExperienceBar() {
    if (!gameStarted) return;

    const expBar = document.getElementById('experienceBar');
    if (!expBar) {
        const newExpBar = document.createElement('canvas');
        newExpBar.id = 'experienceBar';
        document.body.appendChild(newExpBar);
    }

    const expBarCanvas = document.getElementById('experienceBar');
    const expBarCtx = expBarCanvas.getContext('2d');

    const mapButton = document.getElementById('toggle-minimap');
    const mapButtonRect = mapButton.getBoundingClientRect();
    const shopButton = document.getElementById('shopButton');
    const shopButtonRect = shopButton.getBoundingClientRect();

    let barWidth = Math.min(window.innerWidth * 0.8, 400);
    const barHeight = Math.max(10, Math.min(window.innerHeight * 0.02, 20));

    // Adjust width and position if on mobile
    if (window.innerWidth <= 600) {
        const availableWidth = window.innerWidth - shopButtonRect.width - mapButtonRect.width - 40; // 40px for padding
        barWidth = Math.min(availableWidth, barWidth);
        expBarCanvas.style.position = 'fixed';
        expBarCanvas.style.left = `${shopButtonRect.right + 10}px`; // 10px padding from shop button
        expBarCanvas.style.bottom = '10px';
    } else {
        expBarCanvas.style.position = 'fixed';
        expBarCanvas.style.left = '50%';
        expBarCanvas.style.bottom = '10px';
        expBarCanvas.style.transform = 'translateX(-50%)';
    }

    expBarCanvas.width = barWidth;
    expBarCanvas.height = barHeight;

    // Draw background
    expBarCtx.fillStyle = 'rgba(0, 0, 0, 0.5)';
    expBarCtx.beginPath();
    expBarCtx.roundRect(0, 0, barWidth, barHeight, barHeight / 2);
    expBarCtx.fill();

    // Draw experience
    const fillWidth = (playerExperience / playerMaxExperience) * barWidth;
    expBarCtx.fillStyle = '#00ffff';
    expBarCtx.beginPath();
    expBarCtx.roundRect(0, 0, fillWidth, barHeight, barHeight / 2);
    expBarCtx.fill();

    // Add glow effect
    expBarCtx.shadowColor = '#00ffff';
    expBarCtx.shadowBlur = 10;
    expBarCtx.beginPath();
    expBarCtx.roundRect(0, 0, fillWidth, barHeight, barHeight / 2);
    expBarCtx.stroke();
    expBarCtx.shadowBlur = 0;

    // Draw text
    expBarCtx.fillStyle = 'white';
    expBarCtx.font = `${Math.max(10, Math.min(barHeight * 0.8, 16))}px Orbitron`;
    expBarCtx.textAlign = 'center';
    expBarCtx.textBaseline = 'middle';
    
    // Adjust text based on available space
    const fullText = `Level ${playerLevel} - ${playerExperience}/${playerMaxExperience} XP`;
    const shortText = `Lvl ${playerLevel} - ${playerExperience}/${playerMaxExperience}`;
    const veryShortText = `Lvl ${playerLevel}`;
    
    let textToShow = fullText;
    if (expBarCtx.measureText(fullText).width > barWidth) {
        textToShow = shortText;
        if (expBarCtx.measureText(shortText).width > barWidth) {
            textToShow = veryShortText;
        }
    }
    
    expBarCtx.fillText(textToShow, barWidth / 2, barHeight / 2);
}




function checkSession() {
    const sessionToken = localStorage.getItem('sessionToken');
    if (sessionToken) {
        // Verify session with server
        fetch('/verify-session', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({ sessionToken }),
        })
        .then(response => response.json())
        .then(data => {
            if (data.valid) {
                currentUser = data.username;
                updateAuthUI(true);
            } else {
                localStorage.removeItem('sessionToken');
                updateAuthUI(false);
            }
        })
        .catch(error => {
            console.error('Error:', error);
            updateAuthUI(false);
        });
    } else {
        updateAuthUI(false);
    }
}

function updateAuthUI(loggedIn) {
    const authButtons = document.getElementById('authButtons');
    const logoutButton = document.getElementById('logoutButton');
    const playButton = document.getElementById('playButton');
    const welcomeMessage = document.getElementById('welcomeMessage');
    const signupForm = document.getElementById('signupForm');
    const loginForm = document.getElementById('loginForm');

    if (loggedIn) {
        authButtons.style.display = 'none';
        logoutButton.style.display = 'block';  // Changed from 'flex' to 'block'
        playButton.textContent = 'Join Game';
        welcomeMessage.textContent = `Welcome to Resonance Rumble, ${currentUser}!`;
        signupForm.style.display = 'none';
        loginForm.style.display = 'none';
    } else {
        authButtons.style.display = 'flex';
        logoutButton.style.display = 'none';
        playButton.textContent = 'Join Game as Guest';
        welcomeMessage.textContent = 'Welcome to Resonance Rumble';
        // Optionally reset forms
        signupForm.style.display = 'none';
        loginForm.style.display = 'none';
    }
}


function showSignupForm() {
    document.getElementById('signupForm').style.display = 'flex';
    document.getElementById('loginForm').style.display = 'none';
}

function showLoginForm() {
    document.getElementById('loginForm').style.display = 'flex';
    document.getElementById('signupForm').style.display = 'none';
}

function validateSignupInput(event) {
    const input = event.target;
    const value = input.value;

    if (input.id === 'signupUsername') {
        // Username validation (e.g., at least 3 characters)
        input.classList.toggle('valid', value.length >= 3);
        input.classList.toggle('invalid', value.length < 3);
    } else if (input.id === 'signupEmail') {
        // Email validation
        const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
        input.classList.toggle('valid', emailRegex.test(value));
        input.classList.toggle('invalid', !emailRegex.test(value));
    } else if (input.id === 'signupPassword') {
        // Password validation (e.g., at least 8 characters)
        input.classList.toggle('valid', value.length >= 8);
        input.classList.toggle('invalid', value.length < 8);
    }
}

function signup() {
    const username = document.getElementById('signupUsername').value;
    const email = document.getElementById('signupEmail').value;
    const password = document.getElementById('signupPassword').value;

    fetch('/signup', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({ username, email, password }),
    })
    .then(response => response.json())
    .then(data => {
        if (data.success) {
            notificationSystem.showNotification('Signup successful! Please log in.');
            showLoginForm();
        } else {
            notificationSystem.showNotification(data.message);
        }
    })
    .catch(error => {
        console.error('Error:', error);
        notificationSystem.showNotification('An error occurred during signup. Please try again.');
    });
}

function login() {
    const username = document.getElementById('loginUsername').value;
    const password = document.getElementById('loginPassword').value;

    fetch('/login', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({ username, password }),
    })
    .then(response => response.json())
    .then(data => {
        if (data.success) {
            localStorage.setItem('sessionToken', data.sessionToken);
            currentUser = username;
            updateAuthUI(true);
        } else {
            notificationSystem.showNotification(data.message);
        }
    })
    .catch(error => {
        console.error('Error:', error);
        notificationSystem.showNotification('An error occurred during login. Please try again.');
    });
}

function logout() {
    localStorage.removeItem('sessionToken');
    currentUser = null;
    updateAuthUI(false);
}

function fetchUnlockedSkins() {
    if (!currentUser) {
        debugLog('No user logged in');
        return;
    }
    debugLog('Fetching unlocked skins for user:', currentUser);
    fetch('/get-unlocked-skins', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({ username: currentUser }),
    })
    .then(response => {
        if (!response.ok) {
            throw new Error('Network response was not ok');
        }
        return response.json();
    })
    .then(unlockedSkins => {
        debugLog('Fetched unlocked skins:', unlockedSkins);
        displayUnlockedSkins(unlockedSkins);
    })
    .catch(error => {
        console.error('Error fetching unlocked skins:', error);
    });
}

function displayUnlockedSkins(unlockedSkins) {
    debugLog('Displaying unlocked skins:', unlockedSkins);
    const colorOptions = document.getElementById('colorOptions');
    const hatOptions = document.getElementById('hatOptions');

    if (!colorOptions || !hatOptions) {
        console.error('Skin customization elements not found in the DOM');
        return;
    }

    debugLog('Color options element:', colorOptions);
    debugLog('Hat options element:', hatOptions);

    colorOptions.innerHTML = '';
    hatOptions.innerHTML = '';

    unlockedSkins.forEach(skin => {
        debugLog('Processing skin:', skin);
        const optionElement = document.createElement('div');
        optionElement.classList.add('skin-option');
        optionElement.setAttribute('data-skin-id', skin.id);
        optionElement.setAttribute('title', `${skin.name} (${skin.rarity})`);
        
        switch (skin.type) {
            case 'color':
                debugLog('Creating color option for:', skin.name);
                optionElement.style.backgroundColor = skin.value;
                if (skin.effect === 'glow') {
                    optionElement.classList.add('glow-effect');
                }
                colorOptions.appendChild(optionElement);
                break;
            case 'hat':
                debugLog('Creating hat option for:', skin.name);
                optionElement.style.backgroundImage = `url(${skin.value})`;
                hatOptions.appendChild(optionElement);
                break;
        }

        optionElement.addEventListener('click', () => selectSkin(skin.type, skin.id, optionElement));
    });

    debugLog('Color options after processing:', colorOptions.innerHTML);
    debugLog('Hat options after processing:', hatOptions.innerHTML);

    // Show a message if no skins are unlocked for a category
    if (colorOptions.children.length === 0) {
        colorOptions.innerHTML = '<p>No colors unlocked yet</p>';
    }
    if (hatOptions.children.length === 0) {
        hatOptions.innerHTML = '<p>No hats unlocked yet</p>';
    }
}

function toggleInfoWidget() {
    if (isInfoWidgetVisible) {
        hideInfoWidget();
    } else {
        showInfoWidget();
    }
}

function showInfoWidget() {
    infoWidget.classList.add('visible');
    isInfoWidgetVisible = true;
    showInfoTab('socials'); // Open the Socials tab by default
}

function hideInfoWidget() {
    infoWidget.classList.remove('visible');
    isInfoWidgetVisible = false;
}

function showInfoTab(tabName) {
    const tabContents = infoWidget.querySelectorAll('.tab-content');
    tabContents.forEach(content => content.style.display = 'none');

    const tabButtons = infoWidget.querySelectorAll('.tab-button');
    tabButtons.forEach(button => button.classList.remove('active'));

    const selectedTab = document.getElementById(tabName);
    if (selectedTab) {
        selectedTab.style.display = 'block';
    }

    const selectedButton = infoWidget.querySelector(`.tab-button[data-tab="${tabName}"]`);
    if (selectedButton) {
        selectedButton.classList.add('active');
    }
}


function toggleWidget(event) {
    if (event) {
        event.stopPropagation();
    }
    if (uiWidget.classList.contains('visible')) {
        hideWidget();
    } else {
        showWidget();
    }
}


// Add event listeners for close buttons
document.querySelectorAll('.close-button').forEach(button => {
    button.addEventListener('click', () => {
        hideWidget();
    });
});

function showWidget() {
    uiWidget.classList.add('visible');
    openInterfaces.menu = true;
    
    // Add Achievements tab if it doesn't exist
    if (!document.getElementById('achievements')) {
        const achievementsTab = createAchievementsTab();
        const widgetContent = uiWidget.querySelector('.widget-content');
        if (widgetContent) {
            widgetContent.appendChild(achievementsTab);
        } else {
            console.error('Widget content container not found');
        }
        
        // Add Achievements button to tab buttons
        const tabButtons = uiWidget.querySelector('.widget-tabs');
        if (tabButtons) {
            const achievementsButton = document.createElement('button');
            achievementsButton.classList.add('tab-button');
            achievementsButton.setAttribute('data-tab', 'achievements');
            achievementsButton.textContent = 'Achievements';
            tabButtons.appendChild(achievementsButton);
            
            achievementsButton.addEventListener('click', () => showTab('achievements'));
        } else {
            console.error('Widget tabs container not found');
        }
    }

    if (gameStarted && player) {
        pausePlayer();
        showTab('settings'); // Open the Settings tab by default when in-game
    } else {
        showTab('customization'); // Open the Customization tab by default in the main menu
    }
    updateAccountTab();
}


function updateAccountTab() {
    const accountContent = document.getElementById('accountContent');
    if (currentUser) {
        fetch('/get-discord-info', {
            headers: {
                'Authorization': getSessionToken()
            }
        })
        .then(response => response.json())
        .then(data => {
            if (data.linked) {
                accountContent.innerHTML = `
                    <h3>Welcome, ${currentUser}!</h3>
                    <p>Your Discord account is linked:</p>
                    <div class="discord-info">
                        <img src="https://cdn.discordapp.com/avatars/${data.discord_id}/${data.avatar}.png" 
                             alt="Discord Avatar" 
                             class="discord-avatar">
                        <span class="discord-username">${data.username}</span>
                        <button id="unlinkDiscordButton" class="small-button">Unlink Discord</button>
                    </div>
                `;
                document.getElementById('unlinkDiscordButton').addEventListener('click', unlinkDiscord);
            } else {
                accountContent.innerHTML = `
                    <h3>Welcome, ${currentUser}!</h3>
                    <p>Link your Discord account:</p>
                    <button id="linkDiscordButton" class="button">Link Discord</button>
                `;
                document.getElementById('linkDiscordButton').addEventListener('click', linkDiscord);
            }
        })
        .catch(error => {
            console.error('Error fetching Discord info:', error);
            accountContent.innerHTML = `
                <h3>Welcome, ${currentUser}!</h3>
                <p>Error loading Discord information. Please try again later.</p>
            `;
        });
    } else {
        accountContent.innerHTML = `
            <p class="sign-in-message">Please sign in to view account settings.</p>
        `;
    }
}


function getSessionToken() {
    return localStorage.getItem('sessionToken');
}


function linkDiscord() {
    fetch('/initiate-discord-link', {
        method: 'POST',
        headers: {
            'Authorization': getSessionToken(),
            'Content-Type': 'application/json'
        }
    })
    .then(response => response.json())
    .then(data => {
        const width = 600;
        const height = 800;
        const left = (screen.width / 2) - (width / 2);
        const top = (screen.height / 2) - (height / 2);
        
        const popup = window.open(data.auth_url, 'discord-oauth', 
            `width=${width},height=${height},left=${left},top=${top}`);
        
        window.addEventListener('message', function(event) {
            if (event.data === 'discord-linked') {
                popup.close();
                updateAccountTab();
                notificationSystem.showNotification('Discord account linked successfully!');
            }
        }, false);
    })
    .catch(error => {
        console.error('Error initiating Discord link:', error);
        notificationSystem.showNotification('An error occurred while linking Discord account');
    });
}


function unlinkDiscord() {
    fetch('/unlink-discord', { 
        method: 'POST',
        headers: {
            'Authorization': getSessionToken()
        }
    })
    .then(response => response.json())
    .then(data => {
        if (data.success) {
            notificationSystem.showNotification('Discord account unlinked successfully');
            updateAccountTab();
        } else {
            notificationSystem.showNotification('Failed to unlink Discord account');
        }
    })
    .catch(error => {
        console.error('Error unlinking Discord:', error);
        notificationSystem.showNotification('An error occurred while unlinking Discord account');
    });
}



function onCustomizationTabOpen() {
    const skinCustomization = document.getElementById('skinCustomization');
    if (!skinCustomization) {
        console.error('skinCustomization element not found');
        return;
    }

    // Show loading indicator immediately
    // skinCustomization.innerHTML = '<div class="loading-spinner">Loading skins...</div>';

    // Load skin options asynchronously
    setTimeout(() => {
        loadSkinOptions();
    }, 0);
}




function hideWidget() {
    uiWidget.classList.remove('visible');
    openInterfaces.menu = false;
    if (gameStarted && player) {
        unpausePlayer();
    }
}

// Focus
// function handleOutsideClick(event) {
//     const uiWidget = document.getElementById('uiWidget');
//     const classWidget = document.getElementById('classWidget');
//     const infoWidget = document.getElementById('infoWidget');
//     const menuButton = document.getElementById('menuButton');
//     const classSelectorButton = document.getElementById('classSelectorButton');
//     const infoButton = document.getElementById('infoButton');

//     // Check and close UI Widget
//     if (openInterfaces.menu && !uiWidget.contains(event.target) && event.target !== menuButton) {
//         hideWidget();
//     }

//     // Check and close Class Widget
//     if (classWidget.classList.contains('visible') && !classWidget.contains(event.target) && event.target !== classSelectorButton) {
//         hideClassSelector();
//     }

//     // Check and close Info Widget
//     if (isInfoWidgetVisible && !infoWidget.contains(event.target) && event.target !== infoButton) {
//         hideInfoWidget();
//     }
// }


function showTab(tabName) {
    debugLog('Showing tab:', tabName);
    
    // Hide all tab contents
    const tabContents = document.querySelectorAll('.tab-content');
    tabContents.forEach(content => content.style.display = 'none');

    // Deactivate all tab buttons
    const tabButtons = document.querySelectorAll('.tab-button');
    tabButtons.forEach(button => button.classList.remove('active'));

    // Show the selected tab content
    const selectedTab = document.getElementById(tabName);
    if (selectedTab) {
        selectedTab.style.display = 'block';
    } else {
        console.error('No tab found with name:', tabName);
        // If no valid tab is selected, default to the first tab
        const firstTab = tabContents[0];
        if (firstTab) {
            firstTab.style.display = 'block';
            tabName = firstTab.id;
        }
    }

    // Activate the selected tab button
    const selectedButton = document.querySelector(`.tab-button[data-tab="${tabName}"]`);
    if (selectedButton) {
        selectedButton.classList.add('active');
    }

    if (tabName === 'customization') {
        onCustomizationTabOpen();
    } else if (tabName === 'account') {
        updateAccountTab();
    } else if (tabName === 'achievements') {
        fetchUserAchievements();
    }
}

function initAudio() {
    audioContext = new (window.AudioContext || window.webkitAudioContext)();
    analyser = audioContext.createAnalyser();
    analyser.fftSize = 256;
}


function startGame() {
    socket = io({
        reconnection: true,
        reconnectionDelay: 1000,
        reconnectionDelayMax: 5000,
        reconnectionAttempts: 5
    });
    preloadEnemyImages();
    const playerName = currentUser || `Guest-${Math.floor(Math.random() * 10000)}`;

    socket.on('connect', () => {
        debugLog('Connected to server');
        // Send join request with or without class_id
        socket.emit('join', { 
            room: 'main_game_room', 
            name: playerName, 
            class_id: selectedClassId  // This can be undefined if no class was selected
        });
    });

    socket.on('achievement_unlocked', handleAchievementUnlock);


    socket.on('reconnect', (attemptNumber) => {
        debugLog(`Reconnected to server after ${attemptNumber} attempts`);
        // Re-join the game room
        socket.emit('join', { 
            room: 'main_game_room', 
            name: playerName, 
            class_id: selectedClassId  // This can be undefined if no class was selected
        });
    });


    socket.on('disconnect', () => {
        debugLog('Disconnected from server');
        // You might want to show a message to the user here
        hideShopButton();
    });

    socket.on('join_error', (data) => {
        notificationSystem.showNotification(data.message);
        // Disconnect the socket to prevent any further communication
        socket.disconnect();
        // Reset game state
        gameStarted = false;
        document.getElementById('gameControls').style.display = 'flex';
        document.getElementById('ui').style.display = 'none';
    });

    socket.on('reconnect_failed', () => {
        debugLog('Failed to reconnect to server');
        // You might want to show a message to the user and/or reload the page
    });

    socket.on('damage_dealt', (data) => {
        const damageText = Math.round(data.damage).toString();
        showFloatingText(damageText, data.enemyX, data.enemyY, '#ff0000', false); // Red color for damage, not moving up
    });
    
    socket.on('music_sync', (data) => {
        if (gameStarted) {
            const serverClientTimeDiff = Date.now() / 1000 - data.serverTime;
            currentSongDuration = data.songDuration || 180; // Use the provided duration or default to 3 minutes
            const songPosition = (Date.now() / 1000 - data.startTime - serverClientTimeDiff) % currentSongDuration;
            setupAudio(data.song, songPosition);
        }
    });

    socket.on('music_stop', () => {
        if (audioElement) {
            audioElement.pause();
        }
    });

    socket.on('game_alert', (data) => {
        if (gameStarted) {
            alertSystem.addnotificationSystem.showNotification(data.message);
        }
    });    

    socket.on('game_state', (data) => {
        debugLog('Received game state:', data);
        player = new Player(
            data.players[socket.id].x,
            data.players[socket.id].y,
            playerName,
            data.players[socket.id].skin,
            data.players[socket.id].weapons,
            data.players[socket.id].player_class,
            ctx
        );
        player.level = data.players[socket.id].level || 1;
        player.experience = data.players[socket.id].experience || 0;
        player.maxExperience = data.players[socket.id].max_experience || 100;
        player.isPaused = data.players[socket.id].is_paused || false;
        player.synthCoins = data.players[socket.id].synth_coins || 0;
        player.currentHealth = data.players[socket.id].current_health;
        player.maxHealth = data.players[socket.id].max_health;
        updateSynthCoinsDisplay();
        debugLog(`Initial player stats: Level ${player.level}, Exp ${player.experience}/${player.maxExperience}, Health ${player.currentHealth}/${player.maxHealth}`);

            player.weapons.forEach(weapon => {
                if (weapon && weapon.bullet_image_source) {
                    preloadBulletImage(weapon.bullet_image_source);
                } else {
                    console.error('Invalid weapon structure:', weapon);
                }
            });
            
    
        loadPlayerSkin(playerName);
    
        otherPlayers = Object.entries(data.players).reduce((acc, [id, playerData]) => {
            if (id !== socket.id) {
                acc[id] = new Player(
                    playerData.x,
                    playerData.y,
                    playerData.name,
                    playerData.skin,
                    playerData.weapon,
                    playerData.player_class,
                    ctx  // Pass the canvas context here
                );
                acc[id].level = playerData.level || 1;
                acc[id].isPaused = playerData.is_paused || false;
                loadPlayerSkin(playerData.name);
            }
            return acc;
        }, {});
        
        // Preload bullet images for all weapons
        Object.values(data.players).forEach(playerData => {
            if (playerData.weapon && playerData.weapon.bullet_image_source) {
                preloadBulletImage(playerData.weapon.bullet_image_source);
            }
        });
        
        serverEnemies = data.enemies.map(enemyData => new Enemy(enemyData));
        serverBullets = data.bullets;
    
        gameStarted = true;
        document.getElementById('gameControls').style.display = 'none';
        document.getElementById('ui').style.display = 'flex';
        document.getElementById('minimap-container').style.display = 'block';
        infoButton.style.display = 'none';
        hideInfoWidget();
    
        showShopButton();  // Show the shop button when the game starts
    
        socket.emit('request_music_sync');
    });

    socket.on('synth_coins_update', (data) => {
        synthCoins = data.coins.map(coin => new SynthCoin(coin.x, coin.y));
    });
            
    socket.on('new_synth_coin', (data) => {
        synthCoins.push(new SynthCoin(data.x, data.y));
    });

    socket.on('coin_collected', (data) => {
        debugLog('Coin collected event received:', data);
        updateCoinCollection(data);
    });
                                     
    socket.on('collect_synth_coin', (data) => {
        debugLog('Collect synth coin event received:', data);
        updateCoinCollection(data);
    });        
            
    socket.on('player_update', (data) => {
        if (data.id !== socket.id) {
            if (!otherPlayers[data.id]) {
                otherPlayers[data.id] = new Player(
                    data.player.x,
                    data.player.y,
                    data.player.name,
                    data.player.skin,
                    data.player.weapons,
                    data.player.player_class,
                    ctx
                );
            } else {
                const updatedPlayer = otherPlayers[data.id];
                Object.assign(updatedPlayer, data.player);
                updatedPlayer.setSkin(data.player.skin);
                updatedPlayer.weapons = data.player.weapons;
                updatedPlayer.loadWeaponImages();
                updatedPlayer.weaponAngles = data.player.weapon_angles || updatedPlayer.weapons.map(() => 0);
                updatedPlayer.currentHealth = data.player.current_health;
                updatedPlayer.maxHealth = data.player.max_health;
                updatedPlayer.isPaused = data.player.is_paused;
                updatedPlayer.autoFireEnabled = data.player.auto_fire_enabled;
            }
        } else {
            // Update the current player's weapons if necessary
            player.weapons = data.player.weapons;
            player.loadWeaponImages();
            player.weaponAngles = data.player.weapon_angles || player.weapons.map(() => 0);
            player.currentHealth = data.player.current_health;
            player.maxHealth = data.player.max_health;
            player.isPaused = data.player.is_paused;
            player.autoFireEnabled = data.player.auto_fire_enabled;
        }
    });
        
    
    socket.on('upgrade_applied', (data) => {
        debugLog('Upgrade applied:', data);
        if (player) {
            player.upgradeWeapon(data.attribute, data.value);
        } else {
            console.error('Player object not found');
        }
    });
                    
        
    socket.on('new_player', (data) => {
        debugLog('New player joined:', data);
        if (data.id !== socket.id) {
            otherPlayers[data.id] = new Player(
                data.player.x,
                data.player.y,
                data.player.name,
                data.player.skin,
                data.player.weapon,
                data.player.player_class,
                ctx
            );
            loadPlayerSkin(data.player.name);
        }
    });
    
        
    socket.on('player_shoot', (data) => {
        if (data.playerId in otherPlayers) {
            const player = otherPlayers[data.playerId];
            for (let i = 0; i < player.weaponAttributes.count; i++) {
                const angle = data.angle + (Math.random() - 0.5) * 0.2; // Add some spread
                const bullet = {
                    x: player.x,
                    y: player.y,
                    angle: angle,
                    speed: player.weaponAttributes.speed,
                    size: player.weaponAttributes.size,
                    damage: player.weaponAttributes.damage,
                    playerId: data.playerId
                };
                serverBullets.push(bullet);
            }
        }
    });
    

    socket.on('experience_update', (data) => {
        if (data.player_id === socket.id) {
            playerExperience = data.experience;
            playerMaxExperience = data.max_experience;
            playerLevel = data.level;
            player.level = data.level;
        
            debugLog(`Experience updated: ${playerExperience}/${playerMaxExperience}, Level: ${playerLevel}`);
    
            if (data.leveled_up) {
                debugLog('Level up!');
                handleLevelUp();
            }
    
            if (data.exp_gained) {
                showFloatingText(`+${data.exp_gained} XP`, player.x, player.y - 30, '#FFFFFF', true); // Gold color for XP, moving up
            }
        } else if (otherPlayers[data.player_id]) {
            otherPlayers[data.player_id].level = data.level;
        }
    });
            
    socket.on('player_disconnected', (playerId) => {
        delete otherPlayers[playerId];
    });

    socket.on('game_update', (data) => {
        serverEnemies = data.enemies.map(enemyData => {
            const enemy = new Enemy(enemyData);
            enemy.update(); // Ensure the enemy's trail is initialized
            return enemy;
        });
        serverBullets = data.bullets;
        
        // Update synth coins
        synthCoins = data.synth_coins.map(coinData => {
            const existingCoin = synthCoins.find(c => Math.hypot(c.x - coinData.x, c.y - coinData.y) < 0.1);
            if (existingCoin) {
                existingCoin.x = coinData.x;
                existingCoin.y = coinData.y;
                return existingCoin;
            } else {
                return new SynthCoin(coinData.x, coinData.y);
            }
        });
    // Update player health
    if (data.players[socket.id]) {
        player.currentHealth = data.players[socket.id].current_health;
        player.maxHealth = data.players[socket.id].max_health;
    }

    // Update other players' health
    Object.entries(data.players).forEach(([id, playerData]) => {
        if (id !== socket.id && otherPlayers[id]) {
            otherPlayers[id].currentHealth = playerData.current_health;
            otherPlayers[id].maxHealth = playerData.max_health;
        }
    });
});

socket.on('bullet_impact', (data) => {
    impactEffects.push(new ImpactEffect(data.x, data.y, data.color, data.size, data.angle));
});

    
    socket.on('new_bullet', (bulletData) => {
        serverBullets.push(bulletData);
        if (bulletData.bullet_image_source) {
            preloadBulletImage(bulletData.bullet_image_source);
        }
    });
    
    socket.on('enemy_destroyed', (data) => {
        data.particles.forEach(particleData => {
            particles.push(new Particle(
                particleData.x,
                particleData.y,
                particleData.color,
                particleData.radius,
                particleData.velocityX,
                particleData.velocityY,
                particleData.ttl
            ));
        });
    });

    socket.on('player_died', (data) => {
        if (data.player_id === socket.id) {
            // This is the current player
            console.log('You died!');
            // Implement any client-side death logic here (e.g., death animation, respawn timer)
        } else {
            // Another player died
            console.log(`Player ${data.player_id} died`);
            // Optionally implement logic for when other players die
        }
    });
    

    socket.on('music_control', (data) => {
        debugLog('Received music control:', data);
        switch(data.action) {
            case 'start':
            case 'change':
                const currentTime = Date.now() / 1000;
                const elapsedTime = currentTime - data.startTime;
                currentSongDuration = data.songDuration || 180; // Use the provided duration or default to 3 minutes
                setupAudio(data.song, elapsedTime % currentSongDuration);
                break;
            case 'stop':
                if (audioElement) {
                    audioElement.pause();
                }
                break;
        }
    });

    socket.on('skin_update', (data) => {
        const { player_id, skin_data } = data;
        if (player_id === socket.id) {
            // Update the current player's skin
            player.setSkin(skin_data);
        } else if (otherPlayers[player_id]) {
            // Update other player's skin
            otherPlayers[player_id].setSkin(skin_data);
        }
    });
    
}

function hideShopButton() {
    const shopButton = document.getElementById('shopButton');
    if (shopButton) {
        shopButton.style.display = 'none';
    }
}


function updateCoinCollection(data) {
    if (data.player_id === socket.id) {
        const coinsCollected = data.coin_count - player.synthCoins;
        player.synthCoins = data.coin_count;
        updateSynthCoinsDisplay();
        debugLog('Updated player synth coins:', player.synthCoins);

        // Create or update floating text for coin collection
        if (currentCoinFloatingText) {
            currentCoinFloatingText.amount += coinsCollected;
            currentCoinFloatingText.text = `+$${currentCoinFloatingText.amount}`;
            currentCoinFloatingText.lifetime = 60; // Reset lifetime
            currentCoinFloatingText.y = player.y - 50; // Update position
        } else {
            currentCoinFloatingText = {
                text: `+$${coinsCollected}`,
                x: player.x,
                y: player.y - 50,
                color: '#FFD700', // Gold color
                lifetime: 60,
                velocity: -0.5,
                amount: coinsCollected
            };
            floatingTexts.push(currentCoinFloatingText);
        }
        debugLog('Floating text created:', currentCoinFloatingText);
    } else if (otherPlayers[data.player_id]) {
        otherPlayers[data.player_id].synthCoins = data.coin_count;
    }
    // Remove the collected coin from the synthCoins array
    synthCoins = synthCoins.filter(coin => coin.x !== data.coin_x || coin.y !== data.coin_y);
}


function showFloatingText(text, x, y, color, moveUp = true) {
    const floatingText = {
        text: text,
        x: x,
        y: y,
        color: color,
        lifetime: 60, // Number of frames the text will be visible
        velocity: moveUp ? -1 : 0 // Upward velocity if moveUp is true, otherwise 0
    };
    floatingTexts.push(floatingText);
}

// Add an array to store floating texts


// Add a function to load player skins
function loadPlayerSkin(username) {
    fetch('/get-player-skin', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({ username }),
    })
    .then(response => {
        if (!response.ok) {
            throw new Error('Network response was not ok');
        }
        return response.json();
    })
    .then(skinData => {
        debugLog('Received skin data:', skinData);  // Add this line for debugging
        if (player && player.name === username) {
            player.setSkin(skinData);
        }
        // Update other players' skins if necessary
        Object.values(otherPlayers).forEach(otherPlayer => {
            if (otherPlayer.name === username) {
                otherPlayer.setSkin(skinData);
            }
        });
    })
    .catch(error => {
        console.error('Error loading player skin:', error);
        // Set a default skin if there's an error
        const defaultSkin = {
            color: { name: 'Default Blue', value: '#00ffff', effect: null }
        };
        if (player && player.name === username) {
            player.setSkin(defaultSkin);
        }
        Object.values(otherPlayers).forEach(otherPlayer => {
            if (otherPlayer.name === username) {
                otherPlayer.setSkin(defaultSkin);
            }
        });
    });
}

// Update the setupAudio function
function setupAudio(audioSource, startTime = 0) {
    if (audioElement) {
        audioElement.pause();
    }
    audioElement = new Audio(audioSource);
    audioElement.currentTime = startTime;
    audioElement.play().catch(e => console.error("Error playing audio:", e));

    if (!audioContext) {
        audioContext = new (window.AudioContext || window.webkitAudioContext)();
    }
    
    if (!analyser) {
        analyser = audioContext.createAnalyser();
        analyser.fftSize = 256;
        audioData = new Uint8Array(analyser.frequencyBinCount);
    }

    if (!source) {
        source = audioContext.createMediaElementSource(audioElement);
        source.connect(analyser);
        analyser.connect(audioContext.destination);
    }
}

// Add this new function
function toggleMinimap() {
    minimapState = (minimapState + 1) % 3;
    const minimap = document.getElementById('minimap');
    
    switch (minimapState) {
      case 0:
        minimap.classList.remove('small', 'large');
        break;
      case 1:
        minimap.classList.add('small');
        minimap.classList.remove('large');
        break;
      case 2:
        minimap.classList.remove('small');
        minimap.classList.add('large');
        break;
    }
  }
  
// Add this new function
function drawMinimap() {
    if (minimapState === 0) return;
  
    const minimap = document.getElementById('minimap');
    const scale = minimapState === 1 ? 0.05 : 0.2;
    
    minimapCanvas.width = minimap.offsetWidth;
    minimapCanvas.height = minimap.offsetHeight;
    
    minimapCtx.fillStyle = 'rgba(18, 4, 88, 0.7)';
    minimapCtx.fillRect(0, 0, minimapCanvas.width, minimapCanvas.height);
    
    // Draw player
    const playerX = (player.x / MAP_WIDTH) * minimapCanvas.width;
    const playerY = (player.y / MAP_HEIGHT) * minimapCanvas.height;
    minimapCtx.fillStyle = '#00ffff';
    minimapCtx.beginPath();
    minimapCtx.arc(playerX, playerY, 3, 0, Math.PI * 2);
    minimapCtx.fill();
  
    // Draw player name on large minimap
    if (minimapState === 2) {
      drawPlayerName(minimapCtx, player.name, playerX, playerY, '#00ffff');
    }
  
    // Draw other players
    minimapCtx.fillStyle = '#ff00ff';
    Object.values(otherPlayers).forEach(otherPlayer => {
      const x = (otherPlayer.x / MAP_WIDTH) * minimapCanvas.width;
      const y = (otherPlayer.y / MAP_HEIGHT) * minimapCanvas.height;
      minimapCtx.beginPath();
      minimapCtx.arc(x, y, 2, 0, Math.PI * 2);
      minimapCtx.fill();
  
      // Draw other player names on large minimap
      if (minimapState === 2) {
        drawPlayerName(minimapCtx, otherPlayer.name, x, y, '#ff00ff');
      }
    });
  
    // Draw enemies
    minimapCtx.fillStyle = '#ff0000';
    serverEnemies.forEach(enemy => {
      const x = (enemy.x / MAP_WIDTH) * minimapCanvas.width;
      const y = (enemy.y / MAP_HEIGHT) * minimapCanvas.height;
      minimapCtx.beginPath();
      minimapCtx.arc(x, y, 2, 0, Math.PI * 2);
      minimapCtx.fill();
    });
  }
  
  // New helper function to draw player names
  function drawPlayerName(ctx, name, x, y, color) {
    ctx.font = '12px Orbitron';
    ctx.fillStyle = color;
    ctx.textAlign = 'center';
    ctx.textBaseline = 'bottom';
    ctx.fillText(name, x, y - 5);
  }  

  class SynthCoin {
    constructor(x, y) {
        this.x = x;
        this.y = y;
        this.radius = 10;
        this.angle = Math.random() * Math.PI * 2;
        this.glowAngle = 0;
    }

    update() {
        this.angle += 0.02;
        this.glowAngle += 0.1;
    }

    draw(ctx) {
        ctx.save();
        ctx.translate(this.x, this.y);
        ctx.rotate(this.angle);

        // Draw coin base
        const gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, this.radius);
        gradient.addColorStop(0, '#FFD700');   // Center: Gold
        gradient.addColorStop(0.8, '#DAA520'); // Edge: Goldenrod
        gradient.addColorStop(1, '#B8860B');   // Rim: Dark Goldenrod

        ctx.beginPath();
        ctx.arc(0, 0, this.radius, 0, Math.PI * 2);
        ctx.fillStyle = gradient;
        ctx.fill();

        // Draw coin edge
        ctx.beginPath();
        ctx.arc(0, 0, this.radius, 0, Math.PI * 2);
        ctx.strokeStyle = '#B8860B';
        ctx.lineWidth = 2;
        ctx.stroke();

        // Draw "$" symbol
        ctx.fillStyle = '#B8860B';
        ctx.font = `bold ${this.radius}px Arial`;
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.fillText('$', 0, 0);

        // Draw glow effect
        const glowSize = this.radius * 1.5;
        const glowGradient = ctx.createRadialGradient(0, 0, 0, 0, 0, glowSize);
        glowGradient.addColorStop(0, 'rgba(255, 215, 0, 0.5)');
        glowGradient.addColorStop(1, 'rgba(255, 215, 0, 0)');

        ctx.globalAlpha = 0.5 + Math.sin(this.glowAngle) * 0.2; // Pulsating glow
        ctx.beginPath();
        ctx.arc(0, 0, glowSize, 0, Math.PI * 2);
        ctx.fillStyle = glowGradient;
        ctx.fill();

        // Draw shine effect
        ctx.globalAlpha = 0.7;
        ctx.beginPath();
        ctx.ellipse(-this.radius * 0.3, -this.radius * 0.3, this.radius * 0.2, this.radius * 0.4, Math.PI / 4, 0, Math.PI * 2);
        ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
        ctx.fill();

        ctx.restore();
    }
}

let synthCoins = [];


// Star class
class Star {
    constructor() {
        this.reset();
    }

    reset() {
        this.x = Math.random() * MAP_WIDTH;
        this.y = Math.random() * MAP_HEIGHT;
        this.size = Math.random() * 3 + 1;
        this.speed = Math.random() * 0.5 + 0.1;
    }

    update(audioData) {
        this.y += this.speed;
        if (this.y > MAP_HEIGHT) {
            this.reset();
            this.y = 0; // Start from the top again
        }
        
        // Audio visualization effect
        const index = Math.floor(this.x / MAP_WIDTH * audioData.length);
        const audioIntensity = audioData[index] / 255;
        this.size = (Math.random() * 3 + 1) * (1 + audioIntensity);
    }

    draw(ctx) {
        ctx.fillStyle = `rgba(255, 255, 255, ${Math.random() * 0.5 + 0.5})`;
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
        ctx.fill();
    }
}

// Shooting Star class
class ShootingStar {
    constructor() {
        this.reset();
    }

    reset() {
        this.x = Math.random() * MAP_WIDTH;
        this.y = 0;
        this.length = Math.random() * 80 + 20;
        this.speed = Math.random() * 10 + 5;
        this.angle = Math.PI / 4 + (Math.random() * Math.PI / 4);
        this.active = true;
        this.tailPoints = [];
    }

    update(audioData) {
        this.x += Math.cos(this.angle) * this.speed;
        this.y += Math.sin(this.angle) * this.speed;

        // Audio visualization effect
        const index = Math.floor(this.x / MAP_WIDTH * audioData.length);
        const audioIntensity = audioData[index] / 255;
        this.speed = (Math.random() * 10 + 5) * (1 + audioIntensity);

        this.tailPoints.unshift({x: this.x, y: this.y});
        if (this.tailPoints.length > 20) {
            this.tailPoints.pop();
        }

        if (this.x > MAP_WIDTH || this.y > MAP_HEIGHT) {
            this.reset();
        }
    }

    draw(ctx) {
        ctx.strokeStyle = 'rgba(255, 255, 255, 0.8)';
        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.moveTo(this.x, this.y);
        for (let i = 0; i < this.tailPoints.length; i++) {
            const point = this.tailPoints[i];
            ctx.lineTo(point.x, point.y);
            ctx.globalAlpha = 1 - (i / this.tailPoints.length);
        }
        ctx.stroke();
        ctx.globalAlpha = 1;
    }
}

class NeonCloud {
    constructor(x, y, size) {
        this.x = x;
        this.y = y;
        this.size = size;
        this.baseColor = this.getRandomNeonColor();
        this.offset = Math.random() * Math.PI * 2;
    }

    getRandomNeonColor() {
        const neonColors = [
            '#ff00ff', // Magenta
            '#00ffff', // Cyan
            '#ff00a0', // Hot Pink
            '#00ff7f', // Spring Green
            '#ff6b6b', // Light Red
            '#4deeea', // Bright Turquoise
        ];
        return neonColors[Math.floor(Math.random() * neonColors.length)];
    }

    update(audioData) {
        const index = Math.floor(this.x / MAP_WIDTH * audioData.length);
        const audioIntensity = audioData[index] / 255;
        this.size = this.size * (1 + audioIntensity * 0.2);
    }

    draw(ctx) {
        ctx.save();
        ctx.translate(this.x, this.y);

        const gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, this.size);
        gradient.addColorStop(0, this.baseColor + '77'); // Semi-transparent
        gradient.addColorStop(1, this.baseColor + '00'); // Fully transparent

        ctx.beginPath();
        ctx.arc(0, 0, this.size, 0, Math.PI * 2);
        ctx.fillStyle = gradient;
        ctx.globalAlpha = 0.7 + Math.sin(Date.now() / 1000 + this.offset) * 0.3; // Pulsating effect
        ctx.fill();

        ctx.restore();
    }
}


// Background effects manager
class BackgroundEffects {
    constructor() {
        this.stars = Array(200).fill().map(() => new Star());
        this.shootingStars = Array(5).fill().map(() => new ShootingStar());
        this.neonClouds = Array(10).fill().map(() => new NeonCloud(
            Math.random() * MAP_WIDTH,
            Math.random() * MAP_HEIGHT,
            Math.random() * 100 + 50
        ));
    }

    update(audioData) {
        this.stars.forEach(star => star.update(audioData));
        this.shootingStars.forEach(star => {
            if (star.active) {
                star.update(audioData);
            } else {
                star.reset();
            }
        });
        this.neonClouds.forEach(cloud => cloud.update(audioData));
    }

    draw(ctx) {
        // Draw neon clouds first, so they appear behind other elements
        this.neonClouds.forEach(cloud => cloud.draw(ctx));
        this.stars.forEach(star => star.draw(ctx));
        this.shootingStars.forEach(star => star.draw(ctx));
    }
}

class AlertSystem {
    constructor() {
        this.alerts = [];
        this.alertDuration = 3000; // Duration in milliseconds
    }

    // addnotificationSystem.showNotification(message) {
    //     const alert = {
    //         message: message,
    //         createdAt: Date.now(),
    //         opacity: 1
    //     };
    //     this.alerts.push(alert);
    // }

    update() {
        const currentTime = Date.now();
        this.alerts = this.alerts.filter(alert => {
            const elapsedTime = currentTime - alert.createdAt;
            if (elapsedTime > this.alertDuration) {
                return false;
            }
            if (elapsedTime > this.alertDuration / 2) {
                alert.opacity = 1 - ((elapsedTime - this.alertDuration / 2) / (this.alertDuration / 2));
            }
            return true;
        });
    }

    draw(ctx) {
        const alertHeight = 30;
        const padding = 10;
        let yOffset = padding;

        ctx.save();
        ctx.font = '16px Orbitron';
        ctx.textAlign = 'center';

        this.alerts.forEach(alert => {
            ctx.fillStyle = `rgba(255, 255, 255, ${alert.opacity})`;
            ctx.fillText(alert.message, canvas.width / 2, yOffset + alertHeight / 2);
            yOffset += alertHeight + padding;
        });

        ctx.restore();
    }
}

// Create an instance of the AlertSystem
const alertSystem = new AlertSystem();

// Create an instance of BackgroundEffects
const backgroundEffects = new BackgroundEffects();


// Modify the update function
function update() {
    // Clear main canvas
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    if (!gameStarted || !player) {
        requestAnimationFrame(update);
        return;
    }

    const currentTime = Date.now();
    const deltaTime = (currentTime - lastUpdateTime) / 1000; // Convert to seconds
    lastUpdateTime = currentTime;


    if (gameStarted && player) {
        if (!areInterfacesOpen()) {
            if (isAutoFireEnabled) {
                const nearestEnemy = findNearestEnemy();
                player.updateWeaponAngle(nearestEnemy);
                player.shoot(currentTime, nearestEnemy);
            } else {
                // Handle manual aiming and shooting
                player.updateWeaponAngleToMouse();
                if (player.isShooting) {
                    player.shoot(currentTime);
                }
            }
        }


        socket.emit('player_update', { 
            x: player.x, 
            y: player.y,
            weapon_angles: player.weaponAngles,
            auto_fire_enabled: isAutoFireEnabled
        });
    
        updateAndDrawShootingJoystick(deltaTime);
    }

    if (gameStarted) {
        alertSystem.update();
    }

    if (gameStarted && player && !player.isPaused) {
        const allPlayers = { ...otherPlayers, [socket.id]: player };
        synthCoins.forEach(coin => {
            coin.update(allPlayers);
        });
    }

    impactEffects = impactEffects.filter(effect => {
        effect.update();
        return effect.lifetime > 0;
    });



    // Update Synth Coins
    synthCoins.forEach(coin => coin.update());
    

        // Check for coin collection only if the player is not paused
        if (!player.isPaused) {
            synthCoins = synthCoins.filter(coin => {
                const distance = Math.hypot(player.x - coin.x, player.y - coin.y);
                if (distance <= player.radius + coin.radius) {
                    // Coin collected
                    socket.emit('collect_synth_coin', { coin_x: coin.x, coin_y: coin.y });
                    return false;
                }
                return true;
            });
        }


    player.update();
    camera.follow(player);

    serverEnemies.forEach(enemy => enemy.update());

    ctx.save();
    ctx.translate(-camera.x, -camera.y);

    // Draw the map boundaries
    ctx.strokeStyle = 'white';
    ctx.strokeRect(0, 0, MAP_WIDTH, MAP_HEIGHT);

    // Update audio data
    if (analyser) {
        analyser.getByteFrequencyData(audioData);
    }          

    // Update and draw background effects
    backgroundEffects.update(audioData);
    ctx.save();
    ctx.globalCompositeOperation = 'lighter';
    backgroundEffects.draw(ctx);
    ctx.globalCompositeOperation = 'source-over';
    ctx.restore();
    
    // Draw game objects
    drawGameObjects();

    updateSynthCoinsDisplay();

    ctx.restore();

    // Draw UI elements (like joystick) after restoring the context
    if (joystick.active) {
        drawJoystick();
    }

    drawMinimap();
    drawExperienceBar();

    // If the widget is visible, draw a semi-transparent overlay
    if (isWidgetVisible) {
        ctx.fillStyle = 'rgba(18, 4, 88, 0.5)';
        ctx.fillRect(0, 0, canvas.width, canvas.height);
    }

    socket.emit('player_update', { 
        x: player.x, 
        y: player.y,
        auto_fire_enabled: isAutoFireEnabled  // Send auto-fire preference
    });
    if (gameStarted) {
        alertSystem.draw(ctx);
    }
    requestAnimationFrame(update);
    debugLog('Player position:', player.x, player.y);
    debugLog('Number of enemies:', serverEnemies.length);

}

function stopPropagationOnUIElements() {
    const uiElements = document.querySelectorAll('#uiWidget, #classWidget, #infoWidget, #shopWidget, #mobileControls');
    uiElements.forEach(element => {
        element.addEventListener('mousedown', (e) => e.stopPropagation());
        element.addEventListener('touchstart', (e) => e.stopPropagation());
    });
}



function lerpAngle(a, b, t) {
    const diff = b - a;
    const adjusted = ((diff + Math.PI) % (2 * Math.PI)) - Math.PI;
    return a + adjusted * t;
}

function findNearestEnemy() {
    let nearestEnemy = null;
    let nearestDistance = Infinity;

    serverEnemies.forEach(enemy => {
        const distance = Math.hypot(enemy.x - player.x, enemy.y - player.y);
        if (distance < nearestDistance) {
            nearestDistance = distance;
            nearestEnemy = enemy;
        }
    });

    return nearestEnemy;
}


// New function to draw game objects
function drawGameObjects() {
    if (!ctx) {
        console.error('Canvas context is undefined in drawGameObjects');
        return;
    }

    // Draw server-managed enemies
    serverEnemies.forEach(enemy => {
        if (isVisible(enemy.x, enemy.y)) {
            enemy.draw(ctx);
        }
    });

    // Draw server-managed bullets
    serverBullets.forEach(bullet => {
        if (isVisible(bullet.x, bullet.y)) {
            const bulletImage = bulletImageCache.get(bullet.bullet_image_source);
            if (bulletImage && bulletImage.complete) {
                ctx.save();
                ctx.translate(bullet.x, bullet.y);
                ctx.rotate(bullet.angle);
                ctx.drawImage(bulletImage, -bullet.size/2, -bullet.size/2, bullet.size, bullet.size);
                ctx.restore();
            } else {
                // Fallback to drawing a circle if the image is not loaded
                ctx.beginPath();
                ctx.arc(bullet.x, bullet.y, bullet.size, 0, Math.PI * 2);
                ctx.fillStyle = bullet.color || '#ffff00';  // Use the bullet's color or default to yellow
                ctx.fill();
                ctx.closePath();
            }
        }
    });

    impactEffects.forEach(effect => {
        if (isVisible(effect.x, effect.y)) {
            effect.draw(ctx);
        }
    });


    // Draw other players
    Object.values(otherPlayers).forEach(otherPlayer => {
        if (isVisible(otherPlayer.x, otherPlayer.y)) {
            otherPlayer.drawWeapons();
            otherPlayer.draw();
        }
    });

    // Draw Synth Coins
    synthCoins.forEach(coin => {
        if (isVisible(coin.x, coin.y)) {
            coin.draw(ctx);
        }
    });

    // Draw the player
    if (player) {
        player.drawWeapons();
        player.draw();
    }


    // Update and draw particles
    particles.forEach((particle, index) => {
        particle.update();
        if (isVisible(particle.x, particle.y)) {
            particle.draw();
        }
        if (particle.ttl <= 0) {
            particles.splice(index, 1);
        }
    });

    // Update and draw floating texts
    floatingTexts = floatingTexts.filter((text, index) => {
        text.y += text.velocity;
        text.lifetime--;

        if (text.lifetime <= 0) {
            if (text === currentCoinFloatingText) {
                currentCoinFloatingText = null;
            }
            return false;
        }

        if (isVisible(text.x, text.y)) {
            ctx.font = '16px Orbitron';
            ctx.fillStyle = text.color;
            ctx.textAlign = 'center';
            
            let drawX = text.x;
            let drawY = text.y;
            
            // For damage text (not moving up), add a slight random offset
            if (text.velocity === 0) {
                drawX += (Math.random() - 0.5) * 2; // Random X offset
                drawY += (Math.random() - 0.5) * 2; // Random Y offset
            }
            
            ctx.fillText(text.text, drawX, drawY);
        }

        return true;
    });
}


function selectClass(playerClass) {
    if (!playerClass.unlocked) {
        const unlockRequirements = playerClass.unlock_requirements_text || "Unlock requirements not available";
        notificationSystem.showNotification(`This class is locked. ${unlockRequirements}`);
        return;
    }

    selectedClassId = playerClass._id;
    const classSelector = document.getElementById('classSelector');
    const classOptions = classSelector.querySelectorAll('.class-option');
    classOptions.forEach(option => option.classList.remove('selected'));
    const selectedOption = Array.from(classOptions).find(option => option.querySelector('img').alt === playerClass.name);
    if (selectedOption) {
        selectedOption.classList.add('selected');
    }

    if (currentUser) {
        // Only send selection to server if user is logged in
        fetch('/select-class', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': getSessionToken()
            },
            body: JSON.stringify({ class_id: selectedClassId }),
        })
        .then(response => {
            if (!response.ok) {
                return response.json().then(data => {
                    throw new Error(data.error || 'Failed to select class');
                });
            }
            return response.json();
        })
        .then(data => {
            if (data.success) {
                debugLog('Class selected successfully');
                notificationSystem.showNotification(`${playerClass.name} class selected successfully!`);
            } else {
                throw new Error(data.error || 'Failed to select class');
            }
        })
        .catch(error => {
            console.error('Error selecting class:', error.message);
            notificationSystem.showNotification(`Failed to select class: ${error.message}`);
        });
    }
}

function debugShopWidget() {
    debugLog('Debugging Shop Widget:');
    const shopWidget = document.getElementById('shopWidget');
    debugLog('Shop Widget:', shopWidget);
    debugLog('Shop Widget Classes:', shopWidget.classList);
    
    const weaponSelector = document.getElementById('weaponSelector');
    debugLog('Weapon Selector:', weaponSelector);
    if (weaponSelector) {
        debugLog('Weapon Selector Children:', weaponSelector.children);
        debugLog('Weapon Selector Display:', getComputedStyle(weaponSelector).display);
    }
    
    const shopTab = document.querySelector('#shopWidget .tab-button[data-tab="shop"]');
    debugLog('Shop Tab:', shopTab);
    if (shopTab) {
        debugLog('Shop Tab Classes:', shopTab.classList);
    }
    
    const shopContent = document.querySelector('#shopWidget #shop');
    debugLog('Shop Content:', shopContent);
    if (shopContent) {
        debugLog('Shop Content Display:', getComputedStyle(shopContent).display);
    }
    
    debugLog('Player:', player);
    if (player && player.playerClass) {
        debugLog('Player Class ID:', player.playerClass._id);
    }
}


function showUnlockRequirements(playerClass) {
    const requirementsPopup = document.createElement('div');
    requirementsPopup.classList.add('requirements-popup');
    requirementsPopup.innerHTML = `
        <h3>${playerClass.name} Unlock Requirements</h3>
        <ul>
            ${Object.entries(playerClass.unlock_requirements).map(([key, value]) => `<li>${key}: ${value}</li>`).join('')}
        </ul>
        <button id="closeRequirements">Close</button>
    `;
    document.body.appendChild(requirementsPopup);
    document.getElementById('closeRequirements').addEventListener('click', () => requirementsPopup.remove());
}


function isVisible(x, y) {
    return x >= camera.x - 50 && x <= camera.x + camera.width + 50 &&
           y >= camera.y - 50 && y <= camera.y + camera.height + 50;
}

function drawJoystick() {
    const joystickX = joystick.startX;
    const joystickY = joystick.startY;
    ctx.beginPath();
    ctx.arc(joystickX, joystickY, 40, 0, Math.PI * 2);
    ctx.fillStyle = 'rgba(255, 255, 255, 0.2)';
    ctx.fill();
    ctx.closePath();

    ctx.beginPath();
    ctx.arc(joystick.endX, joystick.endY, 20, 0, Math.PI * 2);
    ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
    ctx.fill();
    ctx.closePath();
}

function handleKeyDown(e) {
    if (!gameStarted) return;
    switch(e.key) {
        case 'ArrowUp':
        case 'w':
        case 'W':
            player.keys.up = true;
            break;
        case 'ArrowDown':
        case 's':
        case 'S':
            player.keys.down = true;
            break;
        case 'ArrowLeft':
        case 'a':
        case 'A':
            player.keys.left = true;
            break;
        case 'ArrowRight':
        case 'd':
        case 'D':
            player.keys.right = true;
            break;
    }
}

function handleKeyUp(e) {
    if (!gameStarted) return;
    switch(e.key) {
        case 'ArrowUp':
        case 'w':
        case 'W':
            player.keys.up = false;
            break;
        case 'ArrowDown':
        case 's':
        case 'S':
            player.keys.down = false;
            break;
        case 'ArrowLeft':
        case 'a':
        case 'A':
            player.keys.left = false;
            break;
        case 'ArrowRight':
        case 'd':
        case 'D':
            player.keys.right = false;
            break;
    }
}

let moveTouch = null;
let aimTouch = null;

function handleTouchStart(e) {
    if (!gameStarted || !player) return;

    // Check if the touch is on a UI element
    if (e.target.closest('#uiWidget, #classWidget, #infoWidget, #shopWidget, #mobileControls')) {
        return;
    }

    e.preventDefault();

    const touches = e.changedTouches;
    for (let i = 0; i < touches.length; i++) {
        const touch = touches[i];
        if (touch.clientX < window.innerWidth / 2) {
            // Left half of the screen - movement
            moveTouch = touch;
            joystick.active = true;
            joystick.startX = joystick.endX = touch.clientX;
            joystick.startY = joystick.endY = touch.clientY;
        } else {
            // Right half of the screen - aiming and shooting
            aimTouch = touch;
            shootingJoystick.active = true;
            shootingJoystick.startX = shootingJoystick.currentX = touch.clientX;
            shootingJoystick.startY = shootingJoystick.currentY = touch.clientY;
            shootingJoystick.innerRadius = 0;
            shootingJoystick.aimAngle = 0;
        }
    }
}

function handleTouchMove(e) {
    e.preventDefault();
    if (!gameStarted || !player) return;

    const touches = e.changedTouches;
    for (let i = 0; i < touches.length; i++) {
        const touch = touches[i];
        if (touch.identifier === moveTouch?.identifier) {
            // Movement
            joystick.endX = touch.clientX;
            joystick.endY = touch.clientY;
            const dx = joystick.endX - joystick.startX;
            const dy = joystick.endY - joystick.startY;
            const distance = Math.sqrt(dx * dx + dy * dy);
            if (distance > 0) {
                const maxJoystickDistance = 40;
                const scale = Math.min(1, distance / maxJoystickDistance);
                player.velocityX = (dx / distance) * player.maxSpeed * scale;
                player.velocityY = (dy / distance) * player.maxSpeed * scale;
            }
        } else if (touch.identifier === aimTouch?.identifier) {
            // Aiming and shooting
            shootingJoystick.currentX = touch.clientX;
            shootingJoystick.currentY = touch.clientY;
            updatePlayerAim(touch.clientX, touch.clientY);
        }
    }
}

function handleTouchEnd(e) {
    e.preventDefault();
    if (!gameStarted || !player) return;

    const touches = e.changedTouches;
    for (let i = 0; i < touches.length; i++) {
        const touch = touches[i];
        if (touch.identifier === moveTouch?.identifier) {
            joystick.active = false;
            player.velocityX = 0;
            player.velocityY = 0;
            moveTouch = null;
        } else if (touch.identifier === aimTouch?.identifier) {
            shootingJoystick.active = false;
            aimTouch = null;
            player.isShooting = false;
        }
    }
}

function updateAndDrawShootingJoystick(deltaTime) {
    if (!shootingJoystick.active) {
        shootingJoystick.innerRadius = 0;
        return;
    }

    // Grow the inner circle
    shootingJoystick.innerRadius += shootingJoystick.growthRate * deltaTime;
    shootingJoystick.innerRadius = Math.min(shootingJoystick.innerRadius, shootingJoystick.maxInnerRadius);

    // Check if we should start shooting
    if (shootingJoystick.innerRadius >= shootingJoystick.maxInnerRadius * shootingJoystick.shootThreshold) {
        player.isShooting = true;
    }

    // Calculate the position of the inner circle
    const dx = shootingJoystick.currentX - shootingJoystick.startX;
    const dy = shootingJoystick.currentY - shootingJoystick.startY;
    const distance = Math.sqrt(dx * dx + dy * dy);
    const angle = Math.atan2(dy, dx);
    const cappedDistance = Math.min(distance, shootingJoystick.outerRadius);
    const innerX = shootingJoystick.startX + Math.cos(angle) * cappedDistance;
    const innerY = shootingJoystick.startY + Math.sin(angle) * cappedDistance;

    // Draw the outer circle (base of the joystick)
    ctx.beginPath();
    ctx.arc(shootingJoystick.startX, shootingJoystick.startY, shootingJoystick.outerRadius, 0, Math.PI * 2);
    ctx.fillStyle = 'rgba(255, 0, 0, 0.2)';
    ctx.fill();
    ctx.closePath();

    // Draw the inner circle (movable part of the joystick)
    ctx.beginPath();
    ctx.arc(innerX, innerY, shootingJoystick.innerRadius, 0, Math.PI * 2);
    ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
    ctx.fill();
    ctx.closePath();

    // Draw the aiming line
    ctx.beginPath();
    ctx.moveTo(shootingJoystick.startX, shootingJoystick.startY);
    ctx.lineTo(innerX, innerY);
    ctx.strokeStyle = 'rgba(255, 0, 0, 0.8)';
    ctx.lineWidth = 2;
    ctx.stroke();
}





function updatePlayerAim(clientX, clientY) {
    if (!isAutoFireEnabled && player) {
        const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
        
        if (isMobile && shootingJoystick.active) {
            // Mobile touch aiming
            const dx = shootingJoystick.currentX - shootingJoystick.startX;
            const dy = shootingJoystick.currentY - shootingJoystick.startY;
            shootingJoystick.aimAngle = Math.atan2(dy, dx);
            player.setWeaponAngle(shootingJoystick.aimAngle);
        } else {
            // Mouse aiming (for PC)
            const rect = canvas.getBoundingClientRect();
            const mouseX = clientX - rect.left + camera.x;
            const mouseY = clientY - rect.top + camera.y;
            player.mouseX = mouseX;
            player.mouseY = mouseY;
            const dx = mouseX - player.x;
            const dy = mouseY - player.y;
            const angle = Math.atan2(dy, dx);
            player.setWeaponAngle(angle);
        }
    }
}



window.addEventListener('keydown', handleKeyDown);
window.addEventListener('keyup', handleKeyUp);
canvas.addEventListener('touchstart', handleTouchStart);
canvas.addEventListener('touchmove', handleTouchMove);
canvas.addEventListener('touchend', handleTouchEnd);


document.addEventListener('visibilitychange', function() {
    if (!gameStarted || !player) return; // Only proceed if the game is running
    
    if (document.hidden) {
        wasPausedBeforeHidden = isPlayerPaused;
        if (!isPlayerPaused) {
            pausePlayer();
            socket.emit('player_paused', { isPaused: true });
        }
    } else {
        if (!wasPausedBeforeHidden && !areInterfacesOpen()) {
            unpausePlayer();
            socket.emit('player_paused', { isPaused: false });
        }
    }
});


// Modify the play button event listener
playButton.addEventListener('click', () => {
    if (socket && socket.connected) {
        // If socket is already connected, just try to join
        socket.emit('join', { room: 'main_game_room', name: currentUser || `Guest-${Math.floor(Math.random() * 10000)}`, weapon: currentWeapon });
    } else {
        startGame();
    }
    update();
});

quitButton.addEventListener('click', () => {
    window.location.reload();
    });    

// Update the window resize event handler
window.addEventListener('resize', () => {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    backgroundCanvas.width = canvas.width;
    backgroundCanvas.height = canvas.height;
    backgroundCtx.fillStyle = 'rgb(18, 4, 88)';
    backgroundCtx.fillRect(0, 0, backgroundCanvas.width, backgroundCanvas.height);
    if (camera) {
        camera.width = canvas.width;
        camera.height = canvas.height;
    }
    if (gameStarted) {
        drawExperienceBar();
        updateSynthCoinsDisplay();
    }
});

window.addEventListener('load', () => {
    const shopButton = document.getElementById('shopButton');
    if (shopButton) {
        shopButton.addEventListener('click', toggleShop);
    }
});


document.addEventListener('DOMContentLoaded', initShop);

class Particle {
    constructor(x, y, color, radius, velocityX, velocityY, ttl) {
        this.x = x;
        this.y = y;
        this.color = color;
        this.radius = radius;
        this.velocityX = velocityX;
        this.velocityY = velocityY;
        this.ttl = ttl;
    }

    update() {
        this.x += this.velocityX;
        this.y += this.velocityY;
        this.ttl--;
        this.radius *= 0.98;
    }

    draw() {
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
        ctx.fillStyle = this.color;
        ctx.fill();
        ctx.closePath();
    }
}

class ImpactEffect {
    constructor(x, y, color, size, angle) {
        this.x = x;
        this.y = y;
        this.color = color;
        this.size = size;
        this.angle = angle;
        this.lifetime = 20; // Number of frames the effect will last
        this.particles = [];
        this.generateParticles();
    }

    generateParticles() {
        const particleCount = 10;
        for (let i = 0; i < particleCount; i++) {
            const speed = Math.random() * 2 + 1;
            const angle = this.angle + (Math.random() - 0.5) * Math.PI / 2; // Spread particles in a cone
            this.particles.push({
                x: this.x,
                y: this.y,
                vx: Math.cos(angle) * speed,
                vy: Math.sin(angle) * speed,
                size: Math.random() * this.size / 2,
                color: this.color
            });
        }
    }

    update() {
        this.lifetime--;
        this.particles.forEach(particle => {
            particle.x += particle.vx;
            particle.y += particle.vy;
            particle.size *= 0.9; // Shrink particles over time
        });
    }

    draw(ctx) {
        this.particles.forEach(particle => {
            ctx.beginPath();
            ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2);
            ctx.fillStyle = particle.color;
            ctx.fill();
        });
    }
}



init();