import { afterEach, expect, test, vi } from "vitest";
import { parseResourceFolderFiles, resourcePlanToPayload, translateResourceCodes } from "./batchUpload.js";

afterEach(() => {
    vi.restoreAllMocks();
    vi.unstubAllGlobals();
});

test("parses folder resource filenames into resource plans", () => {
    const files = [
        file("头像框_星光_99_7_cover.png"),
        file("头像框_星光_99_7_animation.svga"),
        file("勋章_守护_长_cover.png"),
        file("勋章_守护_长_animation.pag"),
        file("背景卡_夜色_cover.png"),
        file("背景卡_夜色_animation.svga"),
        file("mic声波_律动_cover.png"),
        file("mic声波_律动_animation.svga"),
        file("礼物_玫瑰_520_cover.png"),
        file("礼物_玫瑰_520_animation.svga"),
    ];

    const plan = parseResourceFolderFiles(files, 1770000000000);

    expect(plan.errors).toEqual([]);
    expect(plan.resources.map((item) => [item.name, item.resourceType, item.price, item.badgeForm])).toEqual([
        ["星光", "avatar_frame", 99, "tile"],
        ["守护", "badge", 0, "strip"],
        ["夜色", "profile_card", 0, "tile"],
        ["律动", "mic_seat_animation", 0, "tile"],
        ["玫瑰", "gift", 520, "tile"],
    ]);
    expect(plan.resources.map((item) => item.resourceCode)).toEqual(["星光", "守护", "夜色", "律动", "玫瑰"]);

    expect(resourcePlanToPayload({ ...plan.resources[0], coverUrl: "cover", animationUrl: "animation" })).toMatchObject(
        {
            animationUrl: "animation",
            coinPrice: 99,
            previewUrl: "cover",
            priceType: "coin",
            resourceType: "avatar_frame",
        },
    );

    expect(resourcePlanToPayload({ ...plan.resources[4], coverUrl: "cover", animationUrl: "animation" })).toMatchObject(
        {
            coinPrice: 520,
            priceType: "coin",
            resourceType: "gift",
        },
    );

    expect(resourcePlanToPayload({ ...plan.resources[1], coverUrl: "cover", animationUrl: "animation" })).toMatchObject(
        {
            badgeForm: "strip",
            badgeKind: "normal",
            resourceType: "badge",
        },
    );

    expect(
        resourcePlanToPayload({
            ...plan.resources[2],
            animationUrl: "animation",
            coverUrl: "cover",
            metadataJson:
                '{"profile_card_layout":{"source_width":1136,"source_height":1680,"color_content_width":750,"content_top":117,"content_bottom":1666,"content_height":1550,"content_top_ratio":0.069643,"content_height_ratio":0.922619,"detect_version":1}}',
        }),
    ).toMatchObject({
        metadataJson: expect.stringContaining("profile_card_layout"),
        resourceType: "profile_card",
    });
});

test("silently ignores invalid and unpaired material", () => {
    const plan = parseResourceFolderFiles(
        [
            file("frame/vip_TOPO2.png"),
            file("气泡_清新_cover.png"),
            file("头像框_星光_99_7_cover.png"),
            file("头像框_星光_99_7_animation.svga"),
        ],
        1770000000000,
    );

    expect(plan.errors).toEqual([]);
    expect(plan.resources).toHaveLength(1);
    expect(plan.resources[0]).toMatchObject({ name: "星光", resourceCode: "星光", resourceType: "avatar_frame" });
});

test("keeps mp4 alpha layout metadata for gift and vehicle batch payloads", () => {
    const giftPayload = resourcePlanToPayload({
        animationUrl: "https://media.haiyihy.com/resource/gift.mp4",
        coverUrl: "cover",
        metadataJson: JSON.stringify({ mp4_alpha_layout: leftAlphaRightRgbLayout() }),
        name: "Love",
        price: 30000,
        resourceCode: "love",
        resourceType: "gift",
    });
    const vehiclePayload = resourcePlanToPayload({
        animationUrl: "https://media.haiyihy.com/resource/vehicle.mp4",
        coverUrl: "cover",
        metadataJson: JSON.stringify({ mp4_alpha_layout: leftAlphaRightRgbLayout() }),
        name: "Knight",
        price: 49000,
        resourceCode: "knight",
        resourceType: "vehicle",
    });

    expect(JSON.parse(giftPayload.metadataJson)).toMatchObject({
        animation_format: "mp4",
        mp4_alpha_layout: {
            alpha_frame: [0, 0, 750, 1334],
            alpha_layout: "alpha_left_rgb_right",
            rgb_frame: [750, 0, 750, 1334],
        },
    });
    expect(JSON.parse(vehiclePayload.metadataJson).mp4_alpha_layout.alpha_layout).toBe("alpha_left_rgb_right");
});

