'use strict';

/* ────────────────────────────────────────────────────────────────
   Camera2D — 2D camera with follow, shake, zoom
──────────────────────────────────────────────────────────────── */
class Camera2D {
    constructor(viewportWidth, viewportHeight) {
        this.position = { x: 0, y: 0 };
        this.zoom = 1;
        this.rotation = 0;
        this._target = null;
        this._smoothing = 0.1;
        this._deadzone = { x: 0, y: 0 };
        this._bounds = null;
        this._shake = null;
        this._shakeOffset = { x: 0, y: 0 };
        this._viewportWidth = viewportWidth;
        this._viewportHeight = viewportHeight;
    }
    /* ── Getters ────────────────────────────────────────────────── */
    get viewportWidth() { return this._viewportWidth; }
    get viewportHeight() { return this._viewportHeight; }
    get worldBounds() {
        const hw = (this._viewportWidth / 2) / this.zoom;
        const hh = (this._viewportHeight / 2) / this.zoom;
        return {
            x: this.position.x - hw + this._shakeOffset.x,
            y: this.position.y - hh + this._shakeOffset.y,
            width: hw * 2,
            height: hh * 2,
        };
    }
    /* ── Follow ─────────────────────────────────────────────────── */
    follow(target, smoothing = 0.1, deadzone) {
        this._target = target;
        this._smoothing = smoothing;
        if (deadzone)
            this._deadzone = deadzone;
    }
    unfollow() {
        this._target = null;
    }
    /** Set world boundaries the camera cannot exceed. */
    setBounds(bounds) {
        this._bounds = bounds;
    }
    /* ── Shake ──────────────────────────────────────────────────── */
    shake(intensity, duration, decay = true) {
        this._shake = { intensity, duration, elapsed: 0, decay };
    }
    /* ── Coordinate conversion ──────────────────────────────────── */
    /** World position → screen position */
    worldToScreen(world) {
        return {
            x: (world.x - this.position.x - this._shakeOffset.x) * this.zoom + this._viewportWidth / 2,
            y: (world.y - this.position.y - this._shakeOffset.y) * this.zoom + this._viewportHeight / 2,
        };
    }
    /** Screen position → world position */
    screenToWorld(screen) {
        return {
            x: (screen.x - this._viewportWidth / 2) / this.zoom + this.position.x + this._shakeOffset.x,
            y: (screen.y - this._viewportHeight / 2) / this.zoom + this.position.y + this._shakeOffset.y,
        };
    }
    /** Check if a world-space rect is visible. */
    isVisible(rect) {
        const vb = this.worldBounds;
        return !(rect.x + rect.width < vb.x ||
            rect.x > vb.x + vb.width ||
            rect.y + rect.height < vb.y ||
            rect.y > vb.y + vb.height);
    }
    resize(width, height) {
        this._viewportWidth = width;
        this._viewportHeight = height;
    }
    /* ── Update ─────────────────────────────────────────────────── */
    update(dt) {
        // Follow target
        if (this._target) {
            const dx = this._target.x - this.position.x;
            const dy = this._target.y - this.position.y;
            // Apply deadzone
            if (Math.abs(dx) > this._deadzone.x) {
                this.position.x += dx * this._smoothing;
            }
            if (Math.abs(dy) > this._deadzone.y) {
                this.position.y += dy * this._smoothing;
            }
        }
        // Clamp to bounds
        if (this._bounds) {
            const hw = (this._viewportWidth / 2) / this.zoom;
            const hh = (this._viewportHeight / 2) / this.zoom;
            this.position.x = Math.max(this._bounds.x + hw, Math.min(this._bounds.x + this._bounds.width - hw, this.position.x));
            this.position.y = Math.max(this._bounds.y + hh, Math.min(this._bounds.y + this._bounds.height - hh, this.position.y));
        }
        // Shake
        if (this._shake) {
            this._shake.elapsed += dt;
            if (this._shake.elapsed >= this._shake.duration) {
                this._shake = null;
                this._shakeOffset = { x: 0, y: 0 };
            }
            else {
                let intensity = this._shake.intensity;
                if (this._shake.decay) {
                    intensity *= 1 - this._shake.elapsed / this._shake.duration;
                }
                this._shakeOffset = {
                    x: (Math.random() * 2 - 1) * intensity,
                    y: (Math.random() * 2 - 1) * intensity,
                };
            }
        }
    }
    /** Apply camera transform to a Canvas2D context. */
    applyTransform(ctx) {
        ctx.setTransform(1, 0, 0, 1, 0, 0);
        ctx.translate(this._viewportWidth / 2, this._viewportHeight / 2);
        ctx.scale(this.zoom, this.zoom);
        ctx.rotate(-this.rotation);
        ctx.translate(-(this.position.x + this._shakeOffset.x), -(this.position.y + this._shakeOffset.y));
    }
}

exports.Camera2D = Camera2D;
//# sourceMappingURL=Camera2D.js.map
