import fs from "fs";
import path from "path";
import {
  normalizeDiscoveryPath,
  shouldExcludeDiscoveryPath,
} from "../discovery/path-policy.mjs";
import { normalizePath } from "./shared.mjs";
import { resolveImportToSourceFile as resolveImportToSourceFileFromAst } from "./next-static-analysis.mjs";

export function findNextAppRoot(serviceRoot) {
  const candidates = [path.join(serviceRoot, "app"), path.join(serviceRoot, "src", "app")];
  return candidates.find((candidate) => fs.existsSync(candidate) && fs.statSync(candidate).isDirectory()) || null;
}

export function resolveServiceRoot(productDir, config) {
  const cwd = config?.local?.cwd || ".";
  return path.resolve(productDir, cwd);
}

export function walkFiles(rootDir, options = {}) {
  if (!fs.existsSync(rootDir)) return [];
  const baseDir = options.baseDir || rootDir;
  const exclude = options.exclude || [];
  const results = [];
  const queue = [rootDir];
  while (queue.length > 0) {
    const current = queue.pop();
    for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
      if (entry.isSymbolicLink()) continue;
      const absolutePath = path.join(current, entry.name);
      if (entry.isDirectory()) {
        const relativeDirPath = normalizeDiscoveryPath(path.relative(baseDir, absolutePath));
        if (shouldExcludeDiscoveryPath(relativeDirPath, exclude)) continue;
        queue.push(absolutePath);
        continue;
      }
      if (entry.isFile()) {
        results.push(absolutePath);
      }
    }
  }
  return results.sort((left, right) => left.localeCompare(right));
}

export function resolveImportToSourceFile(serviceRoot, fromFilePath, specifier) {
  return resolveImportToSourceFileFromAst(serviceRoot, fromFilePath, specifier);
}

export function resolveSourceCandidate(basePath) {
  const direct = [basePath, `${basePath}.ts`, `${basePath}.tsx`, `${basePath}.js`, `${basePath}.mjs`];
  for (const candidate of direct) {
    if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) return candidate;
  }
  const indexed = [
    path.join(basePath, "index.ts"),
    path.join(basePath, "index.tsx"),
    path.join(basePath, "index.js"),
    path.join(basePath, "index.mjs"),
  ];
  for (const candidate of indexed) {
    if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) return candidate;
  }
  return null;
}
