import { mcerror } from "./log";
import { SafetyCheckedEntity } from "./entity";
/**
 * @remarks Reads a custom object stored on the entity, world, or item. Automatically parses object as JSON.
 * @param subject The entity, world, or item to read properties from.
 * @param propertyName The name of the property.
 * @returns The object stored as a property, may be undefined.
 * @example
 * ```typescript
 * const ownerName = readDynamicProperty<string>(entity, 'ownerName'); // Returns the string owner name or undefined if the property is absent.
 * ```
 */
export function readDynamicProperty(subject, propertyName) {
    if (subject instanceof SafetyCheckedEntity)
        subject = subject.UnsafeEntity;
    const property = subject.getDynamicProperty(propertyName);
    if (typeof property === "string") {
        try {
            return JSON.parse(property);
        }
        catch (error) { }
    }
    return property;
}
/**
 * @remarks Clears an existing property of the entity. Called automatically when overwriting an existing property.
 * @param subject The entity, world, or item to clear the property on.
 * @param propertyName The property to clear.
 * @example
 * ```typescript
 * clearDynamicProperty(entity, 'ownerName'); // Clears the ownerName property from the entity.
 * ```
 */
export function clearDynamicProperty(subject, propertyName) {
    if (subject instanceof SafetyCheckedEntity)
        subject = subject.UnsafeEntity;
    subject.setDynamicProperty(propertyName);
}
/**
 * @remarks Clears all properties from the entity, world, or item.
 * @param subject The entity, world, or item to clear all properties from.
 */
export function clearAllDynamicProperties(subject) {
    if (subject instanceof SafetyCheckedEntity)
        subject = subject.UnsafeEntity;
    subject.getDynamicPropertyIds().forEach(prop => subject.setDynamicProperty(prop));
}
/**
 * @remarks Writes data to a property on the entity, world, or item.
 * @param subject The entity, world, or item to write the property to.
 * @param propertyName The property to write.
 * @param data The data to be written to the property. The data must be serializable with [JSON.stringify](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify).
 * @example
 * ```typescript
 * function tameEntity(player: SafetyCheckedPlayer, entity: SafetyCheckedEntity) {
 *  writeDynamicProperty(entity, player.name);
 * }
 * ```
 */
export function writeDynamicProperty(subject, propertyName, data) {
    if (subject instanceof SafetyCheckedEntity)
        subject = subject.UnsafeEntity;
    subject.setDynamicProperty(propertyName, JSON.stringify(data));
}
/**
 * @deprecated This function has been deprecated in favor of {@link readDynamicProperty} due to tag size limits and performance issues.
 * @remarks Reads a custom object stored on the entity.
 * @param entity The entity who's properties to read.
 * @param propertyName The name of the property.
 * @returns The object stored as a property, may be undefined.
 */
export function readTagProperty(entity, propertyName) {
    try {
        const prop = entity.getTags().filter(tag => tag.startsWith('{')).map(tag => JSON.parse(tag)).filter(prop => prop[propertyName] !== undefined)[0];
        if (prop) {
            return prop[propertyName];
        }
    }
    catch (error) {
        mcerror(error);
    }
}
/**
 * @deprecated This function has been deprecated in favor of {@link clearDynamicProperty} due to tag size limits and performance issues.
 * @remarks Clears an existing property of the entity. Called automatically when overwriting an existing property.
 * @param entity The entity who's property to clear.
 * @param propertyName The property to clear.
 * @returns True if the property could be removed, False otherwise.
 */
export function clearTagProperty(entity, propertyName) {
    const tagData = readTagProperty(entity, propertyName);
    if (tagData) {
        return entity.removeTag(JSON.stringify({ [propertyName]: tagData }));
    }
    else {
        return false;
    }
}
/**
 * @deprecated This function has been deprecated in favor of {@link writeDynamicProperty} due to tag size limits and performance issues.
 * @remarks Writes data to a property on the entity.
 * @param entity The entity who's property will be written.
 * @param propertyName The property to write.
 * @param tagData The data to be written to the property. The data must be serializable with JSON.stringify.
 */
export function writeTagProperty(entity, propertyName, tagData) {
    clearTagProperty(entity, propertyName);
    entity.addTag(JSON.stringify({ [propertyName]: tagData }));
}
/**
 * @remarks Creates a copy of the source object with only the filtered properties included.
 * @param source The source object who's properties should be copied.
 * @param properties The property's that should be copied from the source object.
 * @returns A new object with only the selected properties from the source.
 * @example
 * ```typescript
 * const source = {val1: 10, val2: 20, val3: 30};
 * const target = filterObjectProps(source, ["val1", "val2"]); // returns {val1: 10, val2: 20};
 * ```
 */
export function filterObjectProps(source, properties) {
    const obj = {};
    properties.forEach(key => {
        if (source[key]) {
            obj[key] = source[key];
        }
    });
    return obj;
}
