/*
	The WindowManager is responsible for creation, destruction, modification and tracking of game UI windows.
*/

class WindowManager
{
	constructor(container)
	{
		this.windows = {}
		this.container = container
	}

	updateWindow(id, content, title = '')
	{
		if (id in this.windows) {
			let w = this.windows[id]
			w.querySelector('header .title').innerHTML = title
			w.querySelector('.body').innerHTML = content
			this.bringToFront(w)
			return
		}

		let w = this.createWindow(id, content, title)
		this.bringToFront(w)
	}

	createWindow(id, content, title = '')
	{
		// create window
		let w = document.createElement('div')
		w.id = `window-${id}`
		w.classList.add('window')

		// create header
		let h = document.createElement('header')
		w.appendChild(h)

		// create header title
		let ht = document.createElement('span')
		ht.classList.add('title')
		ht.innerHTML = title
		h.appendChild(ht)

		// create close button
		ht.insertAdjacentHTML('afterend', '<a class="close"><img src="/assets/img/ui/icons/bullet_red.png"></a>')
		h.querySelector('a.close').addEventListener('click', () => {
			this.windows[id].remove()
			delete this.windows[id]
		})

		// create body
		let b = document.createElement('div')
		b.classList.add('body')
		b.innerHTML = content
		w.appendChild(b)

		// track window and add it to the container
		this.makeWindowDraggable(w, this.container)
		this.windows[id] = w
		this.container.appendChild(w)
		return w
	}

	makeWindowDraggable(w, c)
	{
		const header = w.querySelector('header');
		if (!header) return;

		let isDragging = false;
		let currentX;
		let currentY;
		let initialX;
		let initialY;

		header.addEventListener('mousedown', startDragging);
		document.addEventListener('mousemove', drag);
		document.addEventListener('mouseup', stopDragging);

        w.addEventListener('mousedown', () => this.bringToFront(w));

		function startDragging(e)
		{
			isDragging = true;
			initialX = e.clientX - w.offsetLeft;
			initialY = e.clientY - w.offsetTop;
		}

		function drag(e)
		{
			if (!isDragging) return;

			e.preventDefault();

			// Calculate new position
			currentX = e.clientX - initialX;
			currentY = e.clientY - initialY;

			// Get viewport dimensions
			const viewportWidth = window.innerWidth;
			const viewportHeight = window.innerHeight;

			// Get window dimensions
			const windowRect = w.getBoundingClientRect();

			// Constrain to viewport bounds
			// Left edge
			currentX = Math.max(0, currentX);
			// Right edge
			currentX = Math.min(viewportWidth - windowRect.width, currentX);
			// Top edge
			currentY = Math.max(0, currentY);
			// Bottom edge
			currentY = Math.min(viewportHeight - windowRect.height, currentY);

			// Apply the constrained position
			w.style.left = currentX + 'px';
			w.style.top = currentY + 'px';
		}

		function stopDragging()
		{
			isDragging = false;
		}

		// Handle window resize
		window.addEventListener('resize', () => {
			// Get current position and dimensions
			const rect = w.getBoundingClientRect();
			const viewportWidth = window.innerWidth;
			const viewportHeight = window.innerHeight;

			// Adjust position if window is outside viewport after resize
			let newX = parseInt(w.style.left);
			let newY = parseInt(w.style.top);

			// Constrain to new viewport bounds
			newX = Math.min(Math.max(0, newX), viewportWidth - rect.width);
			newY = Math.min(Math.max(0, newY), viewportHeight - rect.height);

			w.style.left = newX + 'px';
			w.style.top = newY + 'px';
		});
	}

	normalizeZIndices()
	{
        const array = Array.from(this.windows);
        array.sort((a, b) => (parseInt(a.style.zIndex) || 0) - (parseInt(b.style.zIndex) || 0));

        // Reassign z-indices starting from 1
        array.forEach((win, index) => {
            win.style.zIndex = index + 1;
        });

        return array.length + 1; // Return next available z-index
    }

	bringToFront(windowElement)
	{
        const currentMax = Math.max(...Object.values(this.windows)
            .map(w => parseInt(w.style.zIndex) || 0));

		if (parseInt(windowElement.style.zIndex) >= currentMax) {
			return
		}

        // If z-index is getting too high, normalize all z-indices
        if (currentMax > 10000) {
            const newZ = this.normalizeZIndices();
            windowElement.style.zIndex = newZ;
        } else {
            windowElement.style.zIndex = currentMax + 1;
        }
    }
}
