/**
 * Chiaroscuro Dice Dialog
 *
 * d6 pool system: ring value × multiplier d6, sum vs difficulty.
 * Multiplier: ×1 base, ×2 if aspect or assistance, ×3 if both.
 * Parangon passives adjust individual die results before summing.
 */
export class ChiaroscuroDiceDialog extends FormApplication {
    /**
     * Current Actor
     * @type {ActorL5r5e}
     * @private
     */
    _actor = null;

    /**
     * Payload Object
     */
    object = {
        ring: { id: "void", value: 1 },
        skill: { id: "", name: "", bonus: 0, rank: "0" },
        difficulty: { id: "moyenne", value: 10 },
        modifier: 0,
        useAspectPoint: false,
        aspectType: "solar",
        useAssistance: false,
    };

    static get defaultOptions() {
        return foundry.utils.mergeObject(super.defaultOptions, {
            id: "l5r5e-chiaroscuro-dice-dialog",
            classes: ["l5r5e", "chiaroscuro-dice-dialog"],
            template: CONFIG.l5r5e.paths.templates + "dice/chiaroscuro-dice-dialog.html",
            title: game.i18n.localize("chiaroscuro.dice.title"),
            width: 440,
            height: "auto",
        });
    }

    get id() {
        return `l5r5e-chiaroscuro-dice-dialog-${this._actor?.id ?? "no-actor"}`;
    }

    get title() {
        return game.i18n.localize("chiaroscuro.dice.title") + (this._actor ? " — " + this._actor.name : "");
    }

    /**
     * Total dice to roll (ring value × multiplier)
     * @return {number}
     */
    get totalDice() {
        const base = this.object.ring.value;
        const both = this.object.useAspectPoint && this.object.useAssistance;
        const either = this.object.useAspectPoint || this.object.useAssistance;
        return base * (both ? 3 : either ? 2 : 1);
    }

    /**
     * @param options  actor, actorId, ringId, skillId, itemUuid
     */
    constructor(options = {}) {
        super({}, options);

        // Resolve actor
        [
            options?.actor,
            game.actors.get(options?.actorId),
            canvas.tokens.controlled[0]?.actor,
            game.user.character,
        ].forEach((actor) => {
            if (!this._actor && actor instanceof Actor && actor.isOwner) {
                this._actor = actor;
            }
        });

        // Resolve item from uuid (weapon, technique, etc.)
        this._item = options.itemUuid ? fromUuidSync(options.itemUuid) : null;

        // Default ring: options > actor default_ring > void
        const ringId = options.ringId ?? this._actor?.system?.default_ring ?? "void";
        this.ringId = ringId;

        // Skill
        if (options.skillId) {
            this.skillId = options.skillId;
        }
    }

    /**
     * Set ring (id + value from actor)
     * @param {string} ringId
     */
    set ringId(ringId) {
        this.object.ring.id = CONFIG.l5r5e.stances.includes(ringId) ? ringId : "void";
        this.object.ring.value = this._actor?.system?.rings?.[this.object.ring.id] || 1;
        // Auto-derive aspect type from ring (fire/earth → solar, air/water → lunar; void = manual)
        if (this.object.ring.id !== "void") {
            this.object.aspectType = ["fire", "earth"].includes(this.object.ring.id) ? "solar" : "lunar";
        }
    }

    /**
     * Set skill (id, name, rank, bonus)
     * @param {string} skillId
     */
    set skillId(skillId) {
        if (!skillId) return;
        const catId = CONFIG.l5r5e.skills.get(skillId.toLowerCase().trim());
        const rank = this._actor?.system?.skills?.[catId]?.[skillId] ?? "0";
        this.object.skill = {
            ...this.object.skill,
            id: skillId,
            name: catId ? game.i18n.localize(`l5r5e.skills.${catId}.${skillId}`) : skillId,
            rank,
            bonus: CONFIG.l5r5e.skillRanks?.[rank]?.bonus ?? 0,
        };
    }

    async getData(options = null) {
        const difficultiesList = Object.entries(CONFIG.l5r5e.difficulties).map(([id, value]) => ({
            id,
            label: game.i18n.localize(`chiaroscuro.difficulties.${id}`),
            value,
        }));

        const aspectsList = [
            { id: "solar", label: game.i18n.localize("chiaroscuro.aspects.solar") },
            { id: "lunar", label: game.i18n.localize("chiaroscuro.aspects.lunar") },
        ];

        return {
            ...(await super.getData(options)),
            actor: this._actor,
            data: this.object,
            totalDice: this.totalDice,
            ringsList: game.l5r5e.HelpersL5r5e.getRingsList(this._actor),
            difficultiesList,
            aspectsList,
            isVoidRing: this.object.ring.id === "void",
            quickInfo: this._actor?.system?.quick_info ?? "",
        };
    }

