import assert from "node:assert/strict";
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join, resolve } from "node:path";
import { after, before, test } from "node:test";

import { createServer } from "vite";

const testRoot = dirname(fileURLToPath(import.meta.url));
const controlStationRoot = resolve(testRoot, "..");
const repositoryRoot = resolve(controlStationRoot, "../..");
const coreSourceRoot = join(controlStationRoot, "src");
const pluginFrontendRoot = join(repositoryRoot, "plugins/xgrids-k1/frontend/src");
const legacyPluginRoot = join(coreSourceRoot, "device-plugins/xgrids-k1");

function sourceFiles(root) {
  return readdirSync(root).flatMap((entry) => {
    const path = join(root, entry);
    if (statSync(path).isDirectory()) return sourceFiles(path);
    return /\.(?:css|ts|tsx)$/.test(entry) ? [path] : [];
  });
}

let server;
let createDevicePluginRegistry;

before(async () => {
  server = await createServer({
    appType: "custom",
    logLevel: "silent",
    server: { middlewareMode: true },
  });
  ({ createDevicePluginRegistry } = await server.ssrLoadModule(
    "/src/core/device-plugins/registry.ts",
  ));
});

after(async () => {
  await server?.close();
});

function syntheticPlugin({
  pluginId,
  modelId,
  componentKey,
  connectionView,
  spatialControlsView,
}) {
  return {
    manifest: {
      apiVersion: "missioncore.nodedc/v1alpha2",
      kind: "DevicePlugin",
      metadata: { id: pluginId, version: "1.0.0", displayName: pluginId },
      spec: {
        hostApiRange: "v1alpha2",
        runtime: { backendEntrypoint: `${pluginId}:build`, isolation: "transitional-in-process" },
        permissions: ["device.read"],
        actions: [{ id: "state.read", mutating: false, secretFields: [] }],
        compatibilityProfiles: [{
          profileId: `${modelId}.profile.v1`,
          path: `profiles/${modelId}.json`,
          modelId,
        }],
        models: [{
          id: modelId,
          vendor: pluginId,
          displayName: modelId,
          category: "Sensor",
          description: "Synthetic frontend contribution",
          verified: true,
          capabilities: [{ id: "device.read", label: "Read" }],
          ui: { slot: "device.connection", componentKey },
        }],
      },
    },
    RuntimeProvider: ({ children }) => children,
    connectionViews: { [componentKey]: connectionView },
    ...(spatialControlsView ? { SpatialControlsView: spatialControlsView } : {}),
  };
}

test("each device plugin contributes its own connection pipeline component", () => {
  const alphaConnection = () => null;
  const betaConnection = () => null;
  const registry = createDevicePluginRegistry([
    syntheticPlugin({
      pluginId: "synthetic.alpha",
      modelId: "synthetic.alpha.sensor",
      componentKey: "alpha.connection",
      connectionView: alphaConnection,
    }),
    syntheticPlugin({
      pluginId: "synthetic.beta",
      modelId: "synthetic.beta.sensor",
      componentKey: "beta.connection",
      connectionView: betaConnection,
    }),
  ]);

  assert.equal(registry.resolveModel("synthetic.alpha.sensor").ConnectionView, alphaConnection);
  assert.equal(registry.resolveModel("synthetic.beta.sensor").ConnectionView, betaConnection);
  assert.notEqual(
    registry.resolveModel("synthetic.alpha.sensor").ConnectionView,
    registry.resolveModel("synthetic.beta.sensor").ConnectionView,
  );
});

test("registry exposes an optional model-scoped spatial controls contribution", () => {
  const connectionView = () => null;
  const spatialControlsView = () => null;
  const registry = createDevicePluginRegistry([
    syntheticPlugin({
      pluginId: "synthetic.spatial",
      modelId: "synthetic.spatial.sensor",
      componentKey: "spatial.connection",
      connectionView,
      spatialControlsView,
    }),
    syntheticPlugin({
      pluginId: "synthetic.connection-only",
      modelId: "synthetic.connection-only.sensor",
      componentKey: "connection-only.connection",
      connectionView,
    }),
  ]);

  assert.equal(
    registry.resolveModel("synthetic.spatial.sensor").SpatialControlsView,
    spatialControlsView,
  );
  assert.equal(
    registry.resolveModel("synthetic.connection-only.sensor").SpatialControlsView,
    undefined,
  );
});

test("XGRIDS frontend is physically plugin-owned and split by operator pipeline", () => {
  if (existsSync(legacyPluginRoot)) {
    assert.deepEqual(readdirSync(legacyPluginRoot), []);
  }
  for (const relativePath of [
    "plugin.ts",
    "runtimeContext.tsx",
    "styles.css",
    "components/K1ProvisioningPipeline.tsx",
    "components/K1AcquisitionPipeline.tsx",
    "components/K1SpatialControls.tsx",
    "components/K1Diagnostics.tsx",
    "projectName.ts",
  ]) {
    assert.equal(existsSync(join(pluginFrontendRoot, relativePath)), true, relativePath);
  }

  const spatialControls = readFileSync(
    join(pluginFrontendRoot, "components/K1SpatialControls.tsx"),
    "utf8",
  );
  assert.match(spatialControls, /shouldRenderSpatialControls\(state\)/);
  assert.match(spatialControls, /cleanup_pending/);
  assert.match(spatialControls, /spatialActionFailure/);
  assert.match(spatialControls, /role="alert"/);
  assert.match(spatialControls, /Повторить остановку/);
});

test("generic Control Station has one composition import and no K1 implementation knowledge", () => {
  const compositionPath = join(coreSourceRoot, "composition/devicePlugins.ts");
  const composition = readFileSync(compositionPath, "utf8");
  assert.match(composition, /from "@xgrids-k1\/frontend\/plugin"/);

  for (const path of sourceFiles(coreSourceRoot)) {
    if (path === compositionPath) continue;
    const source = readFileSync(path, "utf8");
    assert.doesNotMatch(source, /xgrids|lixel|\bk1\b/i, path);
  }

  for (const path of sourceFiles(pluginFrontendRoot)) {
    const source = readFileSync(path, "utf8");
    assert.doesNotMatch(source, /apps\/control-station|\.\.\/\.\.\/core|\.\.\/\.\.\/components/, path);
  }
});
