import type {
  DashboardWidgetsUiCapability,
  OrganizationFunctionActionContext,
  OrganizationFunctionActionContribution,
  PlatformWebModule
} from "../src/types";
import {
  hasUiCapability,
  moduleInstalled,
  moduleIntegrationEnabled,
  routeContributionsForModules,
  uiCapability
} from "../src/platform/moduleLogic";
import {
  isViewSurfaceVisible,
  viewSurfaceCatalogueForModules,
  visibleRoutesForProjection
} from "../src/platform/views";
import { scopeGrants } from "../src/utils/permissions";

function assert(condition: unknown, message: string): void {
  if (!condition) throw new Error(message);
}

const access: PlatformWebModule = { id: "access", label: "Access", version: "test" };
const filesCapability = { kind: "fileExplorer" };
const mailCapability = { kind: "mailProfiles" };
const files: PlatformWebModule = {
  id: "files",
  label: "Files",
  version: "test",
  routes: [{ path: "/files", order: 20, render: () => null }],
  uiCapabilities: { "files.fileExplorer": filesCapability }
};
const mail: PlatformWebModule = {
  id: "mail",
  label: "Mail",
  version: "test",
  routes: [{ path: "/mail", order: 30, render: () => null }],
  uiCapabilities: { "mail.profiles": mailCapability }
};
const campaigns: PlatformWebModule = {
  id: "campaigns",
  label: "Campaigns",
  version: "test",
  dependencies: ["access"],
  optionalDependencies: ["files", "mail"],
  routes: [{ path: "/campaigns", order: 10, render: () => null }]
};

const cases: Array<{ name: string; modules: PlatformWebModule[]; files: boolean; mail: boolean }> = [
  { name: "core-only", modules: [access], files: false, mail: false },
  { name: "files-only", modules: [access, files], files: true, mail: false },
  { name: "mail-only", modules: [access, mail], files: false, mail: true },
  { name: "campaign-only", modules: [access, campaigns], files: false, mail: false },
  { name: "campaign-files", modules: [access, campaigns, files], files: true, mail: false },
  { name: "campaign-mail", modules: [access, campaigns, mail], files: false, mail: true },
  { name: "full-product", modules: [access, campaigns, files, mail], files: true, mail: true }
];

for (const testCase of cases) {
  const campaignInstalled = moduleInstalled("campaigns", testCase.modules);
  assert(moduleInstalled("access", testCase.modules), `${testCase.name}: access should be installed`);
  assert(moduleInstalled("files", testCase.modules) === testCase.files, `${testCase.name}: files installed state`);
  assert(moduleInstalled("mail", testCase.modules) === testCase.mail, `${testCase.name}: mail installed state`);
  assert(hasUiCapability("files.fileExplorer", testCase.modules) === testCase.files, `${testCase.name}: files UI capability`);
  assert(hasUiCapability("mail.profiles", testCase.modules) === testCase.mail, `${testCase.name}: mail UI capability`);
  assert(moduleIntegrationEnabled("campaigns", "files", testCase.modules) === (campaignInstalled && testCase.files), `${testCase.name}: campaign files integration`);
  assert(moduleIntegrationEnabled("campaigns", "mail", testCase.modules) === (campaignInstalled && testCase.mail), `${testCase.name}: campaign mail integration`);
}

assert(uiCapability("files.fileExplorer", [access, files]) === filesCapability, "files capability should return the module-provided object");
assert(uiCapability("mail.profiles", [access, mail]) === mailCapability, "mail capability should return the module-provided object");

const configurableDashboardWidgets: DashboardWidgetsUiCapability = {
  widgets: [
    {
      id: "files.recent",
      surfaceId: "files.widget.recent",
      title: "Recent files",
      moduleId: "files",
      supportedSizes: ["medium", "wide"],
      defaultConfiguration: { limit: 10, includeFolders: false },
      configurationFields: [
        {
          id: "limit",
          label: "Items",
          kind: "number",
          min: 1,
          max: 50
        },
        {
          id: "includeFolders",
          label: "Include folders",
          kind: "boolean"
        }
      ],
      render: ({ configuration, effectiveView, instanceId }) =>
        `${instanceId}:${effectiveView?.activeViewId ?? "full"}:${String(configuration.limit)}`
    }
  ]
};
const dashboardProvider: PlatformWebModule = {
  id: "dashboard-provider",
  label: "Dashboard provider",
  version: "test",
  uiCapabilities: {
    "dashboard.widgets": configurableDashboardWidgets
  }
};
const resolvedDashboardWidgets = uiCapability<DashboardWidgetsUiCapability>(
  "dashboard.widgets",
  [dashboardProvider]
);
assert(
  resolvedDashboardWidgets?.widgets[0].configurationFields?.length === 2,
  "dashboard widget capabilities should retain provider-defined configuration"
);

