import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { discoverMocks, resolveRoute } from "./start";

describe("discoverMocks", () => {
  let tmpDir: string;

  beforeEach(() => {
    tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "mock-start-test-"));
  });

  afterEach(() => {
    fs.rmSync(tmpDir, { recursive: true, force: true });
  });

  function writeMock(provider: string, scenario: string): void {
    const dir = path.join(tmpDir, provider, scenario);
    fs.mkdirSync(dir, { recursive: true });
    fs.writeFileSync(path.join(dir, "mock.json"), "{}");
  }

  function pairs(mocks: { provider: string; scenario: string }[]): string[] {
    return mocks.map((m) => `${m.provider}/${m.scenario}`).sort();
  }

  it("discovers every scenario that contains a mock.json", () => {
    writeMock("shopify", "admin-api");
    writeMock("shopify", "storefront");
    writeMock("stripe", "payments");

    expect(pairs(discoverMocks(tmpDir, []))).toEqual([
      "shopify/admin-api",
      "shopify/storefront",
      "stripe/payments",
    ]);
  });

  it("skips scenario directories without a mock.json", () => {
    writeMock("shopify", "admin-api");
    fs.mkdirSync(path.join(tmpDir, "shopify", "empty"), { recursive: true });

    expect(pairs(discoverMocks(tmpDir, []))).toEqual(["shopify/admin-api"]);
  });

  it("filters by provider", () => {
    writeMock("shopify", "admin-api");
    writeMock("stripe", "payments");

    expect(pairs(discoverMocks(tmpDir, ["shopify"]))).toEqual(["shopify/admin-api"]);
  });

  it("filters by provider/scenario", () => {
    writeMock("shopify", "admin-api");
    writeMock("shopify", "storefront");

    expect(pairs(discoverMocks(tmpDir, ["shopify/storefront"]))).toEqual(["shopify/storefront"]);
  });

  it("returns an empty array for a nonexistent mocks directory", () => {
    expect(discoverMocks(path.join(tmpDir, "missing"), [])).toEqual([]);
  });
});

describe("resolveRoute", () => {
  const routes = ["/shopify/admin-api", "/stripe/payments"];

  it("matches a known route and strips the prefix", () => {
    expect(resolveRoute("/shopify/admin-api/products", routes)).toEqual({
      kind: "matched",
      key: "/shopify/admin-api",
      downstream: "/products",
    });
  });

  it("keeps the query string on the downstream path", () => {
    expect(resolveRoute("/shopify/admin-api/products?limit=10", routes)).toEqual({
      kind: "matched",
      key: "/shopify/admin-api",
      downstream: "/products?limit=10",
    });
  });

  it("defaults the downstream path to / when nothing follows the prefix", () => {
    expect(resolveRoute("/shopify/admin-api", routes)).toEqual({
      kind: "matched",
      key: "/shopify/admin-api",
      downstream: "/",
    });
  });

  it("reports an unknown route when the prefix is not registered", () => {
    expect(resolveRoute("/unknown/scenario/x", routes)).toEqual({
      kind: "unknownRoute",
      key: "/unknown/scenario",
    });
  });

  it("reports malformed when the URL lacks a provider/scenario pair", () => {
    expect(resolveRoute("/single", routes)).toEqual({ kind: "malformed" });
    expect(resolveRoute("/", routes)).toEqual({ kind: "malformed" });
    expect(resolveRoute(undefined, routes)).toEqual({ kind: "malformed" });
  });
});
