import { DhHomebrew } from '../../data/settings/_module.mjs';
import { slugify } from '../../helpers/utils.mjs';

const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;

export default class DhHomebrewSettings extends HandlebarsApplicationMixin(ApplicationV2) {
    constructor() {
        super({});

        this.settings = new DhHomebrew(
            game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).toObject()
        );

        this.selected = this.#getDefaultAdversaryType();
    }

    #getDefaultAdversaryType = () => ({
        domain: null,
        adversaryType: null
    });

    get title() {
        return game.i18n.localize('DAGGERHEART.SETTINGS.Menu.title');
    }

    static DEFAULT_OPTIONS = {
        tag: 'form',
        id: 'daggerheart-homebrew-settings',
        classes: ['daggerheart', 'dh-style', 'dialog', 'setting', 'homebrew-settings'],
        position: { width: '600', height: 'auto' },
        window: {
            icon: 'fa-solid fa-gears'
        },
        actions: {
            addItem: this.addItem,
            editItem: this.editItem,
            removeItem: this.removeItem,
            resetMoves: this.resetMoves,
            addDomain: this.addDomain,
            toggleSelectedDomain: this.toggleSelectedDomain,
            deleteDomain: this.deleteDomain,
            addAdversaryType: this.addAdversaryType,
            deleteAdversaryType: this.deleteAdversaryType,
            selectAdversaryType: this.selectAdversaryType,
            save: this.save,
            reset: this.reset
        },
        form: { handler: this.updateData, submitOnChange: true }
    };

    static PARTS = {
        tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
        settings: { template: 'systems/daggerheart/templates/settings/homebrew-settings/settings.hbs' },
        domains: { template: 'systems/daggerheart/templates/settings/homebrew-settings/domains.hbs' },
        types: { template: 'systems/daggerheart/templates/settings/homebrew-settings/types.hbs' },
        itemTypes: { template: 'systems/daggerheart/templates/settings/homebrew-settings/itemFeatures.hbs' },
        downtime: { template: 'systems/daggerheart/templates/settings/homebrew-settings/downtime.hbs' },
        footer: { template: 'systems/daggerheart/templates/settings/homebrew-settings/footer.hbs' }
    };

    /** @inheritdoc */
    static TABS = {
        main: {
            tabs: [{ id: 'settings' }, { id: 'domains' }, { id: 'types' }, { id: 'itemFeatures' }, { id: 'downtime' }],
            initial: 'settings',
            labelPrefix: 'DAGGERHEART.GENERAL.Tabs'
        }
    };

    changeTab(tab, group, options) {
        super.changeTab(tab, group, options);
        this.selected = this.#getDefaultAdversaryType();

        this.render();
    }

    async _prepareContext(_options) {
        const context = await super._prepareContext(_options);
        context.settingFields = this.settings;

        return context;
    }

    async _preparePartContext(partId, context) {
        await super._preparePartContext(partId, context);

        switch (partId) {
            case 'domains':
                const selectedDomain = this.selected.domain ? this.settings.domains[this.selected.domain] : null;
                const enrichedDescription = selectedDomain
                    ? await foundry.applications.ux.TextEditor.implementation.enrichHTML(selectedDomain.description)
                    : null;

                if (enrichedDescription !== null) context.selectedDomain = { ...selectedDomain, enrichedDescription };
                context.configDomains = CONFIG.DH.DOMAIN.domains;
                context.homebrewDomains = this.settings.domains;
                break;
            case 'types':
                context.selectedAdversaryType = this.selected.adversaryType
                    ? { id: this.selected.adversaryType, ...this.settings.adversaryTypes[this.selected.adversaryType] }
                    : null;
                break;
        }

        return context;
    }

    static async updateData(_event, _element, formData) {
        const updatedSettings = foundry.utils.expandObject(formData.object);

        await this.settings.updateSource({
            ...updatedSettings,
            traitArray: Object.values(updatedSettings.traitArray)
        });
        this.render();
    }

    static async addItem(_, target) {
        const { type } = target.dataset;
        if (['shortRest', 'longRest'].includes(type)) {
            await this.settings.updateSource({
                [`restMoves.${type}.moves.${foundry.utils.randomID()}`]: {
                    name: game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.newDowntimeMove'),
                    img: 'icons/magic/life/cross-worn-green.webp',
                    description: '',
                    actions: []
                }
            });
        } else if (['armorFeatures', 'weaponFeatures'].includes(type)) {
            await this.settings.updateSource({
                [`itemFeatures.${type}.${foundry.utils.randomID()}`]: {
                    name: game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.newFeature'),
                    img: 'icons/magic/life/cross-worn-green.webp',
                    description: '',
                    actions: [],
                    effects: []
                }
            });
        }

        this.render();
    }

    static async editItem(_, target) {
        const { type, id } = target.dataset;
        const isDowntime = ['shortRest', 'longRest'].includes(type);
        const path = isDowntime ? `restMoves.${type}.moves.${id}` : `itemFeatures.${type}.${id}`;
        const featureBase = isDowntime ? this.settings.restMoves[type].moves[id] : this.settings.itemFeatures[type][id];

        const configTitle = isDowntime
            ? game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.downtimeMove')
            : type === 'armorFeatures'
              ? game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.armorFeature')
              : game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.weaponFeature');

        const editedBase = await game.system.api.applications.sheetConfigs.SettingFeatureConfig.configure(
            configTitle,
            featureBase,
            path,
            this.settings,
            { hasIcon: isDowntime, hasEffects: !isDowntime }
        );
        if (!editedBase) return;

        await this.updateAction.bind(this)(editedBase, target.dataset.type, target.dataset.id);
    }

    async updateAction(data, type, id) {
        const isDowntime = ['shortRest', 'longRest'].includes(type);
        const path = isDowntime ? `restMoves.${type}.moves` : `itemFeatures.${type}`;
        await this.settings.updateSource({
            [`${path}.${id}`]: {
                actions: data.actions,
                name: data.name,
                icon: data.icon,
                img: data.img,
                description: data.description
            }
        });

        this.render();
    }

    static async removeItem(_, target) {
        const { type, id } = target.dataset;
        const isDowntime = ['shortRest', 'longRest'].includes(type);
        const path = isDowntime ? `restMoves.${type}.moves` : `itemFeatures.${type}`;
        await this.settings.updateSource({
            [`${path}.-=${id}`]: null
        });
        this.render();
    }

    static async resetMoves(_, target) {
        const confirmed = await foundry.applications.api.DialogV2.confirm({
            window: {
                title: game.i18n.format('DAGGERHEART.SETTINGS.Homebrew.resetMovesTitle', {
                    type: game.i18n.localize(
                        `DAGGERHEART.APPLICATIONS.Downtime.${target.dataset.type === 'shortRest' ? 'shortRest' : 'longRest'}.title`
                    )
                })
            },
            content: game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.resetMovesText')
        });

        if (!confirmed) return;

        const fields = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).schema.fields;

        const removeUpdate = Object.keys(this.settings.restMoves[target.dataset.type].moves).reduce((acc, key) => {
            acc[`-=${key}`] = null;

            return acc;
        }, {});

        const updateBase =
            target.dataset.type === 'shortRest'
                ? fields.restMoves.fields.shortRest.fields
                : fields.restMoves.fields.longRest.fields;
        const update = {
            nrChoices: updateBase.nrChoices.initial,
            moves: Object.keys(updateBase.moves.initial).reduce((acc, key) => {
                const move = updateBase.moves.initial[key];
                acc[key] = {
                    ...move,
                    name: game.i18n.localize(move.name),
                    description: game.i18n.localize(move.description),
                    actions: move.actions.reduce((acc, key) => {
                        const action = move.actions[key];
                        acc[key] = {
                            ...action,
                            name: game.i18n.localize(action.name)
                        };
                        return acc;
                    }, {})
                };

                return acc;
            }, {})
        };

        await this.settings.updateSource({
            [`restMoves.${target.dataset.type}`]: {
                ...update,
                moves: {
                    ...removeUpdate,
                    ...update.moves
                }
            }
        });

        this.render();
    }

    static async addDomain(event) {
        event.preventDefault();
        const content = new foundry.data.fields.StringField({
            label: game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.domains.newDomainInputLabel'),
            hint: game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.domains.newDomainInputHint'),
            required: true
        }).toFormGroup({}, { name: 'domainName', localize: true }).outerHTML;

        async function callback(_, button) {
            const domainName = button.form.elements.domainName.value;
            if (!domainName) return;

            const newSlug = slugify(domainName);
            const existingDomains = [
                ...Object.values(this.settings.domains),
                ...Object.values(CONFIG.DH.DOMAIN.domains)
            ];
            if (existingDomains.find(x => slugify(game.i18n.localize(x.label)) === newSlug)) {
                ui.notifications.warn(game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.domains.duplicateDomain'));
                return;
            }

            this.settings.updateSource({
                [`domains.${newSlug}`]: {
                    id: newSlug,
                    label: domainName,
                    src: 'icons/svg/portal.svg'
                }
            });

            this.selected.domain = newSlug;
            this.render();
        }

        foundry.applications.api.DialogV2.prompt({
            content: content,
            rejectClose: false,
            modal: true,
            ok: { callback: callback.bind(this) },
            window: {
                title: game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.domains.newDomainInputTitle')
            },
            position: { width: 400 }
        });
    }

    static toggleSelectedDomain(_, target) {
        this.selected.domain = this.selected.domain === target.id ? null : target.id;
        this.render();
    }

    static async deleteDomain() {
        const confirmed = await foundry.applications.api.DialogV2.confirm({
            window: {
                title: game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.domains.deleteDomain')
            },
            content: game.i18n.format('DAGGERHEART.SETTINGS.Homebrew.domains.deleteDomainText', {
                name: this.settings.domains[this.selected.domain].label
            })
        });

        if (!confirmed) return;

        await this.settings.updateSource({
            [`domains.-=${this.selected.domain}`]: null
        });

        const currentSettings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew);
        if (currentSettings.domains[this.selected.domain]) {
            await currentSettings.updateSource({ [`domains.-=${this.selected.domain}`]: null });
            await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew, currentSettings);
        }

        const updateClasses = game.items.filter(x => x.type === 'class');
        for (let actor of game.actors) {
            updateClasses.push(...actor.items.filter(x => x.type === 'class'));
        }

        for (let c of updateClasses) {
            if (c.system.domains.includes(this.selected.domain)) {
                const newDomains =
                    c.system.domains.length === 1
                        ? [CONFIG.DH.DOMAIN.domains.arcana.id]
                        : c.system.domains.filter(x => x !== this.selected.domain);
                await c.update({ 'system.domains': newDomains });
            }
            c.sheet.render();
        }

        const updateDomainCards = game.items.filter(
            x => x.type === 'domainCard' && x.system.domain === this.selected.domain
        );
        for (let d of updateDomainCards) {
            await d.update({ 'system.domain': CONFIG.DH.DOMAIN.domains.arcana.id });
            d.sheet.render();
        }

        this.selected.domain = null;
        this.render();
    }

    static async addAdversaryType(_, target) {
        const newId = foundry.utils.randomID();
        await this.settings.updateSource({
            [`adversaryTypes.${newId}`]: {
                id: newId,
                label: game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.adversaryType.newType')
            }
        });

        this.selected.adversaryType = newId;
        this.render();
    }

    static async deleteAdversaryType(_, target) {
        const { key } = target.dataset;
        await this.settings.updateSource({ [`adversaryTypes.-=${key}`]: null });

        this.selected.adversaryType = this.selected.adversaryType === key ? null : this.selected.adversaryType;
        this.render();
    }

    static async selectAdversaryType(_, target) {
        this.selected.adversaryType = this.selected.adversaryType === target.dataset.type ? null : target.dataset.type;
        this.render();
    }

    static async save() {
        await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew, this.settings.toObject());
        this.close();
    }

    static async reset() {
        const confirmed = await foundry.applications.api.DialogV2.confirm({
            window: {
                title: game.i18n.format('DAGGERHEART.SETTINGS.ResetSettings.resetConfirmationTitle')
            },
            content: game.i18n.format('DAGGERHEART.SETTINGS.ResetSettings.resetConfirmationText', {
                settings: game.i18n.localize('DAGGERHEART.SETTINGS.Menu.homebrew.name')
            })
        });
        if (!confirmed) return;

        const resetSettings = new DhHomebrew();
        let localizedSettings = this.localizeObject(resetSettings.toObject());
        this.settings.updateSource(localizedSettings);
        this.render();
    }

    localizeObject(obj) {
        for (let key in obj) {
            if (obj.hasOwnProperty(key)) {
                const value = obj[key];
                if (typeof value === 'object' && value !== null) {
                    obj[key] = this.localizeObject(value);
                } else {
                    if (typeof value === 'string' && value.startsWith('DAGGERHEART.')) {
                        obj[key] = game.i18n.localize(value);
                    }
                }
            }
        }
        return obj;
    }

    _getTabs(tabs) {
        for (const v of Object.values(tabs)) {
            v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active;
            v.cssClass = v.active ? 'active' : '';
        }

        return tabs;
    }
}
