import { emitAsGM, GMUpdateEvent } from '../../../systemRegistration/socket.mjs';

const fields = foundry.data.fields;

export default class EffectsField extends fields.ArrayField {
    /**
     * Action Workflow order
     */
    static order = 100;

    /** @inheritDoc */
    constructor(options = {}, context = {}) {
        const element = new fields.SchemaField({
            _id: new fields.DocumentIdField(),
            onSave: new fields.BooleanField({ initial: false })
        });
        super(element, options, context);
    }

    /**
     * Apply Effects Action Workflow part.
     * Must be called within Action context or similar.
     * @param {object} config                    Object that contains workflow datas. Usually made from Action Fields prepareConfig methods.
     * @param {object[]} [targets=null]     Array of targets to override pre-selected ones.
     * @param {boolean} [force=false]       If the method should be executed outside of Action workflow, for ChatMessage button for example.
     */
    static async execute(config, targets = null, force = false) {
        if (!config.hasEffect) return;
        let message = config.message ?? ui.chat.collection.get(config.parent?._id);
        if (!message) {
            const roll = new CONFIG.Dice.daggerheart.DHRoll('');
            roll._evaluated = true;
            message = config.message = await CONFIG.Dice.daggerheart.DHRoll.toMessage(roll, config);
        }
        if (EffectsField.getAutomation() || force) {
            targets ??= (message.system?.targets ?? config.targets).filter(t => !config.hasRoll || t.hit);
            await emitAsGM(GMUpdateEvent.UpdateEffect, EffectsField.applyEffects.bind(this), targets, this.uuid);
            // EffectsField.applyEffects.call(this, config.targets.filter(t => !config.hasRoll || t.hit));
        }
    }

    /**
     * Apply Action Effects to a list of Targets
     * Must be called within Action context or similar.
     * @param {object[]} targets Array of formatted targets
     */
    static async applyEffects(targets) {
        if (!this.effects?.length || !targets?.length) return;

        const conditions = CONFIG.DH.GENERAL.conditions();
        let effects = this.effects;
        const messageTargets = [];
        targets.forEach(async baseToken => {
            if (this.hasSave && baseToken.saved.success === true) effects = this.effects.filter(e => e.onSave === true);
            if (!effects.length) return;

            const token =
                canvas.tokens.get(baseToken.id) ?? foundry.utils.fromUuidSync(baseToken.actorId).prototypeToken;
            if (!token) return;

            const messageToken = token.document ?? token;
            const conditionImmunities = messageToken.actor.system.rules.conditionImmunities ?? {};
            messageTargets.push({
                token: messageToken,
                conditionImmunities: Object.values(conditionImmunities).some(x => x)
                    ? game.i18n.format('DAGGERHEART.UI.Chat.effectSummary.immunityTo', {
                          immunities: Object.keys(conditionImmunities)
                              .filter(x => conditionImmunities[x])
                              .map(x => game.i18n.localize(conditions[x].name))
                              .join(', ')
                      })
                    : null
            });

            effects.forEach(async e => {
                const effect = this.item.effects.get(e._id);
                if (!token.actor || !effect) return;
                await EffectsField.applyEffect(effect, token.actor);
            });
        });

        if (messageTargets.length === 0) return;

        const summaryMessageSettings = game.settings.get(
            CONFIG.DH.id,
            CONFIG.DH.SETTINGS.gameSettings.Automation
        ).summaryMessages;
        if (!summaryMessageSettings.effects) return;

        const cls = getDocumentClass('ChatMessage');
        const msg = {
            type: 'systemMessage',
            user: game.user.id,
            speaker: cls.getSpeaker(),
            title: game.i18n.localize('DAGGERHEART.UI.Chat.effectSummary.title'),
            content: await foundry.applications.handlebars.renderTemplate(
                'systems/daggerheart/templates/ui/chat/effectSummary.hbs',
                {
                    effects: this.effects.map(e => this.item.effects.get(e._id)),
                    targets: messageTargets
                }
            )
        };

        cls.create(msg);
    }

    /**
     * Apply an Effect to a target or enable it if already on it
     * @param {object} effect   Effect object containing ActiveEffect UUID
     * @param {object} actor    Actor Document
     */
    static async applyEffect(effect, actor) {
        const existingEffect = actor.effects.find(e => e.origin === effect.uuid);
        if (existingEffect) {
            return effect.update(
                foundry.utils.mergeObject({
                    ...effect.constructor.getInitialDuration(),
                    disabled: false
                })
            );
        }

        // Otherwise, create a new effect on the target
        const effectData = foundry.utils.mergeObject({
            ...effect.toObject(),
            disabled: false,
            transfer: false,
            origin: effect.uuid
        });
        await ActiveEffect.implementation.create(effectData, { parent: actor });
    }

    /**
     * Return the automation setting for execute method for current user role
     * @returns {boolean} If execute should be triggered automatically
     */
    static getAutomation() {
        return (
            (game.user.isGM &&
                game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.effect.gm) ||
            (!game.user.isGM &&
                game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.effect.players)
        );
    }
}
