import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { beforeEach, expect, test, vi } from "vitest";
import { downloadResponse } from "@/shared/api/download";
import { uploadFile, uploadImage } from "@/shared/api/upload";
import { ToastProvider } from "@/shared/ui/ToastProvider.jsx";
import { UploadField } from "./UploadField.jsx";

vi.mock("@/shared/api/upload", () => ({
    uploadFile: vi.fn(async () => ({ url: "https://media.haiyihy.com/admin/files/effect.bin" })),
    uploadImage: vi.fn(async () => ({ url: "https://media.haiyihy.com/admin/images/effect.png" })),
}));

vi.mock("@/shared/api/download", () => ({
    downloadResponse: vi.fn(async () => undefined),
}));

beforeEach(() => {
    vi.clearAllMocks();
});

test("file upload field does not restrict picker type and uses generic upload endpoint", async () => {
    const onChange = vi.fn();
    const onFileSelected = vi.fn();
    const { container } = render(
        <ToastProvider>
            <UploadField kind="file" label="动效素材" value="" onChange={onChange} onFileSelected={onFileSelected} />
        </ToastProvider>,
    );
    const input = container.querySelector('input[type="file"]');

    expect(input).not.toHaveAttribute("accept");

    fireEvent.change(input, {
        target: {
            files: [new File(["effect"], "effect.bin", { type: "application/octet-stream" })],
        },
    });

    await waitFor(() => expect(uploadFile).toHaveBeenCalledTimes(1));
    expect(onFileSelected).toHaveBeenCalledWith(expect.objectContaining({ name: "effect.bin" }));
    expect(uploadImage).not.toHaveBeenCalled();
    expect(onChange).toHaveBeenCalledWith("https://media.haiyihy.com/admin/files/effect.bin");
});

test("image-style resource field accepts PAG and routes it through generic upload", async () => {
    const onChange = vi.fn();
    const { container } = render(
        <ToastProvider>
            <UploadField kind="image" label="动效素材" value="" onChange={onChange} />
        </ToastProvider>,
    );
    const input = container.querySelector('input[type="file"]');
    const file = new File(["pag"], "effect.pag", { type: "application/octet-stream" });

    expect(input).not.toHaveAttribute("accept");
    fireEvent.change(input, { target: { files: [file] } });

    await waitFor(() => expect(uploadFile).toHaveBeenCalledWith(file));
    expect(uploadImage).not.toHaveBeenCalled();
    expect(onChange).toHaveBeenCalledWith("https://media.haiyihy.com/admin/files/effect.bin");
});

test("standard raster image keeps the strict image upload endpoint", async () => {
    const onChange = vi.fn();
    const { container } = render(
        <ToastProvider>
            <UploadField kind="image" label="封面" value="" onChange={onChange} />
        </ToastProvider>,
    );
    const file = new File(["png"], "cover.png", { type: "image/png" });

    fireEvent.change(container.querySelector('input[type="file"]'), { target: { files: [file] } });

    await waitFor(() => expect(uploadImage).toHaveBeenCalledWith(file));
    expect(uploadFile).not.toHaveBeenCalled();
    expect(onChange).toHaveBeenCalledWith("https://media.haiyihy.com/admin/images/effect.png");
});

test("mp4 file upload field can open video preview dialog", async () => {
    const source = "https://media.haiyihy.com/admin/files/gift.mp4?sign=1";
    const onChange = vi.fn();
    const { container } = render(
        <ToastProvider>
            <UploadField kind="file" label="动效素材" value={source} onChange={onChange} />
        </ToastProvider>,
    );

    expect(screen.getByText("MP4")).toBeInTheDocument();
    const clearButton = screen.getByRole("button", { name: "清除" });

    fireEvent.click(screen.getByRole("button", { name: "查看" }));

    expect(screen.getByRole("dialog", { name: "动效素材 MP4" })).toBeInTheDocument();
    expect(container.ownerDocument.querySelector("video")).toHaveAttribute("src", source);

    fireEvent.click(clearButton);

    expect(onChange).toHaveBeenCalledWith("");
    await waitFor(() => {
        expect(screen.queryByRole("dialog", { name: "动效素材 MP4" })).not.toBeInTheDocument();
    });
});

test("source actions open the asset in a new tab and download it with the source filename", async () => {
    const source = "https://media.haiyihy.com/admin/files/frame.webp?sign=1";
    const response = { ok: true, status: 200 };
    const fetchMock = vi.fn(async () => response);
    const openMock = vi.spyOn(window, "open").mockImplementation(() => null);
    vi.stubGlobal("fetch", fetchMock);

    render(
        <ToastProvider>
            <UploadField
                kind="file"
                label="资源封面"
                showSourceActions
                value={source}
                onChange={vi.fn()}
            />
        </ToastProvider>,
    );

    fireEvent.click(screen.getByRole("button", { name: "打开资源封面" }));
    expect(openMock).toHaveBeenCalledWith(source, "_blank", "noopener,noreferrer");

    fireEvent.click(screen.getByRole("button", { name: "下载资源封面" }));
    await waitFor(() => expect(downloadResponse).toHaveBeenCalledWith(response, "frame.webp"));
    expect(fetchMock).toHaveBeenCalledWith(source);

    openMock.mockRestore();
    vi.unstubAllGlobals();
});
