"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var architecture_exports = {};
__export(architecture_exports, {
  ArchitectureAnalyzer: () => ArchitectureAnalyzer
});
module.exports = __toCommonJS(architecture_exports);
var import_manifest = require("./manifest/index");
var import_layers = require("./layers/index");
class ArchitectureAnalyzer {
  constructor(db, config, projectRoot) {
    this.db = db;
    this.config = config;
    this.projectRoot = projectRoot;
  }
  async analyze(onProgress) {
    const log = (msg) => onProgress?.(msg);
    log("architecture: parsing manifests");
    const manifestPackages = await (0, import_manifest.parseAllManifests)(this.projectRoot);
    const allFiles = this.db.getAllFiles().map((f) => f.path);
    log("architecture: assigning files to packages");
    const filePackageMap = /* @__PURE__ */ new Map();
    const sortedPkgs = [...manifestPackages].sort((a, b) => b.path.length - a.path.length);
    for (const file of allFiles) {
      for (const pkg of sortedPkgs) {
        const pkgPath = pkg.path === "." ? "" : pkg.path + "/";
        if (pkg.path === "." || file.startsWith(pkgPath)) {
          filePackageMap.set(file, pkg.id);
          break;
        }
      }
    }
    const SUBDIR_THRESHOLD = 1;
    const directoryPackages = [];
    const rootManifestIds = new Set(manifestPackages.filter((p) => p.path === ".").map((p) => p.id));
    const hasRootManifest = rootManifestIds.size > 0;
    if (manifestPackages.length === 0) {
      const topDirs = /* @__PURE__ */ new Set();
      for (const file of allFiles) {
        const parts = file.split("/");
        if (parts.length > 1) topDirs.add(parts[0]);
      }
      for (const dir of topDirs) {
        const pkgId = `pkg:dir:${dir}`;
        directoryPackages.push({ id: pkgId, name: dir, path: dir, source: "directory", updatedAt: Date.now() });
        for (const file of allFiles) {
          if (file.startsWith(dir + "/")) filePackageMap.set(file, pkgId);
        }
      }
    } else if (hasRootManifest) {
      const rootOwnedFiles = allFiles.filter((f) => rootManifestIds.has(filePackageMap.get(f) ?? ""));
      const subDirCounts = /* @__PURE__ */ new Map();
      for (const file of rootOwnedFiles) {
        const parts = file.split("/");
        if (parts.length > 2) {
          const dir = parts.slice(0, 2).join("/");
          subDirCounts.set(dir, (subDirCounts.get(dir) ?? 0) + 1);
        }
      }
      for (const [dir, count] of subDirCounts) {
        if (count >= SUBDIR_THRESHOLD) {
          const pkgId = `pkg:dir:${dir}`;
          const name = dir.split("/").pop() ?? dir;
          const pkg = { id: pkgId, name, path: dir, source: "directory", updatedAt: Date.now() };
          directoryPackages.push(pkg);
          for (const file of rootOwnedFiles) {
            if (file.startsWith(dir + "/") || file === dir) {
              filePackageMap.set(file, pkgId);
            }
          }
        }
      }
    } else {
      const uncovered = allFiles.filter((f) => !filePackageMap.has(f));
      const subDirCounts = /* @__PURE__ */ new Map();
      for (const file of uncovered) {
        const parts = file.split("/");
        if (parts.length > 1) {
          const dir = parts.slice(0, 2).join("/");
          subDirCounts.set(dir, (subDirCounts.get(dir) ?? 0) + 1);
        }
      }
      for (const [dir, count] of subDirCounts) {
        if (count >= SUBDIR_THRESHOLD) {
          const pkgId = `pkg:dir:${dir}`;
          const name = dir.split("/").pop() ?? dir;
          const pkg = { id: pkgId, name, path: dir, source: "directory", updatedAt: Date.now() };
          directoryPackages.push(pkg);
          for (const file of uncovered) {
            if (file.startsWith(dir + "/") && !filePackageMap.has(file)) {
              filePackageMap.set(file, pkgId);
            }
          }
        }
      }
    }
    const allPackages = [...manifestPackages, ...directoryPackages];
    log("architecture: detecting layers");
    const layerAssignments = [];
    const fileLayerMap = /* @__PURE__ */ new Map();
    if (this.config.architectureLayers !== void 0 || this.config.enableArchitecture) {
      const assignments = await (0, import_layers.detectAllLayers)(allFiles, this.projectRoot, this.config.architectureLayers);
      for (const a of assignments) {
        layerAssignments.push(a);
        fileLayerMap.set(a.filePath, a);
      }
    }
    const allLayers = (0, import_layers.buildArchLayers)(layerAssignments, this.config.architectureLayers);
    log("architecture: rolling up package dependencies");
    const importPairs = this.db.getFileImportPairs();
    const pkgDepCounts = /* @__PURE__ */ new Map();
    for (const { sourceFile, targetFile } of importPairs) {
      const sourcePkg = filePackageMap.get(sourceFile);
      const targetPkg = filePackageMap.get(targetFile);
      if (!sourcePkg || !targetPkg || sourcePkg === targetPkg) continue;
      if (!pkgDepCounts.has(sourcePkg)) pkgDepCounts.set(sourcePkg, /* @__PURE__ */ new Map());
      const inner = pkgDepCounts.get(sourcePkg);
      if (!inner.has(targetPkg)) inner.set(targetPkg, { count: 0, files: [] });
      const entry = inner.get(targetPkg);
      entry.count++;
      if (entry.files.length < 5) entry.files.push({ from: sourceFile, to: targetFile });
    }
    const packageDeps = [];
    for (const [sourcePkg, targets] of pkgDepCounts) {
      for (const [targetPkg, { count, files }] of targets) {
        packageDeps.push({ sourcePkg, targetPkg, depCount: count, files });
      }
    }
    const layerDepCounts = /* @__PURE__ */ new Map();
    for (const dep of packageDeps) {
      const srcFile = [...filePackageMap.entries()].find(([, pkgId]) => pkgId === dep.sourcePkg)?.[0];
      const tgtFile = [...filePackageMap.entries()].find(([, pkgId]) => pkgId === dep.targetPkg)?.[0];
      const srcLayer = srcFile ? fileLayerMap.get(srcFile)?.layerName : void 0;
      const tgtLayer = tgtFile ? fileLayerMap.get(tgtFile)?.layerName : void 0;
      if (!srcLayer || !tgtLayer || srcLayer === tgtLayer) continue;
      const srcLayerId = `layer:${srcLayer}`;
      const tgtLayerId = `layer:${tgtLayer}`;
      if (!layerDepCounts.has(srcLayerId)) layerDepCounts.set(srcLayerId, /* @__PURE__ */ new Map());
      const inner = layerDepCounts.get(srcLayerId);
      inner.set(tgtLayerId, (inner.get(tgtLayerId) ?? 0) + dep.depCount);
    }
    const layerDeps = [];
    for (const [srcLayer, targets] of layerDepCounts) {
      for (const [tgtLayer, count] of targets) {
        layerDeps.push({ sourceLayer: srcLayer, targetLayer: tgtLayer, depCount: count });
      }
    }
    const afferentMap = /* @__PURE__ */ new Map();
    const efferentMap = /* @__PURE__ */ new Map();
    for (const dep of packageDeps) {
      efferentMap.set(dep.sourcePkg, (efferentMap.get(dep.sourcePkg) ?? 0) + 1);
      afferentMap.set(dep.targetPkg, (afferentMap.get(dep.targetPkg) ?? 0) + 1);
    }
    const coupling = allPackages.map((pkg) => {
      const ca = afferentMap.get(pkg.id) ?? 0;
      const ce = efferentMap.get(pkg.id) ?? 0;
      const instability = ca + ce === 0 ? 0 : ce / (ca + ce);
      return { packageId: pkg.id, afferent: ca, efferent: ce, instability, updatedAt: Date.now() };
    });
    log("architecture: persisting to database");
    this.db.clearArchitecture();
    for (const pkg of allPackages) this.db.upsertArchPackage(pkg);
    for (const layer of allLayers) this.db.upsertArchLayer(layer);
    for (const [filePath, pkgId] of filePackageMap) this.db.upsertArchFilePackage(filePath, pkgId);
    for (const a of layerAssignments) {
      this.db.upsertArchFileLayer(a.filePath, `layer:${a.layerName}`, a.confidence, a.matchedPattern);
    }
    for (const dep of packageDeps) {
      this.db.upsertArchPackageDep(dep.sourcePkg, dep.targetPkg, dep.depCount, dep.files);
    }
    for (const dep of layerDeps) {
      this.db.upsertArchLayerDep(dep.sourceLayer, dep.targetLayer, dep.depCount);
    }
    for (const c of coupling) this.db.upsertArchCoupling(c);
    const filePackages = {};
    for (const [filePath, pkgId] of filePackageMap) {
      if (!filePackages[filePath]) filePackages[filePath] = [];
      filePackages[filePath].push(pkgId);
    }
    const fileLayers = {};
    for (const a of layerAssignments) {
      fileLayers[a.filePath] = [{ layerId: `layer:${a.layerName}`, confidence: a.confidence, matchedPattern: a.matchedPattern }];
    }
    return { packages: allPackages, layers: allLayers, packageDeps, layerDeps, coupling, filePackages, fileLayers };
  }
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  ArchitectureAnalyzer
});
//# sourceMappingURL=index.js.map
