import { GraphvizLayouter, GraphvizWasmAdapter } from "@likec4/layouts";
import {
  DocumentCache,
  EmptyFileSystem,
  inject,
  WorkspaceCache
} from "langium";
import {
  createDefaultModule,
  createDefaultSharedModule
} from "langium/lsp";
import { LikeC4DocumentationProvider } from "./documentation/index.js";
import { LikeC4Formatter } from "./formatting/LikeC4Formatter.js";
import {
  LikeC4GeneratedModule,
  LikeC4GeneratedSharedModule
} from "./generated/module.js";
import { logger, logToLspConnection } from "./logger.js";
import {
  LikeC4CodeLensProvider,
  LikeC4CompletionProvider,
  LikeC4DocumentHighlightProvider,
  LikeC4DocumentLinkProvider,
  LikeC4DocumentSymbolProvider,
  LikeC4HoverProvider,
  LikeC4SemanticTokenProvider
} from "./lsp/index.js";
import {
  DeploymentsIndex,
  FqnIndex,
  LikeC4ModelBuilder,
  LikeC4ModelLocator,
  LikeC4ModelParser
} from "./model/index.js";
import { LikeC4ModelChanges } from "./model-change/ModelChanges.js";
import {
  LikeC4NameProvider,
  LikeC4ScopeComputation,
  LikeC4ScopeProvider
} from "./references/index.js";
import { Rpc } from "./Rpc.js";
import {
  LikeC4WorkspaceManager,
  NodeKindProvider,
  WorkspaceSymbolProvider
} from "./shared/index.js";
import { registerValidationChecks } from "./validation/index.js";
import { LikeC4Views } from "./views/index.js";
const LikeC4SharedModule = {
  lsp: {
    NodeKindProvider: (services) => new NodeKindProvider(services),
    WorkspaceSymbolProvider: (services) => new WorkspaceSymbolProvider(services)
  },
  workspace: {
    WorkspaceManager: (services) => new LikeC4WorkspaceManager(services)
  }
};
function bind(Type) {
  return (services) => new Type(services);
}
export const LikeC4Module = {
  documentation: {
    DocumentationProvider: bind(LikeC4DocumentationProvider)
  },
  WorkspaceCache: (services) => new WorkspaceCache(services.shared),
  DocumentCache: (services) => new DocumentCache(services.shared),
  Rpc: bind(Rpc),
  likec4: {
    Layouter: (_services) => {
      logger.debug("Creating GraphvizLayouter with GraphvizWasmAdapter");
      return new GraphvizLayouter(new GraphvizWasmAdapter());
    },
    Views: bind(LikeC4Views),
    DeploymentsIndex: bind(DeploymentsIndex),
    ModelChanges: bind(LikeC4ModelChanges),
    FqnIndex: bind(FqnIndex),
    ModelParser: bind(LikeC4ModelParser),
    ModelBuilder: bind(LikeC4ModelBuilder),
    ModelLocator: bind(LikeC4ModelLocator)
  },
  lsp: {
    // RenameProvider: bind(LikeC4RenameProvider),
    CompletionProvider: bind(LikeC4CompletionProvider),
    DocumentHighlightProvider: bind(LikeC4DocumentHighlightProvider),
    DocumentSymbolProvider: bind(LikeC4DocumentSymbolProvider),
    SemanticTokenProvider: bind(LikeC4SemanticTokenProvider),
    HoverProvider: bind(LikeC4HoverProvider),
    CodeLensProvider: bind(LikeC4CodeLensProvider),
    DocumentLinkProvider: bind(LikeC4DocumentLinkProvider),
    Formatter: bind(LikeC4Formatter)
  },
  references: {
    NameProvider: bind(LikeC4NameProvider),
    ScopeComputation: bind(LikeC4ScopeComputation),
    ScopeProvider: bind(LikeC4ScopeProvider)
  }
};
export function createCustomLanguageServices(context, module, module2, module3) {
  const shared = createSharedServices(context);
  const modules = [
    createDefaultModule({ shared }),
    LikeC4GeneratedModule,
    LikeC4Module,
    module,
    module2,
    module3
  ].reduce(_merge, {});
  const likec4 = inject(modules);
  shared.ServiceRegistry.register(likec4);
  registerValidationChecks(likec4);
  if (!context.connection) {
    shared.workspace.ConfigurationProvider.initialized({});
  } else {
    likec4.Rpc.init();
  }
  return { shared, likec4 };
}
export function createSharedServices(context = {}) {
  const moduleContext = {
    ...EmptyFileSystem,
    ...context
  };
  if (context.connection) {
    logToLspConnection(context.connection);
  }
  return inject(
    createDefaultSharedModule(moduleContext),
    LikeC4GeneratedSharedModule,
    LikeC4SharedModule
  );
}
export function createLanguageServices(context = {}) {
  const shared = createSharedServices(context);
  const likec4 = inject(
    createDefaultModule({ shared }),
    LikeC4GeneratedModule,
    LikeC4Module
  );
  shared.ServiceRegistry.register(likec4);
  registerValidationChecks(likec4);
  if (!context.connection) {
    shared.workspace.ConfigurationProvider.initialized({});
  } else {
    likec4.Rpc.init();
  }
  return { shared, likec4 };
}
function _merge(target, source) {
  if (source) {
    for (const [key, value2] of Object.entries(source)) {
      if (value2 !== void 0) {
        const value1 = target[key];
        if (value1 !== null && value2 !== null && typeof value1 === "object" && typeof value2 === "object") {
          target[key] = _merge(value1, value2);
        } else {
          target[key] = value2;
        }
      }
    }
  }
  return target;
}
