import { afterEach, beforeEach, expect, test, vi } from "vitest";
import * as path from "node:path";

const hoisted = vi.hoisted(() => ({
  getConfiguration: vi.fn(),
  showErrorMessage: vi.fn(),
  vscodeVariables: vi.fn((value: string) => value.replace(/\$\{workspaceFolder\}/g, "/workspace")),
}));

vi.mock("vscode", () => ({
  workspace: {
    getConfiguration: hoisted.getConfiguration,
  },
  window: {
    activeColorTheme: { kind: 1 },
    showErrorMessage: hoisted.showErrorMessage,
  },
  ColorThemeKind: {
    Dark: 2,
    HighContrast: 3,
  },
}));

vi.mock("./vscode-variables", () => ({
  vscodeVariables: hoisted.vscodeVariables,
}));

import {
  loadTinymistConfig,
  patchInjectedClientOptionsInConfig,
  resolvePreviewerValue,
  substVscodeVarsInConfig,
} from "./config.js";

beforeEach(() => {
  hoisted.getConfiguration.mockReset();
  hoisted.showErrorMessage.mockReset();
  hoisted.vscodeVariables.mockClear();
  vi.spyOn(console, "warn").mockImplementation(() => undefined);
});

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

test("loadTinymistConfig preserves substitution for valid fontPaths arrays", () => {
  hoisted.getConfiguration.mockReturnValue({
    fontPaths: ["${workspaceFolder}/fonts", "assets/fonts"],
  });

  expect(loadTinymistConfig().fontPaths).toEqual(["/workspace/fonts", "assets/fonts"]);
  expect(substVscodeVarsInConfig(["tinymist.fontPaths"], [["${workspaceFolder}/fonts"]])).toEqual([
    ["/workspace/fonts"],
  ]);
  expect(hoisted.showErrorMessage).not.toHaveBeenCalled();
});

test("substVscodeVarsInConfig ignores mixed-type fontPaths arrays", () => {
  expect(
    substVscodeVarsInConfig(["tinymist.fontPaths"], [["${workspaceFolder}/fonts", 1]]),
  ).toEqual([undefined]);
  expect(hoisted.showErrorMessage).toHaveBeenCalledTimes(1);
});

test("patchInjectedClientOptionsInConfig fills requested injected flags", () => {
  expect(
    patchInjectedClientOptionsInConfig(
      ["tinymist.supportClientCodelens", "supportExtendedCodeAction", "tinymist.compileStatus"],
      [undefined, null, "disable"],
      {
        supportClientCodelens: true,
        supportExtendedCodeAction: false,
        compileStatus: "enable",
      },
    ),
  ).toEqual([true, false, "disable"]);
});

test("patchInjectedClientOptionsInConfig patches tinymist objects without overriding values", () => {
  expect(
    patchInjectedClientOptionsInConfig(
      ["tinymist"],
      [
        {
          supportClientCodelens: false,
          supportExtendedCodeAction: null,
        },
      ],
      {
        supportClientCodelens: true,
        supportExtendedCodeAction: true,
        delegateFsRequests: false,
      },
    ),
  ).toEqual([
    {
      supportClientCodelens: false,
      supportExtendedCodeAction: true,
      delegateFsRequests: false,
    },
  ]);
});

test("loadTinymistConfig substitutes previewer html paths", () => {
  hoisted.getConfiguration.mockReturnValue({
    previewer: "html:${workspaceFolder}/preview-provider/../local-previewer.html",
  });

  expect(loadTinymistConfig().previewer).toBe(
    `html:${path.normalize("/workspace/local-previewer.html")}`,
  );
});

test("resolvePreviewerValue substitutes and normalizes html previewer paths", () => {
  expect(
    resolvePreviewerValue("html:${workspaceFolder}/preview-provider/../local-previewer.html"),
  ).toBe(`html:${path.normalize("/workspace/local-previewer.html")}`);
});

test("resolvePreviewerValue preserves extension id providers", () => {
  expect(resolvePreviewerValue(" myriad-dreamin.tinymist-previewer-fixture ")).toBe(
    "myriad-dreamin.tinymist-previewer-fixture",
  );
});