const routes = routeContributionsForModules([access, files, mail, campaigns]).map((route) => route.path);
assert(routes.join(",") === "/campaigns,/files,/mail", "routes should aggregate and sort by contribution order");

assert(scopeGrants("tenant:*", "calendar:event:read"), "tenant wildcard should grant tenant-level module scopes");
assert(!scopeGrants("tenant:*", "system:settings:read"), "tenant wildcard should not grant system scopes");

let selectedFunctionId = "";
const functionAction: OrganizationFunctionActionContribution = {
  id: "test.view-assignments",
  label: "View assignments",
  icon: "assignments-icon",
  order: 40,
  anyOf: ["idm:organization_assignment:read"],
  onClick: (context) => {
    selectedFunctionId = context.function.id;
  }
};
functionAction.onClick({
  settings: { apiBaseUrl: "", apiKey: "", accessToken: "" },
  auth: {} as OrganizationFunctionActionContext["auth"],
  function: {
    id: "function-1",
    tenant_id: "tenant-1",
    organization_unit_id: "unit-1",
    slug: "test-function",
    name: "Test function"
  }
});
assert(selectedFunctionId === "function-1", "organization function actions receive their row context");
assert(!("render" in functionAction), "organization function actions expose metadata instead of arbitrary rendered controls");

const viewAwareFiles: PlatformWebModule = {
  ...files,
  navItems: [{ to: "/files", label: "Files", order: 20 }],
  viewSurfaces: [
    {
      id: "files.settings.connectors",
      moduleId: "files",
      kind: "section",
      label: "File connectors"
    }
  ]
};
const viewCatalogue = viewSurfaceCatalogueForModules([viewAwareFiles]);
assert(
  viewCatalogue.some((surface) => surface.id === "files.module"),
  "view catalogue should derive a module root"
);
assert(
  viewCatalogue.some((surface) => surface.id === "files.nav.files"),
  "view catalogue should derive navigation surfaces"
);
assert(
  viewCatalogue.some((surface) => surface.id === "files.route.files"),
  "view catalogue should derive route surfaces"
);

const serverNormalizedCatalogue = viewSurfaceCatalogueForModules([
  {
    ...viewAwareFiles,
    viewSurfaces: [
      {
        id: "files.module",
        moduleId: "files",
        kind: "module",
        label: "Files",
        parentId: null
      },
      ...(viewAwareFiles.viewSurfaces ?? [])
    ]
  }
]);
assert(
  serverNormalizedCatalogue.find((surface) => surface.id === "files.module")
    ?.parentId == null,
  "server-normalized module roots must not become their own parent"
);

const filesView = {
  activeViewId: "view-files",
  activeRevisionId: "revision-files",
  activeViewName: "Files only",
  visibleSurfaceIds: [
    "files.module",
    "files.nav.files",
    "files.route.files"
  ],
  locked: false,
  availableViews: [],
  provenance: [],
  diagnostics: []
};
assert(
  isViewSurfaceVisible(filesView, "files.route.files", viewCatalogue),
  "selected child surfaces should remain visible when their ancestor is selected"
);
assert(
  !isViewSurfaceVisible(filesView, "files.settings.connectors", viewCatalogue),
  "unselected sections should be hidden"
);
assert(
  visibleRoutesForProjection([viewAwareFiles], filesView).length === 1,
  "selected routes should remain in the effective route list"
);

const missingParentView = {
  ...filesView,
  visibleSurfaceIds: ["files.route.files"]
};
assert(
  !isViewSurfaceVisible(
    missingParentView,
    "files.route.files",
    viewCatalogue
  ),
  "a selected child should stay hidden when its module ancestor is not selected"
);
assert(
  isViewSurfaceVisible(filesView, "future.module.action", viewCatalogue),
  "unknown surfaces should fail open for forward compatibility and recovery"
);
