/*
 * Copyright 2025 New Vector Ltd.
 *
 * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
 * Please see LICENSE files in the repository root for full details.
 */

import { Room } from "matrix-js-sdk/src/matrix";

import { SettingLevel } from "../../../../../src/settings/SettingLevel";
import SettingsStore, { type CallbackFn } from "../../../../../src/settings/SettingsStore";
import { mkEvent, stubClient, upsertRoomStateEvents } from "../../../../test-utils";
import { HistoryVisibleBannerViewModel } from "../../../../../src/viewmodels/composer/HistoryVisibleBannerViewModel";

describe("HistoryVisibleBannerViewModel", () => {
    const ROOM_ID = "!roomId:example.org";

    let room: Room;
    let watcherCallbacks: CallbackFn[];
    let acknowledgedHistoryVisibility: boolean;

    beforeEach(() => {
        watcherCallbacks = [];
        acknowledgedHistoryVisibility = false;

        jest.spyOn(SettingsStore, "setValue").mockImplementation(async (settingName, roomId, level, value) => {
            if (settingName === "acknowledgedHistoryVisibility") {
                acknowledgedHistoryVisibility = value;
            }
            watcherCallbacks.forEach((callbackFn) => callbackFn(settingName, roomId, level, value, value));
        });

        jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName, roomId) => {
            if (settingName === "acknowledgedHistoryVisibility") {
                return acknowledgedHistoryVisibility;
            }
            if (settingName === "feature_share_history_on_invite") {
                return true;
            }
            return SettingsStore.getDefaultValue(settingName);
        });

        jest.spyOn(SettingsStore, "watchSetting").mockImplementation((settingName, roomId, callbackFn) => {
            watcherCallbacks.push(callbackFn);
            return `mockWatcherId-${settingName}-${roomId}`;
        });

        stubClient();
        room = new Room(ROOM_ID, {} as any, "@user:example.org");
    });

    afterEach(() => {
        jest.clearAllMocks();
    });

    it("should not show the banner in unencrypted rooms", () => {
        const vm = new HistoryVisibleBannerViewModel({ room, canSendMessages: true, threadId: null });
        expect(vm.getSnapshot().visible).toBe(false);
    });

    it("should not show the banner in encrypted rooms with joined history visibility", () => {
        upsertRoomStateEvents(room, [
            mkEvent({
                event: true,
                type: "m.room.encryption",
                user: "@user1:server",
                content: {},
            }),
            mkEvent({
                event: true,
                type: "m.room.history_visibility",
                content: {
                    history_visibility: "joined",
                },
                user: "@user1:server",
            }),
        ]);

        const vm = new HistoryVisibleBannerViewModel({ room, canSendMessages: true, threadId: null });
        expect(vm.getSnapshot().visible).toBe(false);
    });

    it("should not show the banner if it has been dismissed", async () => {
        await SettingsStore.setValue("acknowledgedHistoryVisibility", ROOM_ID, SettingLevel.ROOM_ACCOUNT, true);
        upsertRoomStateEvents(room, [
            mkEvent({
                event: true,
                type: "m.room.encryption",
                user: "@user1:server",
                content: {},
            }),
            mkEvent({
                event: true,
                type: "m.room.history_visibility",
                user: "@user1:server",
                content: {
                    history_visibility: "shared",
                },
            }),
        ]);

        const vm = new HistoryVisibleBannerViewModel({ room, canSendMessages: true, threadId: null });
        expect(vm.getSnapshot().visible).toBe(false);
        vm.dispose();
    });

    it("should not show the banner in threads", () => {
        upsertRoomStateEvents(room, [
            mkEvent({
                event: true,
                type: "m.room.encryption",
                user: "@user1:server",
                content: {},
            }),
            mkEvent({
                event: true,
                type: "m.room.history_visibility",
                user: "@user1:server",
                content: {
                    history_visibility: "shared",
                },
            }),
        ]);

        const vm = new HistoryVisibleBannerViewModel({ room, canSendMessages: true, threadId: "some thread ID" });
        expect(vm.getSnapshot().visible).toBe(false);
        vm.dispose();
    });

    it("should not show the banner if the user cannot send messages", () => {
        upsertRoomStateEvents(room, [
            mkEvent({
                event: true,
                type: "m.room.encryption",
                user: "@user1:server",
                content: {},
            }),
            mkEvent({
                event: true,
                type: "m.room.history_visibility",
                user: "@user1:server",
                content: {
                    history_visibility: "shared",
                },
            }),
        ]);

        const vm = new HistoryVisibleBannerViewModel({ room, canSendMessages: false, threadId: null });
        expect(vm.getSnapshot().visible).toBe(false);
        vm.dispose();
    });

    it("should not show the banner if history visibility is `invited`", () => {
        upsertRoomStateEvents(room, [
            mkEvent({
                event: true,
                type: "m.room.encryption",
                user: "@user1:server",
                content: {},
            }),
            mkEvent({
                event: true,
                type: "m.room.history_visibility",
                user: "@user1:server",
                content: {
                    history_visibility: "invited",
                },
            }),
        ]);

        const vm = new HistoryVisibleBannerViewModel({ room, canSendMessages: true, threadId: null });
        expect(vm.getSnapshot().visible).toBe(false);
        vm.dispose();
    });

    it("should show the banner in encrypted rooms with shared history visibility", async () => {
        upsertRoomStateEvents(room, [
            mkEvent({
                event: true,
                type: "m.room.encryption",
                user: "@user1:server",
                content: {},
            }),
            mkEvent({
                event: true,
                type: "m.room.history_visibility",
                user: "@user1:server",
                content: {
                    history_visibility: "shared",
                },
            }),
        ]);

        const vm = new HistoryVisibleBannerViewModel({ room, canSendMessages: true, threadId: null });
        expect(vm.getSnapshot().visible).toBe(true);
        await vm.onClose();
        expect(vm.getSnapshot().visible).toBe(false);
    });
});
