//
// shelfShape.js — Manifold Shop Entity Script
//
// Attach to each shelf shape entity. Set userData to:
//   {"shapeId": "tetrahedron"}
//
// Clones are domain-owned. The domain script (manifoldDomain.js) handles
// all cleanup via WebSocket presence events and recall messages.
//

(function () {
    var API_BASE     = "https://wizards.cyou/api";
    var SPAWN_OFFSET = { x: 0, y: 0.3, z: 0.5 };

    var SHAPE_TYPE = {
        tetrahedron:  "Tetrahedron",
        hexahedron:   "Box",
        octahedron:   "Octahedron",
        dodecahedron: "Dodecahedron",
        icosahedron:  "Icosahedron",
    };

    var SHAPE_COLOR = {
        tetrahedron:  { red: 255, green: 180, blue:  60 },
        hexahedron:   { red: 180, green: 220, blue: 255 },
        octahedron:   { red: 140, green: 255, blue: 180 },
        dodecahedron: { red: 255, green: 120, blue: 180 },
        icosahedron:  { red: 200, green: 140, blue: 255 },
    };

    var _entityID = null;
    var _shapeId  = null;
    var _token    = null;
    var _username = null;
    var _busy     = false;

    // ── helpers ──────────────────────────────────────────────────

    function getShapeId() {
        try {
            var props = Entities.getEntityProperties(_entityID, ["userData"]);
            return JSON.parse(props.userData || "{}").shapeId || null;
        } catch (e) { return null; }
    }

    function notify(msg) {
        Window.displayAnnouncement(msg);
    }

    // ── session ──────────────────────────────────────────────────

    function ensureSession(cb) {
        if (_token) { cb(null, _token); return; }
        _username = MyAvatar.displayName;
        if (!_username) { cb("Not logged in to Overte"); return; }

        var xhr = new XMLHttpRequest();
        xhr.open("POST", API_BASE + "/session", true);
        xhr.setRequestHeader("Content-Type", "application/json");
        xhr.onreadystatechange = function () {
            if (xhr.readyState !== 4) return;
            if (xhr.status === 200) {
                try {
                    _token = JSON.parse(xhr.responseText).token;
                    Script.setTimeout(function () { _token = null; }, 5 * 60 * 1000);
                    cb(null, _token);
                } catch (e) { cb("Session parse error"); }
            } else if (xhr.status === 403) {
                cb("Must be in-world to use the shop");
            } else {
                cb("Session error (" + xhr.status + ")");
            }
        };
        xhr.send(JSON.stringify({ username: _username }));
    }

    // ── inventory ────────────────────────────────────────────────

    function getInventory(cb) {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", API_BASE + "/inventory/" + _username, true);
        xhr.onreadystatechange = function () {
            if (xhr.readyState !== 4) return;
            if (xhr.status === 200) {
                try { cb(null, JSON.parse(xhr.responseText).inventory || {}); }
                catch (e) { cb("Inventory parse error"); }
            } else {
                cb("Inventory fetch failed (" + xhr.status + ")");
            }
        };
        xhr.send();
    }

    function countLiveClones(username, shapeId) {
        // Scan both Shape and Box — hexahedron/cube uses the Box entity type
        var results = Entities.findEntitiesByType("Shape", MyAvatar.position, 100)
            .concat(Entities.findEntitiesByType("Box", MyAvatar.position, 100));
        var count = 0;
        results.forEach(function (id) {
            try {
                var ud = JSON.parse(Entities.getEntityProperties(id, ["userData"]).userData || "{}");
                if (ud.manifoldClone && ud.owner === username && ud.shapeId === shapeId) count++;
            } catch (e) {}
        });
        return count;
    }

    // ── spawn ────────────────────────────────────────────────────

    function spawnClone() {
        var shelfProps = Entities.getEntityProperties(_entityID, ["position", "rotation"]);
        var spawnPos   = Vec3.sum(shelfProps.position,
                            Vec3.multiplyQbyV(shelfProps.rotation, SPAWN_OFFSET));

        var shapeType  = SHAPE_TYPE[_shapeId] || "Sphere";
        var entityType = (shapeType === "Box") ? "Box" : "Shape";
        Entities.addEntity({
            type:          entityType,
            shape:         shapeType,
            name:          "manifold_" + _shapeId + "_" + _username,
            position:      spawnPos,
            dimensions:    { x: 0.25, y: 0.25, z: 0.25 },
            color:         SHAPE_COLOR[_shapeId] || { red: 200, green: 200, blue: 200 },
            userData:      JSON.stringify({ manifoldClone: true, owner: _username, shapeId: _shapeId }),
            dynamic:       true,
            grabbable:     true,
            restitution:   0.6,
            friction:      0.4,
            density:       800,
            emissive:      true,
            lifetime:      3600,   // hard ceiling fallback
        }, "domain");
    }

    // ── click handler ────────────────────────────────────────────

    function onClickDown() {
        if (_busy) return;
        _busy = true;

        _shapeId = getShapeId();
        if (!_shapeId) {
            notify("Shop item not configured (missing shapeId in userData)");
            _busy = false;
            return;
        }

        ensureSession(function (err) {
            if (err) { notify(err); _busy = false; return; }

            getInventory(function (err, inventory) {
                if (err) { notify(err); _busy = false; return; }

                var owned = inventory[_shapeId] || 0;
                if (owned === 0) {
                    notify("You don't own any " + _shapeId + "s. Buy one in the Manifold tablet.");
                    _busy = false;
                    return;
                }

                var live = countLiveClones(_username, _shapeId);
                if (live >= owned) {
                    notify("You have " + live + "/" + owned + " " + _shapeId +
                           "(s) active. Recall them or buy more.");
                    _busy = false;
                    return;
                }

                spawnClone();
                notify("Spawned " + _shapeId + " (" + (live + 1) + "/" + owned + " active)");
                // _busy stays true until trigger release (stopNearTrigger/stopFarTrigger/clickUpOnEntity)
            });
        });
    }

    // ── lifecycle ────────────────────────────────────────────────

    this.preload = function (entityID) {
        _entityID = entityID;
    };

    // Mouse
    this.clickDownOnEntity  = function () { onClickDown(); };
    this.clickReleaseOnEntity    = function () { _busy = false; };

    // Controller — near (<0.3m) and far (>0.3m)
    // Requires "Triggerable" checkbox enabled on the entity.
    this.startNearTrigger = function () { onClickDown(); };
    this.stopNearTrigger  = function () { _busy = false; };
    this.startFarTrigger  = function () { onClickDown(); };
    this.stopFarTrigger   = function () { _busy = false; };

    this.unload = function () {
        _token = null;
        _username = null;
    };
});
