/**
 * Class for handling zoom operations.
 */
class ZoomManager {
    /**
     * Creates a new instance of the ZoomManager class.
     * @param {boolean} horizontalZoom - Indicates if horizontal zoom is enabled.
     * @param {boolean} verticalZoom - Indicates if vertical zoom is enabled.
     */
    constructor(horizontalZoom, verticalZoom) {
        this.x = 0 // Horizontal position
        this.y = 0 // Vertical position
        this.scaleX = 1 // Horizontal scale
        this.scaleY = 1 // Vertical scale
        this.horizontalZoom = horizontalZoom // Flag for horizontal zoom
        this.verticalZoom = verticalZoom // Flag for vertical zoom

        this.lastPos = {
            x: 0,
            y: 0
        }
    }

    /**
     * Convert world coordinates to screen coordinates.
     * 
     * @param {number} worldX - The x-coordinate in world space.
     * @param {number} worldY - The y-coordinate in world space.
     * @returns {Array} The screen coordinates [screenX, screenY].
     */
    worldToScreen(worldX, worldY) {
        let screenX = (worldX - this.x) * this.scaleX
        let screenY = (worldY - this.y) * this.scaleY
        return {
            x: screenX,
            y: screenY
        }
    }

    /**
     * Convert screen coordinates to world coordinates.
     * 
     * @param {number} screenX - The x-coordinate on the screen.
     * @param {number} screenY - The y-coordinate on the screen.
     * @returns {Array} The world coordinates [worldX, worldY].
     */
    screenToWorld(screenX, screenY) {
        let worldX = screenX / this.scaleX + this.x
        let worldY = screenY / this.scaleY + this.y
        return {
            x: worldX,
            y: worldY
        }
    }

    /**
     * Recalculates zoom based on mouse wheel event or panning.
     * @param {MouseEvent} event - The mouse wheel event object.
     * @param {boolean} [panning=false] - Whether panning is enabled.
     */
    recalculate(event, panning = false) {
        // Get mouse position
        const pos = {
            x: event.clientX,
            y: event.clientY
        }

        // Zooming
        if (event.deltaY) {
            // Calculate world coordinates before zoom
            let beforeZoom, afterZoom
            beforeZoom = this.screenToWorld(pos.x, pos.y)

            // Adjust zoom scale based on mouse wheel delta
            if (this.horizontalZoom)
                this.scaleX -= (10 * this.scaleX) / event.deltaY
            if (this.verticalZoom)
                this.scaleY -= (10 * this.scaleY) / event.deltaY

            // Calculate world coordinates after zoom
            afterZoom = this.screenToWorld(pos.x, pos.y)

            // Adjust zoom position to keep zoom centered around mouse position
            this.x += beforeZoom.x - afterZoom.x
            this.y += beforeZoom.y - afterZoom.y
        }

        // Panning
        if (panning) {
            // Only pan if the mouse movement exceeds minimum distance
            if ((this.lastPos.x - pos.x) ** 2 + (this.lastPos.y - pos.y) ** 2 > 10) {
                if (this.horizontalZoom)
                    this.x += (this.lastPos.x - pos.x) / this.scaleX
                if (this.verticalZoom)
                    this.y += (this.lastPos.y - pos.y) / this.scaleY
                this.lastPos = pos
            }
        }

        // Reset zoom if it goes below 1
        if (this.scaleX < 1 || this.scaleY < 1) {
            this.x = 0
            this.y = 0
            this.scaleX = 1
            this.scaleY = 1
        }
    }
}
