import { Direction, TicksPerSecond, system, world } from "@minecraft/server";
import * as mcui from "@minecraft/server-ui";
import PlayerHelper from "./PlayerHelper";
import FSPlayerPerms, { FSPlayerAccessLevel } from "./fs/libs/perms/FSPlayerPerms";
import PlayerManager from "./PlayerManager";
import EntityManager from "./EntityManager";
import FSUtil from "./fs/FSUtil";
import FSEntityPerms from "./fs/libs/perms/FSEntityPerms";
import FSDynamicProperty from "./fs/libs/FSDynamicProperty";
import FSLocalizedString from "./fs/FSLocalizedString";
import FSEntityHelper from "./fs/FSEntityHelper";
import FSInventoryManager from "./fs/libs/FSInventoryManager";
import FormManager from "./FormManager";
import FSPlayer from "./fs/FSPlayer";
import FSWorldHelper from "./fs/FSWorldHelper";
export default class CameraManager {
    constructor() {
        this.locs = [];
    }
    static sharedInstance() {
        if (!CameraManager.instance) {
            CameraManager.instance = new CameraManager();
        }
        return CameraManager.instance;
    }
    init() {
        this.locs = JSON.parse(world.getDynamicProperty("locs") || "[]");
        world.afterEvents.entityLoad.subscribe(this.handleEntityLoad.bind(this));
        world.afterEvents.entitySpawn.subscribe(this.handleEntitySpawn.bind(this));
        world.afterEvents.entityDie.subscribe(this.handleEntityDie.bind(this));
        world.afterEvents.entityRemove.subscribe(this.handleEntityRemove.bind(this));
    }
    static onItemUsed(player, item) {
        if (player.isSneaking) {
            PlayerManager.sharedInstance().confirmCameraPlacement(player);
            return;
        }
        const location = player.getHeadLocation();
        const direction = player.getViewDirection();
        const snappedRotation = PlayerHelper.getSnappedRotation(player, true);
        const dimension = player.dimension;
        let placement = "wall";
        const rco = {
            maxDistance: 8,
            includeLiquidBlocks: true,
            includePassableBlocks: true
        };
        const raycast_hit = dimension.getBlockFromRay(location, direction, rco);
        if (raycast_hit && raycast_hit.block) {
            const block = raycast_hit.block;
            const face = raycast_hit.face;
            let rotation = 0;
            let adjacentBlock = undefined;
            switch (face) {
                case Direction.North:
                    adjacentBlock = block.north(1);
                    rotation = 180;
                    break;
                case Direction.South:
                    adjacentBlock = block.south(1);
                    rotation = 0;
                    break;
                case Direction.West:
                    adjacentBlock = block.west(1);
                    rotation = 90;
                    break;
                case Direction.East:
                    adjacentBlock = block.east(1);
                    rotation = 270;
                    break;
                case Direction.Up:
                    adjacentBlock = block.above(1);
                    rotation = snappedRotation;
                    placement = "floor";
                    break;
                case Direction.Down:
                    adjacentBlock = block.below(1);
                    rotation = snappedRotation;
                    placement = "ceiling";
                    break;
            }
            if (adjacentBlock && adjacentBlock.permutation.matches("minecraft:air")) {
                const spawn_location = adjacentBlock.bottomCenter();
                const event = `fs_sbunk:set_placement_${placement}`;
                const command = `summon 57d_sbunk:camera ${spawn_location.x} ${spawn_location.y} ${spawn_location.z} ${rotation} 0 ${event}`;
                const result = dimension.runCommand(command);
                if (result.successCount > 0) {
                    if (!FSPlayer.isCreative(player)) {
                        FSInventoryManager.removeItem(player, item, 1);
                    }
                }
            }
            else {
                player.playSound("fs.sbunk.chat_ping");
                world.sendMessage({ translate: FSLocalizedString.localize("chat.camera.invalid_location", "§c[!] Invalid location", "Invalid location") });
            }
        }
    }
    tickCameras() {
        const camera_tag = FSUtil.namespacedString("send_notifications");
        const eqo = {
            type: "57d_sbunk:camera",
            tags: [camera_tag]
        };
        const cameras = world.getDimension("overworld").getEntities(eqo);
        const players = world.getAllPlayers();
        const camera_radius = 10;
        cameras.forEach(camera => {
            if (camera.isValid() === true) {
                const camera_tag_0 = `camera_${camera.id}_0`;
                const camera_tag_1 = `camera_${camera.id}_1`;
                players.forEach(player => {
                    player.removeTag(camera_tag_0);
                    player.removeTag(camera_tag_1);
                });
                const eqo0 = {
                    maxDistance: camera_radius,
                    location: camera.location
                };
                const camera_players_0 = camera.dimension.getPlayers(eqo0);
                camera_players_0.forEach(player => {
                    player.addTag(camera_tag_0);
                });
                const eqo1 = {
                    maxDistance: camera_radius,
                    location: EntityManager.getLocationOffsetByRotation(camera, 0, 0, camera_radius),
                    tags: [camera_tag_0]
                };
                const camera_players_1 = camera.dimension.getPlayers(eqo1);
                camera_players_1.forEach(player => {
                    player.addTag(camera_tag_1);
                });
                players.forEach(player => {
                    if (player.hasTag(camera_tag_0) && player.hasTag(camera_tag_1) && !FSPlayerPerms.sharedInstance().hasAccessLevel(player, FSEntityPerms.getEntityPermission(camera))) {
                        PlayerHelper.seenByCamera(player, camera);
                    }
                    else {
                        PlayerHelper.tickCameraTimeout(player, camera);
                    }
                });
            }
        });
    }
    clear() {
        this.locs = [];
        world.setDynamicProperty("locs", JSON.stringify(this.locs));
        world.getDimension("overworld").runCommand("/kill @e[type=57d_sbunk:camera]");
    }
    getLocs(accessLevels = []) {
        this.locs = JSON.parse(world.getDynamicProperty("locs") || "[]");
        if (accessLevels.length > 0) {
            return this.locs.filter(loc => {
                return accessLevels.includes(loc.access_level);
            });
        }
        return this.locs;
    }
    updateNameAndAccessLevel(id, name, access_level) {
        this.locs = JSON.parse(world.getDynamicProperty("locs") || "[]");
        let array = new Array();
        this.locs.forEach(loc => {
            if (loc.id === id) {
                loc.name = name;
                loc.access_level = access_level;
            }
            array.push(loc);
        });
        this.locs = array;
        world.setDynamicProperty("locs", JSON.stringify(this.locs));
    }
    getLocationDataForCameraId(id) {
        this.locs = JSON.parse(world.getDynamicProperty("locs") || "[]");
        let loc = null;
        this.locs.forEach(location => {
            if (location.id === id) {
                loc = location;
            }
        });
        return loc;
    }
    handleEntityLoad(eventData) {
        this.handleEntityLoaded(eventData.entity);
    }
    handleEntitySpawn(eventData) {
        this.handleEntityLoaded(eventData.entity);
    }
    getCameraNumber() {
        let number = FSDynamicProperty.getNumber(world, FSUtil.namespacedString("cameraNumber")) || 0;
        if (number === 0) {
            number = this.getLocs().length + 1;
            FSDynamicProperty.setNumber(world, FSUtil.namespacedString("cameraNumber"), number);
        }
        return number;
    }
    incrementCameraNumber() {
        let number = this.getCameraNumber();
        number++;
        FSDynamicProperty.setNumber(world, FSUtil.namespacedString("cameraNumber"), number);
    }
    handleEntityLoaded(entity) {
        const entityTypeId = entity.typeId;
        if (entityTypeId === "57d_sbunk:camera") {
            const placement = entity.getProperty("property:fs_sbunk_placement") || "wall";
            if (placement === "floor" || placement === "ceiling") {
                entity.triggerEvent("fs:enable_gravity");
                system.runTimeout(() => {
                    if (entity.isValid()) {
                        entity.triggerEvent("fs:disable_gravity");
                    }
                }, TicksPerSecond * 2);
                system.runTimeout(() => {
                    if (entity.isValid()) {
                        entity.triggerEvent("fs:set_collision_box_smaller");
                    }
                }, TicksPerSecond * 3);
                if (placement === "ceiling") {
                    const eeo = {
                        showParticles: false,
                        amplifier: 255
                    };
                    entity.addEffect("levitation", TicksPerSecond * 3, eeo);
                }
            }
            this.locs = JSON.parse(world.getDynamicProperty("locs") || "[]");
            let found = false;
            this.locs.forEach(loc => {
                if (loc.id === entity.id) {
                    found = true;
                }
            });
            FSEntityHelper.snapRotation(entity);
            if (!found) {
                const shouldSuppressNewCameraNotifications = FSDynamicProperty.getBoolean(world, FSUtil.namespacedString("shouldSuppressNewCameraNotifications")) || false;
                if (!shouldSuppressNewCameraNotifications) {
                    const msg = {
                        rawtext: [
                            { text: "§g[!] " },
                            {
                                translate: FSLocalizedString.localize("camera.added", "A new camera has been added!", "Output to chat when a new camera is added by a player.")
                            }
                        ]
                    };
                    FSPlayerPerms.sharedInstance().forceSendMessageToAllAdmins(msg);
                    FSDynamicProperty.setBoolean(world, FSUtil.namespacedString("shouldSuppressNewCameraNotifications"), false);
                }
                entity.nameTag = "Camera " + (this.getCameraNumber() + 1);
                FSEntityPerms.setEntityCustomName(entity, entity.nameTag);
                FSEntityPerms.setEntityPermission(entity, FSPlayerAccessLevel.Everyone);
                entity.nameTag = FSEntityPerms.getEntityCustomName(entity);
                this.incrementCameraNumber();
                const loc = {
                    id: entity.id,
                    name: entity.nameTag,
                    location: entity.location,
                    rotation: entity.getRotation().y,
                    access_level: FSPlayerAccessLevel.Everyone,
                    placement: placement
                };
                this.locs.push(loc);
            }
            world.setDynamicProperty("locs", JSON.stringify(this.locs));
            return;
        }
    }
    handleEntityRemove(eventData) {
        if (eventData.typeId === "57d_sbunk:camera") {
            this.handleCameraUnloaded(eventData.removedEntityId);
        }
    }
    handleEntityDie(eventData) {
        if (eventData.deadEntity.typeId === "57d_sbunk:camera") {
            this.handleCameraUnloaded(eventData.deadEntity.id);
        }
    }
    handleCameraUnloaded(id) {
        this.locs = JSON.parse(world.getDynamicProperty("locs") || "[]");
        let array = new Array();
        this.locs.forEach(loc => {
            if (loc.id !== id) {
                array.push(loc);
            }
        });
        this.locs = array;
        world.setDynamicProperty("locs", JSON.stringify(this.locs));
    }
    canShowCameraDialogue(accessLevels = [], displayAddCamera = true) {
        const locs = CameraManager.sharedInstance().getLocs(accessLevels);
        if (!displayAddCamera && locs.length === 0) {
            return false;
        }
        return locs.length > 0;
    }
    showCameraDialogue(player, accessLevels = [], displayAddCamera = true) {
        const locs = CameraManager.sharedInstance().getLocs(accessLevels);
        if (!displayAddCamera && locs.length === 0) {
            return false;
        }
        const form = new mcui.ActionFormData();
        form.title({
            rawtext: [
                {
                    translate: FSLocalizedString.localize("ui.camera.manage.title", "Cameras", "Title for cameras user interface")
                }
            ]
        });
        form.body({
            rawtext: [
                {
                    translate: FSLocalizedString.localize("ui.camera.manage.body_tip", "[Tip!] Try adding a Computer Monitor to quickly access your cameras!", "Camera tip message")
                }
            ]
        });
        const addButtonText = {
            rawtext: [
                {
                    translate: FSLocalizedString.localize("ui.camera.manage.add", "Add Camera", "Button to add a new camera")
                }
            ]
        };
        if (displayAddCamera) {
            form.button(addButtonText, "textures/57digital/sbunk/items/camera.png");
        }
        locs.forEach(loc => {
            let buttonTitle = loc.name;
            buttonTitle = buttonTitle.replace("§7[§7", "§8[§8");
            buttonTitle = buttonTitle.replace("§7]§7", "§8]§8");
            buttonTitle = buttonTitle.replace("§7]", "§8]");
            buttonTitle = buttonTitle.replace("§7", "§8");
            form.button(buttonTitle);
        });
        form.button({
            rawtext: [
                {
                    translate: FSLocalizedString.localize("ui.camera.manage.cancel", "Cancel", "Cancels adding a camera")
                }
            ]
        });
        form.show(player).then(resp => {
            if (resp.canceled) {
                FSInventoryManager.replaceItemInHand(player, "fs_sbunk:tablet", 1);
                FSWorldHelper.replaceTablets();
                return;
            }
            FSDynamicProperty.setBoolean(world, FSUtil.namespacedString("shouldSuppressNewCameraNotifications"), false);
            let selection = resp.selection || 0;
            if (displayAddCamera && selection == 0) {
                FormManager.sharedInstance().showCameraInfo(player);
            }
            else {
                if (displayAddCamera) {
                    selection -= 1;
                }
                if (selection < locs.length) {
                    let loc = locs[selection];
                    if (loc) {
                        let holdingCorrectSecurityCard = false;
                        switch (loc.access_level) {
                            case FSPlayerAccessLevel.Red:
                                holdingCorrectSecurityCard = FSInventoryManager.hasItem(player, "57d_sbunk:security_card_red", 1);
                                break;
                            case FSPlayerAccessLevel.Yellow:
                                holdingCorrectSecurityCard = FSInventoryManager.hasItem(player, "57d_sbunk:security_card_yellow", 1);
                                break;
                            case FSPlayerAccessLevel.Green:
                                holdingCorrectSecurityCard = FSInventoryManager.hasItem(player, "57d_sbunk:security_card_green", 1);
                                break;
                            case FSPlayerAccessLevel.Orange:
                                holdingCorrectSecurityCard = FSInventoryManager.hasItem(player, "57d_sbunk:security_card_orange", 1);
                                break;
                            case FSPlayerAccessLevel.Blue:
                                holdingCorrectSecurityCard = FSInventoryManager.hasItem(player, "57d_sbunk:security_card_blue", 1);
                                break;
                            case FSPlayerAccessLevel.Pink:
                                holdingCorrectSecurityCard = FSInventoryManager.hasItem(player, "57d_sbunk:security_card_pink", 1);
                                break;
                        }
                        if (FSPlayerPerms.sharedInstance().hasAccessLevel(player, loc.access_level) || holdingCorrectSecurityCard) {
                            let camera = world.getEntity(loc.id);
                            if (camera && camera.isValid()) {
                                if (accessLevels.length > 0) {
                                    PlayerHelper.becomeCamera(player, loc);
                                }
                                else {
                                    FSEntityPerms.showEntityPermissionMenu(player, camera);
                                }
                            }
                            else {
                                player.sendMessage({
                                    rawtext: [
                                        { text: "§c" },
                                        {
                                            translate: FSLocalizedString.localize("ui.camera.place.reach.error", "Error accessing camera! Please try again.", "Error if camera can not be reached.")
                                        },
                                        { text: "\n§r" },
                                        {
                                            translate: FSLocalizedString.localize("ui.camera.place.reach.tip", "This camera may be out of range. It is located at: %s.", "Error if camera can not be reached."),
                                            with: [`${loc.location.x} ${loc.location.y} ${loc.location.z}`]
                                        }
                                    ]
                                });
                                player.playSound("fs.sbunk.chat_ping");
                                PlayerHelper.confirmTeleportToCameraWithId(player, loc.id, true);
                            }
                        }
                        else {
                            player.sendMessage({
                                rawtext: [
                                    { text: "§c[!] " },
                                    {
                                        translate: FSLocalizedString.localize("ui.camera.place.access.error", "You do not have access to this camera!", "The player tried to access a camera that they do not have permission to access.")
                                    }
                                ]
                            });
                        }
                    }
                    else {
                        player.sendMessage({
                            rawtext: [
                                { text: "§c[!] " },
                                {
                                    translate: FSLocalizedString.localize("ui.camera.place.access.error2", "Error accessing camera!", "There was an error accessing the camera")
                                }
                            ]
                        });
                    }
                }
            }
        });
        return locs.length > 0;
    }
    _addCamera(player) {
        if (!FSPlayerPerms.sharedInstance().isAdmin(player)) {
            PlayerHelper.outputAdminAccessRequired(player);
            return;
        }
        FSInventoryManager.replaceItemInHand(player, "fs_sbunk:tablet_camera", 1);
        FSWorldHelper.replaceTablets();
        try {
            const placementMessageText = {
                rawtext: [
                    { text: "§a" },
                    {
                        translate: FSLocalizedString.localize("ui.camera.place.tip2", "[TIP] Look where you want to place the camera and use your Security Tablet item to place it.", "Tip for player to place camera")
                    }
                ]
            };
            player.sendMessage(placementMessageText);
            PlayerManager.sharedInstance().enterCameraPlacementMode(player);
        }
        catch (ex) {
            player.sendMessage({
                rawtext: [
                    { text: "§c" },
                    {
                        translate: FSLocalizedString.localize("ui.camera.place.error2", "Error adding camera! Try that again.", "Error if camera can not be placed")
                    }
                ]
            });
        }
    }
    static outputUseTabletMessage(player) {
        player.playSound("fs.sbunk.chat_ping");
        player.sendMessage({
            rawtext: [{ text: "§b[!] " }, { translate: FSLocalizedString.localize("camera.use_tablet_to_view", "Use your Security Tablet to view camera options.", "Message to inform players they should use their security tablet to view camera options.") }]
        });
    }
}

//# sourceMappingURL=../../../_SBUNK_BPDebug/fs_sbunk/CameraManager.js.map
