/*
 * 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 { render, screen } from "@test-utils";
import { composeStories } from "@storybook/react-vite";
import React from "react";
import userEvent from "@testing-library/user-event";
import { fireEvent } from "@testing-library/dom";
import { describe, it, vi, afterEach, expect } from "vitest";

import * as stories from "./AudioPlayerView.stories.tsx";
import { AudioPlayerView, type AudioPlayerViewActions, type AudioPlayerViewSnapshot } from "./AudioPlayerView";
import { MockViewModel } from "../../../../../core/viewmodel/MockViewModel.ts";
import { I18nContext } from "../../../../../core/i18n/i18nContext.ts";
import { I18nApi } from "../../../../../core/i18n/I18nApi.ts";

const { Default, NoMediaName, NoSize, HasError } = composeStories(stories);

describe("AudioPlayerView", () => {
    afterEach(() => {
        vi.clearAllMocks();
    });

    it("renders the audio player in default state", () => {
        const { container } = render(<Default />);
        expect(container).toMatchSnapshot();
    });

    it("renders the audio player without media name", () => {
        const { container } = render(<NoMediaName />);
        expect(container).toMatchSnapshot();
    });

    it("renders the audio player without size", () => {
        const { container } = render(<NoSize />);
        expect(container).toMatchSnapshot();
    });

    it("renders the audio player in error state", () => {
        const { container } = render(<HasError />);
        expect(container).toMatchSnapshot();
    });

    const onKeyDown = vi.fn();
    const togglePlay = vi.fn();
    const onSeekbarChange = vi.fn();

    class AudioPlayerViewModel extends MockViewModel<AudioPlayerViewSnapshot> implements AudioPlayerViewActions {
        public onKeyDown = onKeyDown;
        public togglePlay = togglePlay;
        public onSeekbarChange = onSeekbarChange;
    }

    it("should attach vm methods", async () => {
        const user = userEvent.setup();
        const vm = new AudioPlayerViewModel({
            playbackState: "stopped",
            mediaName: "Test Audio",
            durationSeconds: 300,
            playedSeconds: 120,
            percentComplete: 30,
            sizeBytes: 3500,
            error: false,
        });

        render(<AudioPlayerView vm={vm} />, {
            wrapper: ({ children }) => <I18nContext.Provider value={new I18nApi()}>{children}</I18nContext.Provider>,
        });
        await user.click(screen.getByRole("button", { name: "Play" }));
        expect(togglePlay).toHaveBeenCalled();

        // user event doesn't support change events on sliders, so we use fireEvent
        fireEvent.change(screen.getByRole("slider", { name: "Audio seek bar" }), { target: { value: "50" } });
        expect(onSeekbarChange).toHaveBeenCalled();

        await user.type(screen.getByLabelText("Audio player"), "{arrowup}");
        expect(onKeyDown).toHaveBeenCalledWith(expect.objectContaining({ key: "ArrowUp" }));
    });
});
