/** @odoo-module **/

import { Composer } from "@mail/core/common/composer";
import { Store } from "@mail/core/common/store_service";
import { patch } from "@web/core/utils/patch";
import { useState, onWillStart } from "@odoo/owl";
import { useService } from "@web/core/utils/hooks";
import { user } from "@web/core/user";
import { rpc } from "@web/core/network/rpc";

/**
 * Patch Store.getMessagePostParams to inject channel_tag_ids into post_data.
 * This is the correct way to add custom fields — they end up in post_data
 * which is filtered by _get_allowed_message_params on the Python side.
 */
patch(Store.prototype, {
    async getMessagePostParams({ body, postData, thread }) {
        const params = await super.getMessagePostParams({ body, postData, thread });
        if (postData.tierChannelTagIds !== undefined) {
            if (postData.tierChannelTagIds) {
                params.post_data.channel_tag_ids = postData.tierChannelTagIds;
            }
        }
        return params;
    },

    async doMessagePost(params, tmpMessage) {
        const result = await super.doMessagePost(params, tmpMessage);
        // Store the last posted message_id so Composer can use it for channel notification
        if (result?.message_id) {
            this._lastPostedMessageId = result.message_id;
        }
        return result;
    },
});

/**
 * Patch Composer to add channel/mailbox selector UI.
 *
 * Логика выбора канала:
 * - По умолчанию канал не выбран (только Odoo)
 * - Если последнее сообщение в треде пришло через email → автовыбор email
 * - Если через matrix → автовыбор matrix
 * - Если без канала → ничего не выбираем
 * - Пользователь может вручную переключить или снять выбор
 */
patch(Composer.prototype, {
    setup() {
        super.setup();
        this.orm = useService("orm");
        this.notification = useService("notification");
        this.store = useService("mail.store");
        this.tierState = useState({
            selectedChannelId: null,
            selectedMailboxIds: [],
            availableChannels: [],
            availableMailboxes: [],
        });
        onWillStart(async () => {
            await this._loadTierData();
        });
    },

    async _loadTierData() {
        try {
            const [isCompanySender, channelTags, mailboxes] = await Promise.all([
                user.hasGroup("tier_communications.group_company_sender"),
                this.orm.searchRead(
                    "tier.channel.tag",
                    [["active", "=", true]],
                    ["id", "name", "code", "is_company_reply"]
                ),
                this.orm.call("tier.mailbox", "get_accessible_mailboxes", [], {}),
            ]);

            this.tierState.availableChannels = (channelTags || []).filter(
                (channelTag) => !channelTag.is_company_reply || isCompanySender
            );
            this.tierState.availableMailboxes = mailboxes || [];

            await this._autoSelectChannel();
        } catch (error) {
            console.warn("[tier_communications] _loadTierData error:", error);
            this.tierState.availableChannels = [];
            this.tierState.availableMailboxes = [];
        }
    },

    /**
     * Auto-select channel based on the last message in the thread.
     * email → select email, matrix → select matrix, none → no selection.
     */
    async _autoSelectChannel() {
        const composerThread = this.props?.composer?.thread;
        if (!composerThread || composerThread.model === "mail.box" || !composerThread.id) {
            this.tierState.selectedChannelId = null;
            return;
        }

        try {
            const lastChannelCode = await this.orm.call(
                "mail.message",
                "get_last_channel_code",
                [composerThread.model, composerThread.id],
                {}
            );

            if (!lastChannelCode) {
                this.tierState.selectedChannelId = null;
                return;
            }

            const matchedChannel = this.tierState.availableChannels.find(
                (channelTag) => channelTag.code === lastChannelCode
            );
            this.tierState.selectedChannelId = matchedChannel ? matchedChannel.id : null;
        } catch {
            this.tierState.selectedChannelId = null;
        }
    },

    /** Toggle channel: click selected → deselect, click other → select */
    selectChannel(channelId) {
        this.tierState.selectedChannelId =
            this.tierState.selectedChannelId === channelId ? null : channelId;
    },

    toggleMailbox(mailboxId) {
        const existingIndex = this.tierState.selectedMailboxIds.indexOf(mailboxId);
        if (existingIndex >= 0) {
            this.tierState.selectedMailboxIds.splice(existingIndex, 1);
        } else {
            this.tierState.selectedMailboxIds.push(mailboxId);
        }
    },

    get postData() {
        const basePostData = super.postData;
        // Inject tierChannelTagIds into postData so Store.getMessagePostParams can pick it up
        if (this.tierState.selectedChannelId) {
            basePostData.tierChannelTagIds = [[6, 0, [this.tierState.selectedChannelId]]];
        } else {
            basePostData.tierChannelTagIds = null;
        }
        return basePostData;
    },

    async _sendMessage(value, postData, extraData) {
        const sentMessage = await super._sendMessage(value, postData, extraData);

        if (!this.tierState.selectedChannelId) {
            return sentMessage;
        }

        const selectedChannel = this.tierState.availableChannels.find(
            (channelTag) => channelTag.id === this.tierState.selectedChannelId
        );
        if (!selectedChannel) {
            return sentMessage;
        }

        // For discuss.channel, sentMessage may be undefined (optimistic send).
        // Fall back to the message_id captured by doMessagePost patch.
        const messageId = sentMessage?.id ?? this.store._lastPostedMessageId;
        if (!messageId) {
            return sentMessage;
        }

        const composerThread = this.props?.composer?.thread;
        // Fire-and-forget: show toast after send
        this._tierNotifyChannelSend(
            messageId,
            selectedChannel.code,
            composerThread?.model,
            composerThread?.id
        );

        return sentMessage;
    },

    /**
     * Call the backend to send via external channel and show a toast notification.
     * Runs async — does not block message posting.
     */
    async _tierNotifyChannelSend(messageId, channelCode, threadModel, threadId) {
        try {
            const result = await rpc('/tier_communications/send_via_channel', {
                message_id: messageId,
                channel_code: channelCode,
                thread_model: threadModel || null,
                thread_id: threadId || null,
            });

            const notificationType = result.status === 'success' ? 'success'
                : result.status === 'no_data' ? 'warning'
                : 'danger';

            this.notification.add(result.message, { type: notificationType });
        } catch (error) {
            this.notification.add(
                `Ошибка при отправке через ${channelCode}: ${error.message || error}`,
                { type: 'danger' }
            );
        }
    },

    /**
     * Assign the current thread's conversation to a mailbox.
     * Called from the chatter toolbar buttons "Входящие лиды" / "Входящие тикеты".
     */
    async assignToMailbox(mailboxId, mailboxName) {
        const composerThread = this.props?.composer?.thread;
        if (!composerThread || composerThread.model === "mail.box" || !composerThread.id) {
            return;
        }
        try {
            await this.orm.call(
                composerThread.model,
                "assign_mailbox",
                [[composerThread.id], mailboxId],
                {}
            );
            this.notification.add(
                `Переписка перенесена в "${mailboxName}"`,
                { type: "success" }
            );
        } catch (error) {
            console.error("[tier_communications] assignToMailbox error:", error);
            this.notification.add(
                `Ошибка при переносе в "${mailboxName}"`,
                { type: "danger" }
            );
        }
    },
});
