import { afterEach, expect, test, vi } from "vitest";
import { setAccessToken, setSelectedAppCode } from "@/shared/api/request";
import { createPolicyInstance, listPolicyInstances, listPolicyTemplates, publishPolicyInstance, savePolicyTemplate, updatePolicyInstanceStatus } from "./api";

afterEach(() => {
    setAccessToken("");
    setSelectedAppCode("lalu");
    vi.unstubAllGlobals();
});

function mockEnvelope(data: unknown, status = 200) {
    vi.stubGlobal(
        "fetch",
        vi.fn(async () => new Response(JSON.stringify({ code: 0, data }), { status })),
    );
}

function requestHeaders(init: RequestInit | undefined): Record<string, string> {
    return (init?.headers || {}) as Record<string, string>;
}

function requestBody(init: RequestInit | undefined): Record<string, unknown> {
    return JSON.parse(String(init?.body || "{}")) as Record<string, unknown>;
}

test("listPolicyTemplates normalizes snake case page and template fields", async () => {
    vi.stubGlobal(
        "fetch",
        vi.fn(
            async () =>
                new Response(
                    JSON.stringify({
                        code: 0,
                        data: {
                            items: [
                                {
                                    created_at_ms: "1767225600000",
                                    description: "Huwaa default policy",
                                    name: "Huwaa Google + coin seller",
                                    rule_json: "{\"google_coin_per_usd\":70000,\"coin_seller\":{\"levels\":[{\"coin_per_usd\":92000}]}}",
                                    status: "active",
                                    template_code: "first_google70000_coin_seller_92000_100000_v1",
                                    template_id: "101",
                                    template_version: "v1",
                                    updated_at_ms: "1767229200000",
                                    version_id: "202",
                                },
                            ],
                            page: 1,
                            page_size: 50,
                            total: 1,
                        },
                    }),
                ),
        ),
    );

    const result = await listPolicyTemplates({ page: 1, page_size: 50, status: "active" });
    const [url, init] = vi.mocked(fetch).mock.calls[0];

    expect(String(url)).toContain("/api/v1/admin/policy-templates?");
    expect(String(url)).toContain("page_size=50");
    expect(String(url)).toContain("status=active");
    expect(init?.method).toBe("GET");
    expect(result.pageSize).toBe(50);
    expect(result.items[0]).toMatchObject({
        createdAtMs: 1767225600000,
        ruleJson: {
            coin_seller: { levels: [{ coin_per_usd: 92000 }] },
            google_coin_per_usd: 70000,
        },
        templateCode: "first_google70000_coin_seller_92000_100000_v1",
        templateId: 101,
        templateVersion: "v1",
        updatedAtMs: 1767229200000,
        versionId: 202,
    });
});

test("savePolicyTemplate sends typed upsert payload and normalizes response", async () => {
    mockEnvelope(
        {
            created_at_ms: "1767225600000",
            description: "desc",
            name: "Policy",
            rule_json: { points_per_usd: 100000 },
            status: "active",
            template_code: "code",
            template_id: "101",
            template_version: "v2",
            updated_at_ms: "1767229200000",
            version_id: "202",
        },
        201,
    );

    const result = await savePolicyTemplate({
        description: "desc",
        name: "Policy",
        rule_json: { points_per_usd: 100000 },
        status: "active",
        template_code: "code",
        template_version: "v2",
    });
    const [url, init] = vi.mocked(fetch).mock.calls[0];

    expect(String(url)).toContain("/api/v1/admin/policy-templates");
    expect(init?.method).toBe("POST");
    expect(requestHeaders(init)["Content-Type"]).toBe("application/json");
    expect(requestBody(init)).toMatchObject({
        name: "Policy",
        rule_json: { points_per_usd: 100000 },
        template_code: "code",
        template_version: "v2",
    });
    expect(result).toMatchObject({
        ruleJson: { points_per_usd: 100000 },
        templateCode: "code",
        templateId: 101,
        templateVersion: "v2",
        versionId: 202,
    });
});

test("listPolicyInstances normalizes snake case page and instance fields", async () => {
    vi.stubGlobal(
        "fetch",
        vi.fn(
            async () =>
                new Response(
                    JSON.stringify({
                        code: 0,
                        data: {
                            items: [
                                {
                                    app_code: "huwaa",
                                    created_at_ms: "1767225600000",
                                    effective_from_ms: "1767225600000",
                                    effective_to_ms: "1767312000000",
                                    instance_code: "huwaa_policy",
                                    instance_id: "301",
                                    last_published_at_ms: "1767229200000",
                                    publish_error: "",
                                    publish_status: "published",
                                    region_scope: "region_id:1001",
                                    status: "active",
                                    template_code: "first_google70000_coin_seller_92000_100000_v1",
                                    template_version: "v1",
                                    updated_at_ms: "1767229300000",
                                },
                            ],
                            page: 2,
                            page_size: 20,
                            total: 31,
                        },
                    }),
                ),
        ),
    );

    const result = await listPolicyInstances({ keyword: "huwaa", page: 2, page_size: 20 });
    const [url, init] = vi.mocked(fetch).mock.calls[0];

    expect(String(url)).toContain("/api/v1/admin/policy-instances?");
    expect(String(url)).toContain("keyword=huwaa");
    expect(String(url)).toContain("page_size=20");
    expect(init?.method).toBe("GET");
    expect(result.pageSize).toBe(20);
    expect(result.items[0]).toMatchObject({
        appCode: "huwaa",
        createdAtMs: 1767225600000,
        effectiveFromMs: 1767225600000,
        effectiveToMs: 1767312000000,
        instanceCode: "huwaa_policy",
        instanceId: 301,
        lastPublishedAtMs: 1767229200000,
        publishStatus: "published",
        regionScope: "region_id:1001",
        templateCode: "first_google70000_coin_seller_92000_100000_v1",
        templateVersion: "v1",
        updatedAtMs: 1767229300000,
    });
});

