/** @odoo-module **/

import { TranslationDialog } from "@web/views/fields/translation_dialog";
import { patch } from "@web/core/utils/patch";
import { useService } from "@web/core/utils/hooks";
import { _t } from "@web/core/l10n/translation";
import { useState } from "@odoo/owl";

patch(TranslationDialog.prototype, {
    setup() {
        super.setup(...arguments);
        this.orm = useService('orm');
        this.notification = useService("notification");
        this.action = useService("action");
        this.state = useState({ translating: false, translatingTermIds: {} });
    },

    /**
     * Find the best source term to translate from for a given target term.
     * Picks a term in a different language with the same source text.
     * Priority: any candidate with actual translated content > en_US > first
     * candidate. en_US is deprioritized because Odoo populates en_US from the
     * record's base value — which may itself be in another language (e.g. a
     * record edited primarily in French) and would mislabel the source to GPT.
     */
    _findSourceTerm(targetTerm) {
        const candidates = this.terms.filter(
            t => t.lang !== targetTerm.lang && t.source === targetTerm.source
        );
        if (candidates.length === 0) return null;
        return candidates.find(t => (this.updatedTerms[t.id] ?? t.value ?? "").trim())
            || candidates.find(t => t.lang === "en_US")
            || candidates[0];
    },

    /**
     * Handle translation error notifications.
     * Returns true if an error was displayed (caller should stop).
     */
    _handleTranslationNotification(result) {
        if (!result[0]) {
            if (result[2] === "credits") {
                this.notification.add(result[1], {
                    type: "danger",
                    buttons: [{
                        onClick: () => window.open("https://osolutions.app/pricing"),
                        primary: false,
                        name: _t("Get tokens"),
                    }],
                });
            } else if (result[2] === "settings") {
                this.notification.add(result[1], {
                    type: "danger",
                    buttons: [{
                        onClick: () => this.action.doAction({
                            type: "ir.actions.act_window",
                            res_model: "res.config.settings",
                            views: [[false, "form"]],
                            target: "current",
                            context: { module: "otoolkit_auth" },
                        }),
                        primary: false,
                        name: _t("Open Settings"),
                    }],
                });
            } else {
                this.notification.add(result[1], { type: "danger" });
            }
            return true;
        }
        return false;
    },

    /**
     * Apply translated terms to the dialog state.
     * Returns the count of terms updated.
     */
    _applyTranslationResults(translatedTerms) {
        let count = 0;
        for (const item of translatedTerms) {
            if (item.translation) {
                this.updatedTerms[item.id] = item.translation;
                const target = this.terms.find(t => t.id === item.id);
                if (target) {
                    target.value = item.translation;
                    count++;
                }
            }
        }
        return count;
    },

    /**
     * Whether any translation (bulk or single-term) is currently running.
     */
    get anyTranslating() {
        if (this.state.translating) return true;
        for (const id in this.state.translatingTermIds) {
            if (this.state.translatingTermIds[id]) return true;
        }
        return false;
    },

    /**
     * Bulk auto-translate all empty terms.
     */
    async autoTranslate() {
        this.state.translating = true;
        try {
            const result = await this._translateText(this.terms, this.updatedTerms, null, null);
            if (this._handleTranslationNotification(result)) return;

            if (result[1].length === 0) {
                return this.notification.add(
                    _t("All translations are already filled."), { type: "info" }
                );
            }

            const count = this._applyTranslationResults(result[1]);
            this.render();
            if (count > 0) {
                this.notification.add(_t("Successfully translated"), { type: "success" });
            }
        } finally {
            this.state.translating = false;
        }
    },

    /**
     * Translate a single empty term.
     */
    async translateSingleTerm(targetTerm) {
        const sourceTerm = this._findSourceTerm(targetTerm);
        if (!sourceTerm) {
            return this.notification.add(
                _t("No other language available to translate from."), { type: "warning" }
            );
        }

        this.state.translatingTermIds[targetTerm.id] = true;
        try {
            const result = await this._translateText(
                [sourceTerm, targetTerm], this.updatedTerms,
                sourceTerm.lang, targetTerm.lang,
            );
            if (this._handleTranslationNotification(result)) return;

            if (result[1].length === 0) {
                return this.notification.add(
                    _t("No translation returned for this term."), { type: "warning" }
                );
            }

            // Apply only the target term's translation. The API also returns
            // an "echo" entry for the source-language term (its `translation`
            // is the source text itself) — applying it would overwrite the
            // source row's displayed value, which is wrong when the source
            // peer is an empty row whose displayed `value` is empty (HTML
            // showSource case).
            const targetOnly = result[1].filter(item => item.id === targetTerm.id);
            const count = this._applyTranslationResults(targetOnly);
            this.render();
            if (count > 0) {
                this.notification.add(_t("Successfully translated"), { type: "success" });
            } else {
                this.notification.add(
                    _t("No translation returned for this term."), { type: "warning" }
                );
            }
        } finally {
            delete this.state.translatingTermIds[targetTerm.id];
        }
    },

    async _translateText(terms, updated_terms, source_lang_hint = null, target_lang_hint = null) {
        return await this.orm.call(
            "translation.dialog", "translate_text",
            [terms, updated_terms, source_lang_hint, target_lang_hint],
        );
    },

    async onSave() {
        const translations = {};

        this.terms.forEach((term) => {
            const updatedTermValue = this.updatedTerms[term.id];

            if (term.id in this.updatedTerms && updatedTermValue !== term.originalValue) {
                if (this.props.showSource) {
                    if (!translations[term.lang]) {
                        translations[term.lang] = {};
                    }
                    const oldTermValue = term.originalValue ? term.originalValue : term.source;
                    translations[term.lang][oldTermValue] = updatedTermValue || term.source;
                } else {
                    translations[term.lang] = updatedTermValue || false;
                }
            }
        });

        await this.orm.call(this.props.resModel, "update_field_translations", [
            [this.props.resId],
            this.props.fieldName,
            translations,
        ]);

        await this.props.onSave();
        this.props.close();
    },
});
