import { describe, expect, it, vi } from "vitest";
import { ref } from "vue";

import type { TaskMonitor } from "@/composables/genericTaskMonitor";
import {
    type MonitoringData,
    type MonitoringRequest,
    usePersistentProgressTaskMonitor,
} from "@/composables/persistentProgressMonitor";

// Mocks for dependencies
vi.mock("@vueuse/core", () => ({
    useLocalStorage: vi.fn().mockImplementation((key, initialValue) => ref(initialValue)),
    StorageSerializers: {
        object: {
            read: (value: string) => JSON.parse(value),
            write: (value: any) => JSON.stringify(value),
        },
    },
}));

function useMonitorMock(): TaskMonitor {
    const isRunning = ref(false);
    const taskStatus = ref();

    return {
        waitForTask: vi.fn().mockImplementation(() => {
            isRunning.value = true;
        }),
        stopWaitingForTask: vi.fn(),
        isRunning,
        isCompleted: ref(false),
        hasFailed: ref(false),
        failureReason: ref(),
        requestHasFailed: ref(false),
        taskStatus,
        expirationTime: 1000,
        isFinalState: vi.fn(),
        loadStatus(storedStatus) {
            taskStatus.value = storedStatus;
        },
        fetchTaskStatus: vi.fn(),
    };
}
const mockUseMonitor = useMonitorMock();

const MOCK_REQUEST: MonitoringRequest = {
    source: "testSource",
    action: "export",
    taskType: "task",
    object: {
        id: "1",
        type: "history",
    },
    description: "Test description",
};

describe("usePersistentProgressTaskMonitor", () => {
    it("should initialize with no monitoring data if none is provided or stored", () => {
        const { hasMonitoringData } = usePersistentProgressTaskMonitor(MOCK_REQUEST, mockUseMonitor);
        expect(hasMonitoringData.value).toBeFalsy();
    });

    it("should start monitoring with provided monitoring data", async () => {
        const monitoringData: MonitoringData = {
            taskId: "123",
            taskType: "task",
            request: MOCK_REQUEST,
            startedAt: new Date(),
            isFinal: false,
        };

        const { start, isRunning } = usePersistentProgressTaskMonitor(MOCK_REQUEST, mockUseMonitor, monitoringData);

        await start();
        expect(isRunning.value).toBeTruthy();
    });

    it("should throw an error if trying to start monitoring without monitoring data", async () => {
        const { start } = usePersistentProgressTaskMonitor(MOCK_REQUEST, mockUseMonitor);
        await expect(start()).rejects.toThrow(
            "No monitoring data provided or stored. Cannot start monitoring progress.",
        );
    });

    it("should reset monitoring data", () => {
        const monitoringData: MonitoringData = {
            taskId: "123",
            taskType: "task",
            request: MOCK_REQUEST,
            startedAt: new Date(),
            isFinal: false,
        };

        const { reset, hasMonitoringData } = usePersistentProgressTaskMonitor(
            MOCK_REQUEST,
            mockUseMonitor,
            monitoringData,
        );
        expect(hasMonitoringData.value).toBeTruthy();
        reset();
        expect(hasMonitoringData.value).toBeFalsy();
    });
});
