import { createHmac } from "node:crypto";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { SubscriptionStatus } from "@prisma/client";
import { db } from "@/lib/db";
import { encryptCredential } from "./credential-crypto";
import { syncSiteLicense } from "./license-sync";

vi.mock("node:dns/promises", () => ({ lookup: vi.fn(async () => [{ address: "93.184.216.34" }]) }));
vi.mock("@/lib/env", () => ({ getEnv: () => ({ CREDENTIAL_ENCRYPTION_KEY: "test-encryption-key-material" }) }));
vi.mock("@/lib/db", () => ({ db: { site: { findUnique: vi.fn(), update: vi.fn() } } }));

function pairedSite(status: SubscriptionStatus) {
  return {
    id: "site-1",
    pluginSiteId: "plugin-site-1",
    normalizedUrl: "https://example.com",
    organization: { subscription: {
      status,
      plan: { code: "growth", name: "Growth", siteLimit: 10, clientSeatLimit: 10, allowAiChat: true, allowChatAnalytics: true, allowMultiSiteJobs: true, allowWhiteLabel: false },
      trialEndsAt: null,
      currentPeriodEnd: null,
    } },
    credentials: [{ encryptedSecret: encryptCredential("paired-secret", "test-encryption-key-material") }],
  };
}

describe("site license sync", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    vi.mocked(db.site.update).mockResolvedValue({} as never);
  });

  it("sends a site-bound signed entitlement for an active subscription", async () => {
    vi.mocked(db.site.findUnique).mockResolvedValue(pairedSite(SubscriptionStatus.ACTIVE) as never);
    const fetchMock = vi.fn(async () => new Response(JSON.stringify({ success: true }), { status: 200 }));
    vi.stubGlobal("fetch", fetchMock);
    try {
      await syncSiteLicense("site-1");
      const [url, options] = fetchMock.mock.calls[0] as unknown as [URL, RequestInit];
      const body = String(options.body);
      const headers = options.headers as Record<string, string>;
      expect(url.pathname).toBe("/wp-json/site-agent/v1/license");
      expect(headers["X-Site-Agent-License-Signature"]).toBe(createHmac("sha256", "paired-secret").update(body).digest("hex"));
      expect(JSON.parse(body)).toMatchObject({ site_id: "plugin-site-1", active: true, plan_code: "growth", limits: { sites: 10 } });
      expect(db.site.update).toHaveBeenCalledWith(expect.objectContaining({ data: expect.objectContaining({ licenseActive: true }) }));
    } finally { vi.unstubAllGlobals(); }
  });

  it("deactivates the entitlement when WooCommerce cancels", async () => {
    vi.mocked(db.site.findUnique).mockResolvedValue(pairedSite(SubscriptionStatus.CANCELED) as never);
    const fetchMock = vi.fn(async () => new Response(JSON.stringify({ success: true }), { status: 200 }));
    vi.stubGlobal("fetch", fetchMock);
    try {
      await syncSiteLicense("site-1");
      const body = JSON.parse(String((fetchMock.mock.calls[0][1] as RequestInit).body));
      expect(body.active).toBe(false);
      expect(body.features.ai_chat).toBe(false);
      expect(db.site.update).toHaveBeenCalledWith(expect.objectContaining({ data: expect.objectContaining({ licenseActive: false }) }));
    } finally { vi.unstubAllGlobals(); }
  });
});