test("keeps profile card layout while adding mp4 alpha layout", () => {
    const payload = resourcePlanToPayload({
        animationUrl: "https://media.haiyihy.com/resource/profile-card.mp4",
        coverUrl: "cover",
        metadataJson: JSON.stringify({
            mp4_alpha_layout: leftAlphaRightRgbLayout(),
            profile_card_layout: {
                color_content_width: 750,
                content_bottom: 1666,
                content_height: 1550,
                content_height_ratio: 0.922619,
                content_top: 117,
                content_top_ratio: 0.069643,
                detect_version: 1,
                source_height: 1680,
                source_width: 1136,
            },
        }),
        name: "Night",
        price: 0,
        resourceCode: "night",
        resourceType: "profile_card",
    });
    const metadata = JSON.parse(payload.metadataJson);

    expect(metadata.profile_card_layout.content_top).toBe(117);
    expect(metadata.mp4_alpha_layout.rgb_frame).toEqual([750, 0, 750, 1334]);
});

test("translates chinese names to english resource codes with API fallback", async () => {
    vi.spyOn(Math, "random")
        .mockReturnValueOnce(0)
        .mockReturnValueOnce(51.5 / 52)
        .mockReturnValueOnce(26 / 52)
        .mockReturnValueOnce(27 / 52);
    vi.stubGlobal(
        "fetch",
        vi.fn(async (url) => {
            if (String(url).includes("mymemory")) {
                return new Response(JSON.stringify({ responseData: { translatedText: "Starlight" } }));
            }
            return new Response("{}", { status: 500 });
        }),
    );

    const translated = await translateResourceCodes([
        {
            name: "星光",
            resourceCode: "星光",
            resourceType: "avatar_frame",
        },
        {
            name: "c11",
            resourceCode: "c11",
            resourceType: "avatar_frame",
        },
    ]);

    expect(translated.map((item) => item.resourceCode)).toEqual(["starlight_aZ", "c11_AB"]);
});

test("uses local dictionary when public translation APIs fail", async () => {
    vi.spyOn(Math, "random").mockReturnValue(0);
    vi.stubGlobal(
        "fetch",
        vi.fn(async () => new Response("{}", { status: 500 })),
    );

    const translated = await translateResourceCodes([
        {
            name: "守护",
            resourceCode: "守护",
            resourceType: "badge",
        },
    ]);

    expect(translated[0].resourceCode).toBe("guardian_aa");
});

test("reports translate progress after suffix is added", async () => {
    vi.spyOn(Math, "random").mockReturnValue(0);
    vi.stubGlobal(
        "fetch",
        vi.fn(async () => new Response("{}", { status: 500 })),
    );
    const onProgress = vi.fn();

    await translateResourceCodes(
        [
            {
                name: "守护",
                resourceCode: "守护",
                resourceType: "badge",
            },
        ],
        { onProgress },
    );

    expect(onProgress).toHaveBeenCalledWith(
        expect.objectContaining({
            completed: 1,
            index: 0,
            resource: expect.objectContaining({ resourceCode: "guardian_aa" }),
            total: 1,
        }),
    );
});

function file(name) {
    return new File(["payload"], name, { type: "image/png" });
}

function leftAlphaRightRgbLayout() {
    return {
        alpha_frame: [0, 0, 750, 1334],
        alpha_layout: "alpha_left_rgb_right",
        confirmed: true,
        detect_version: 1,
        rgb_frame: [750, 0, 750, 1334],
        video_h: 1334,
        video_w: 1500,
    };
}