    activateListeners(html) {
        super.activateListeners(html);

        // Ring selector
        html.find(".ring-selection-chi").on("click", async (event) => {
            event.preventDefault();
            event.stopPropagation();
            this.ringId = event.currentTarget.dataset.ringid;
            this.render(false);
        });

        // Difficulty select
        html.find("select[name='difficulty.id']").on("change", (event) => {
            this.object.difficulty.id = event.target.value;
            this.object.difficulty.value = CONFIG.l5r5e.difficulties[this.object.difficulty.id];
            this.render(false);
        });

        // Flat modifier
        html.find("input[name='modifier']").on("change", (event) => {
            this.object.modifier = parseInt(event.target.value) || 0;
        });

        // Aspect point checkbox
        html.find("#use_aspect_point").on("change", (event) => {
            this.object.useAspectPoint = event.target.checked;
            this.render(false);
        });

        // Aspect type select (solar / lunar)
        html.find("select[name='aspectType']").on("change", (event) => {
            this.object.aspectType = event.target.value;
        });

        // Assistance checkbox
        html.find("#use_assistance").on("change", (event) => {
            this.object.useAssistance = event.target.checked;
            this.render(false);
        });

        // Roll button — explicit submit trigger
        html.find("button[name='roll']").on("click", (event) => {
            event.preventDefault();
            this._onSubmit(event);
        });
    }

    async _updateObject(event, formData) {
        const nbDice = this.totalDice;
        const skillRank = this.object.skill.rank;
        const skillBonus = this.object.skill.bonus;
        const flatModifier = this.object.modifier;
        const difficultyObj = this.object.difficulty;
        const difficultyValue = difficultyObj.value;

        // Roll the dice using FoundryVTT Roll API
        const roll = await new Roll(`${nbDice}d6`).evaluate();
        const rawResults = roll.dice[0].results.map((r) => r.result);

        // Apply parangon passive adjustments
        const adjustedResults = rawResults.map((r) => this._applyParangon(r, skillRank));
        const diceAdjustedFlags = rawResults.map((r, i) => adjustedResults[i] !== r);
        const wasAdjusted = diceAdjustedFlags.some(Boolean);

        // Compute total
        const rawSum = adjustedResults.reduce((a, b) => a + b, 0);
        const total = rawSum + skillBonus + flatModifier;
        const success = total >= difficultyValue;
        const bonus = success ? total - difficultyValue : 0;

        // Update aspect gauge after roll
        if (this._actor && this.object.useAspectPoint) {
            await this._updateAspectGauge();
        }

        // Post chat message
        await this._sendChatMessage({
            nbDice,
            rawResults,
            adjustedResults,
            diceAdjustedFlags,
            wasAdjusted,
            rawSum,
            total,
            skillBonus,
            flatModifier,
            difficulty: difficultyObj,
            success,
            bonus,
            missBy: success ? 0 : difficultyValue - total,
        });

        return this.close();
    }

    /**
     * Apply parangon rank passive: replace low die results with higher value.
     * parangon1: 1 → 2
     * parangon2: 1–2 → 3
     * parangon3: 1–3 → 4
     * @param {number} result
     * @param {string} rank
     * @return {number}
     */
    _applyParangon(result, rank) {
        if (rank === "parangon3" && result <= 3) return 4;
        if (rank === "parangon2" && result <= 2) return 3;
        if (rank === "parangon1" && result <= 1) return 2;
        return result;
    }

    /**
     * Update the aspect gauge on the actor after an aspect point roll.
     * Gauge positive = solar side, negative = lunar side.
     * ±5 → apply Déséquilibre. ±10 → full reset.
     */
    async _updateAspectGauge() {
        // Support both single-nested (system.aspects) and double-nested (system.aspects.aspects)
        const aspectsPath = this._actor.system.aspects?.aspects !== undefined
            ? "system.aspects.aspects"
            : "system.aspects";
        const aspects = foundry.utils.getProperty(this._actor, aspectsPath) ?? {};

        const gaugeDirection = this.object.aspectType === "solar" ? 1 : -1;
        const newGauge = (aspects.gauge ?? 0) + gaugeDirection;

        if (Math.abs(newGauge) >= 10) {
            // Full reset
            await this._actor.update({
                [`${aspectsPath}.gauge`]: 0,
                [`${aspectsPath}.solar`]: 0,
                [`${aspectsPath}.lunar`]: 0,
            });
        } else {
            await this._actor.update({ [`${aspectsPath}.gauge`]: newGauge });
        }
    }

    /**
     * Create and send the chat message.
     */
    async _sendChatMessage(rollData) {
        const content = await foundry.applications.handlebars.renderTemplate(
            CONFIG.l5r5e.paths.templates + "dice/chiaroscuro-chat-roll.html",
            {
                actor: this._actor,
                profileImg: this._actor?.img ?? "icons/svg/mystery-man.svg",
                ring: {
                    ...this.object.ring,
                    label: game.i18n.localize(`l5r5e.rings.${this.object.ring.id}`),
                },
                skill: this.object.skill,
                difficulty: this.object.difficulty,
                useAspectPoint: this.object.useAspectPoint,
                aspectType: this.object.aspectType,
                useAssistance: this.object.useAssistance,
                modifier: this.object.modifier,
                quickInfo: this._actor?.system?.quick_info ?? "",
                l5r5e: {
                    item: this._item ?? null,
                },
                ...rollData,
            }
        );

        return ChatMessage.implementation.create({
            user: game.user.id,
            speaker: {
                actor: this._actor?.id ?? null,
                alias: this._actor?.name ?? null,
            },
            content,
            sound: CONFIG.sounds.dice,
        });
    }
}
