const fs = require('fs');
const path = require('path');
const { parseEnvFile } = require('./env-parser');

const BASE_DIR = path.resolve(__dirname, '../../');
const SKIP_DIRS = new Set([
  'backups', 'varia', 'wn-golem-starter', 'summercms.io', 'docs', 'projects-browser'
]);

function extractPortFromUrl(url) {
  if (!url) return null;
  try {
    const u = new URL(url);
    const port = parseInt(u.port, 10);
    return port || null;
  } catch {
    return null;
  }
}

function detectFrontend(dirPath) {
  try {
    const entries = fs.readdirSync(dirPath, { withFileTypes: true });
    for (const entry of entries) {
      if (!entry.isDirectory() || !entry.name.startsWith('vue-')) continue;
      const frontendDir = path.join(dirPath, entry.name);
      const pkgPath = path.join(frontendDir, 'package.json');
      if (!fs.existsSync(pkgPath)) continue;

      try {
        const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
        if (!pkg.scripts?.dev) continue;
      } catch { continue; }

      const hasPnpmLock = fs.existsSync(path.join(frontendDir, 'pnpm-lock.yaml'));
      return {
        dir: entry.name,
        fullPath: frontendDir,
        packageManager: hasPnpmLock ? 'pnpm' : 'npm',
      };
    }
  } catch {}
  return null;
}

function scanProjects() {
  const projects = [];
  const entries = fs.readdirSync(BASE_DIR, { withFileTypes: true });

  for (const entry of entries) {
    if (!entry.isDirectory() || SKIP_DIRS.has(entry.name) || entry.name.startsWith('.')) continue;

    const dirPath = path.join(BASE_DIR, entry.name);

    // Check if artisan exists directly
    if (fs.existsSync(path.join(dirPath, 'artisan'))) {
      projects.push(buildProjectMeta(dirPath, entry.name));
      continue;
    }

    // Check one level deeper
    try {
      const subEntries = fs.readdirSync(dirPath, { withFileTypes: true });
      for (const sub of subEntries) {
        if (!sub.isDirectory() || sub.name.startsWith('.')) continue;
        const subPath = path.join(dirPath, sub.name);
        if (fs.existsSync(path.join(subPath, 'artisan'))) {
          projects.push(buildProjectMeta(subPath, entry.name));
        }
      }
    } catch {}
  }

  // Sort by slug for deterministic port assignment
  projects.sort((a, b) => a.slug.localeCompare(b.slug));

  // Assign API ports to projects without one
  let nextPort = 8100;
  const usedPorts = new Set(projects.filter(p => p.port).map(p => p.port));

  for (const project of projects) {
    if (!project.port) {
      while (usedPorts.has(nextPort)) nextPort++;
      project.port = nextPort;
      project.portSource = 'assigned';
      usedPorts.add(nextPort);
      nextPort++;
    }
  }

  // Assign frontend ports deterministically from 3010+
  let nextFrontendPort = 3010;
  for (const project of projects) {
    if (project.frontend) {
      project.frontend.port = nextFrontendPort++;
    }
  }

  return projects;
}

function buildProjectMeta(dirPath, slug) {
  const envPath = path.join(dirPath, '.env');
  const hasEnv = fs.existsSync(envPath);
  const env = hasEnv ? parseEnvFile(envPath) : {};

  const port = extractPortFromUrl(env.APP_URL);

  // Make SQLite path relative if it starts with the project path
  let dbName = env.DB_DATABASE || null;
  if (dbName && dbName.startsWith(dirPath)) {
    dbName = path.relative(dirPath, dbName);
  }

  const frontend = detectFrontend(dirPath);
  const hasDocs = fs.existsSync(path.join(dirPath, 'docs'));

  return {
    slug,
    name: slug,
    path: dirPath,
    port: port,
    portSource: port ? '.env' : null,
    hasEnv,
    dbType: env.DB_CONNECTION || null,
    dbName,
    frontend,
    hasDocs,
  };
}

module.exports = { scanProjects };