test("createPolicyInstance sends app-scoped payload with selected X-App-Code", async () => {
    setSelectedAppCode("huwaa");
    mockEnvelope(
        {
            app_code: "huwaa",
            created_at_ms: "1767225600000",
            effective_from_ms: "1767225600000",
            effective_to_ms: "0",
            instance_code: "huwaa_policy",
            instance_id: "301",
            last_published_at_ms: "0",
            publish_error: "",
            publish_status: "draft",
            region_scope: "all_active_regions",
            status: "active",
            template_code: "code",
            template_version: "v1",
            updated_at_ms: "1767225600000",
        },
        201,
    );

    const result = await createPolicyInstance({
        effective_from_ms: 1767225600000,
        effective_to_ms: 0,
        instance_code: "huwaa_policy",
        region_scope: "all_active_regions",
        status: "active",
        template_code: "code",
        template_version: "v1",
    });
    const [url, init] = vi.mocked(fetch).mock.calls[0];

    expect(String(url)).toContain("/api/v1/admin/policy-instances");
    expect(init?.method).toBe("POST");
    expect(requestHeaders(init)["X-App-Code"]).toBe("huwaa");
    expect(requestBody(init)).toMatchObject({
        effective_from_ms: 1767225600000,
        instance_code: "huwaa_policy",
        region_scope: "all_active_regions",
        template_code: "code",
    });
    expect(result).toMatchObject({
        appCode: "huwaa",
        instanceCode: "huwaa_policy",
        instanceId: 301,
        regionScope: "all_active_regions",
    });
});

test("publishPolicyInstance normalizes snake case publish result fields", async () => {
    vi.stubGlobal(
        "fetch",
        vi.fn(
            async () =>
                new Response(
                    JSON.stringify({
                        code: 0,
                        data: {
                            app_code: "huwaa",
                            instance_code: "huwaa_policy",
                            instance_id: "301",
                            job_id: "401",
                            published_at_ms: "1767229300000",
                            published_region_ids: ["1001", "1002"],
                            status: "published",
                            target_count: "2",
                            template_code: "first_google70000_coin_seller_92000_100000_v1",
                            template_version: "v1",
                        },
                    }),
                ),
        ),
    );

    const result = await publishPolicyInstance("301");
    const [url, init] = vi.mocked(fetch).mock.calls[0];

    expect(String(url)).toContain("/api/v1/admin/policy-instances/301/publish");
    expect(init?.method).toBe("POST");
    expect(result).toMatchObject({
        appCode: "huwaa",
        instanceCode: "huwaa_policy",
        instanceId: 301,
        jobId: 401,
        publishedAtMs: 1767229300000,
        publishedRegionIds: [1001, 1002],
        status: "published",
        targetCount: 2,
        templateCode: "first_google70000_coin_seller_92000_100000_v1",
        templateVersion: "v1",
    });
});

test("updatePolicyInstanceStatus sends PUT status with selected X-App-Code", async () => {
    setSelectedAppCode("huwaa");
    mockEnvelope({
        app_code: "huwaa",
        created_at_ms: "1767225600000",
        effective_from_ms: "1767225600000",
        effective_to_ms: "0",
        instance_code: "huwaa_policy",
        instance_id: "301",
        last_published_at_ms: "0",
        publish_error: "",
        publish_status: "draft",
        region_scope: "all_active_regions",
        status: "disabled",
        template_code: "code",
        template_version: "v1",
        updated_at_ms: "1767229300000",
    });

    const result = await updatePolicyInstanceStatus(301, "disabled");
    const [url, init] = vi.mocked(fetch).mock.calls[0];

    expect(String(url)).toContain("/api/v1/admin/policy-instances/301/status");
    expect(init?.method).toBe("PUT");
    expect(requestHeaders(init)["X-App-Code"]).toBe("huwaa");
    expect(requestBody(init)).toEqual({ status: "disabled" });
    expect(result).toMatchObject({
        appCode: "huwaa",
        instanceId: 301,
        status: "disabled",
    });
});
