import { mkdir, writeFile, readdir, stat, rm } from "node:fs/promises";
import { join, dirname } from "node:path";
import { randomBytes } from "node:crypto";
import { createPackageJson } from "./package-json";
import { packageVersions } from "./package-versions";
import { readTemplate, injectVariables, getTemplatesInDirectory } from "./template-engine";
import { resolveLatestVersions } from "./npm-registry";
import type {
  AuthTarget,
  CachingTarget,
  DbTarget,
  ExtraPackage,
  PackageMap,
  ProjectOptions,
  ProjectPackageJson,
} from "./types";
import console from "node:console";
import { inherits } from "node:util";
import { cwd, env } from "node:process";

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

async function copyDirectoryRecursive(dirPrefix: string, destDir: string, replacements: Record<string, string>) {
  const files = getTemplatesInDirectory(dirPrefix);
  for (const file of files) {
    if (file.endsWith(".stub")) continue;
    let content = await readTemplate(file);
    for (const [key, value] of Object.entries(replacements)) {
      content = content.split(key).join(value);
    }
    const relativeDest = file.slice(dirPrefix.length).replace(/^\//, "");
    const destPath = join(destDir, relativeDest);
    await mkdir(dirname(destPath), { recursive: true });
    await Bun.write(destPath, content);
  }
}

// ---------------------------------------------------------------------------
// Cryptographic secret helpers
// ---------------------------------------------------------------------------

/** Generate a 48-byte (96-char hex) secret suitable for JWT_SECRET. */
function generateJwtSecret(): string {
  return randomBytes(48).toString("hex");
}

/** Generate a 12-byte (24-char hex) password for the Docker PostgreSQL user. */
function generateDbPassword(): string {
  return randomBytes(12).toString("hex");
}

const PROJECT_FOLDERS = [
  "src/controllers",
  "src/services",
  "src/middlewares",
  "src/lib",
  "src/routes",
  "prisma",
];

async function writeJson(path: string, value: unknown) {
  await writeFile(path, `${JSON.stringify(value, null, 2)}\n`);
}

async function resolveViteVersions(packageNames: string[]): Promise<Record<string, string>> {
  const resolved = await resolveLatestVersions(packageNames);

  for (const name of packageNames) {
    if (!resolved[name]) resolved[name] = "latest";
  }

  return resolved;
}

async function writeViteIndexHtml(targetDir: string, framework: "react" | "vue") {
  const title = framework === "react" ? "React + Vite" : "Vue + Vite";
  const html = `<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>${title}</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/${framework === "react" ? "main.tsx" : "main.ts"}"></script>
  </body>
</html>
`;
  await writeFile(join(targetDir, "index.html"), html);
}

/** The local URL exposed by each supported fullstack backend. */
export function resolveFrontendApiUrl(backendFramework?: string): string {
  if (backendFramework === "laravel" || backendFramework === "python") {
    return "http://localhost:8000/";
  }
  if (backendFramework === "rust") {
    return "http://localhost:8080/";
  }
  // Express, Hono, Elysia, and Fiber all listen on port 3000.
  return "http://localhost:3000/";
}

async function writeReactScaffold(targetDir: string) {
  await Promise.all([
    writeViteIndexHtml(targetDir, "react"),
    writeFile(
      join(targetDir, "src", "main.tsx"),
      `import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./index.css";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
);
`,
    ),
    writeFile(
      join(targetDir, "src", "vite-env.d.ts"),
      `/// <reference types="vite/client" />\n`,
    ),
    writeFile(
      join(targetDir, "tsconfig.json"),
      `{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "moduleResolution": "Bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "strict": true,
    "jsx": "react-jsx"
  },
  "include": ["src"]
}
`,
    ),
  ]);
}

async function writeVueScaffold(targetDir: string, includeClerkBootstrap = false) {
  await Promise.all([
    writeViteIndexHtml(targetDir, "vue"),
    writeFile(
      join(targetDir, "src", "main.ts"),
      includeClerkBootstrap
        ? `import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import { setupClerk } from './lib/clerk'

const app = createApp(App)
setupClerk(app)
app.mount('#app')
`
        : `import { createApp } from 'vue'
import './style.css'
import App from './App.vue'

createApp(App).mount('#app')
`,
    ),
    writeFile(
      join(targetDir, "src", "vite-env.d.ts"),
      `/// <reference types="vite/client" />

declare module '*.vue' {
  import type { DefineComponent } from 'vue'
  const component: DefineComponent<{}, {}, any>
  export default component
}
`,
    ),
    writeFile(
      join(targetDir, "tsconfig.json"),
      `{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "moduleResolution": "Bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "strict": true,
    "jsx": "preserve"
  },
  "include": ["src"]
}
`,
    ),
  ]);
}

async function createVitePackageJson(
  projectName: string,
  framework: "react" | "vue",
  authTarget: AuthTarget,
): Promise<ProjectPackageJson> {
  const baseDeps = framework === "react"
    ? [
        "react",
        "react-dom",
        "tailwindcss",
        "@clerk/react",
        "@supabase/supabase-js",
        "zod",
      ]
    : [
        "vue",
        "tailwindcss",
        "@clerk/vue",
        "@supabase/supabase-js",
        "zod",
      ];

  const devDeps = framework === "react"
    ? [
        "vite",
        "typescript",
        "@vitejs/plugin-react",
        "@tailwindcss/vite",
        "@types/react",
        "@types/react-dom",
        "@types/node",
      ]
    : [
        "vite",
        "typescript",
        "@vitejs/plugin-vue",
        "@tailwindcss/vite",
        "@vue/compiler-sfc",
        "@types/node",
      ];

  const versions = await resolveViteVersions([...baseDeps, ...devDeps]);

  const dependencies: PackageMap = {
    ...(framework === "react"
      ? {
          react: versions.react!,
          "react-dom": versions["react-dom"]!,
        }
      : {
          vue: versions.vue!,
        }),
    tailwindcss: versions.tailwindcss!,
  };

  const devDependencies: PackageMap = {
    vite: versions.vite!,
    typescript: versions.typescript!,
    "@tailwindcss/vite": versions["@tailwindcss/vite"]!,
    "@types/node": versions["@types/node"]!,
  };

  if (framework === "react") {
    devDependencies["@vitejs/plugin-react"] = versions["@vitejs/plugin-react"]!;
    devDependencies["@types/react"] = versions["@types/react"]!;
    devDependencies["@types/react-dom"] = versions["@types/react-dom"]!;
  } else {
    devDependencies["@vitejs/plugin-vue"] = versions["@vitejs/plugin-vue"]!;
    devDependencies["@vue/compiler-sfc"] = versions["@vue/compiler-sfc"]!;
  }

  if (authTarget === "clerk") {
    dependencies[framework === "react" ? "@clerk/react" : "@clerk/vue"] =
      versions[framework === "react" ? "@clerk/react" : "@clerk/vue"]!;
  } else if (authTarget === "supabase") {
    dependencies["@supabase/supabase-js"] = versions["@supabase/supabase-js"]!;
    dependencies.zod = versions.zod!;
  }

  return {
    name: projectName,
    version: "1.0.0",
    type: "module",
    scripts: {
      dev: "vite",
      build: "vite build",
      preview: "vite preview",
      typecheck: "tsc --noEmit",
    },
    dependencies,
    devDependencies,
  };
}

// ---------------------------------------------------------------------------
// Template resolvers — pick the right variant and inject variables
// ---------------------------------------------------------------------------

async function resolveEnvFile(
  dbTarget: DbTarget,
  projectName: string,
  jwtSecret: string,
  dbPassword: string,
  authTarget: AuthTarget = "local",
  cachingTarget: CachingTarget = "none",
  dbPort: number = 54320,
  redisPort: number = 63790
): Promise<string> {
  const variantMap: Record<DbTarget, string> = {
    supabase: "express/env.supabase.txt",
    docker: "express/env.docker.txt",
    local: "express/env.local.txt",
    neon: "express/env.neon.txt",
  };

  const raw = await readTemplate(variantMap[dbTarget]);

  let authVars = "";
  if (authTarget === "clerk") {
    authVars = `\n# Clerk Auth\nCLERK_PUBLISHABLE_KEY="YOUR_CLERK_PUBLISHABLE_KEY"\nCLERK_SECRET_KEY="YOUR_CLERK_SECRET_KEY"\n`;
  } else if (authTarget === "supabase") {
    authVars = `\n# Supabase Auth\nSUPABASE_URL="https://your-project.supabase.co"\nSUPABASE_ANON_KEY="your-anon-key"\n`;
  }

  let cachingVars = "";
  if (cachingTarget === "docker") {
    cachingVars = `\n# Redis Caching (Docker)\nREDIS_URL="redis://127.0.0.1:${redisPort}"\n`;
  } else if (cachingTarget === "upstash") {
    cachingVars = `\n# Upstash Redis\nUPSTASH_REDIS_REST_URL="https://your-endpoint.upstash.io"\nUPSTASH_REDIS_REST_TOKEN="your-token"\n`;
  }

  if (dbTarget === "supabase" || dbTarget === "neon") {
    return injectVariables(raw, { JWT_SECRET: jwtSecret }) + authVars + cachingVars;
  }

  const dbName = projectName.replace(/[\\/]/g, "-");

  if (dbTarget === "docker") {
    return injectVariables(raw, {
      PROJECT_NAME: dbName,
      JWT_SECRET: jwtSecret,
      DB_PASSWORD: dbPassword,
      DB_PORT: dbPort.toString()
    }) + authVars + cachingVars;
  }

  // local
  return injectVariables(raw, {
    PROJECT_NAME: dbName,
    JWT_SECRET: jwtSecret,
  }) + authVars + cachingVars;
}

async function resolveDockerCompose(
  projectName: string,
  dbPassword: string,
  dbTarget: string,
  cachingTarget: string,
  dbPort: number = 54320,
  redisPort: number = 63790
): Promise<string> {
  let compose = `services:\n`;
  let volumes = "";
  const containerPrefix = projectName.replace(/[\\/]/g, "-");

  if (dbTarget === "docker") {
    compose += `  qwykz-db:
    image: postgres:17-alpine
    container_name: ${containerPrefix}-postgres
    command: postgres -c synchronous_commit=off -c max_connections=50
    mem_limit: 512m
    mem_reservation: 128m
    cpus: 1.0
    pids_limit: 200
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: ${dbPassword}
      POSTGRES_DB: ${containerPrefix}
    ports:
      - "127.0.0.1:${dbPort}:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres -d ${containerPrefix}"]
      interval: 5s
      timeout: 5s
      retries: 12
      start_period: 5s
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"
    volumes:
      - ${containerPrefix}_data:/var/lib/postgresql/data\n\n`;
    volumes += `  ${containerPrefix}_data:
    labels:
      io.qwykz.managed: "true"
      io.qwykz.kind: "postgres"\n`;
  }

  if (cachingTarget === "docker") {
    compose += `  qwykz-redis:
    image: redis:7-alpine
    container_name: ${containerPrefix}-redis
    command:
      - redis-server
      - --save
      - ""
      - --appendonly
      - "no"
      - --maxmemory
      - 96mb
      - --maxmemory-policy
      - allkeys-lru
    mem_limit: 128m
    mem_reservation: 32m
    cpus: 0.5
    pids_limit: 100
    ports:
      - "127.0.0.1:${redisPort}:6379"
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 5s
      retries: 10
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"\n\n`;
  }

  return volumes ? `${compose}volumes:\n${volumes}` : compose;
}

async function resolvePrismaClient(dbTarget: DbTarget): Promise<string> {
  const variant =
    dbTarget === "supabase"
      ? "express/prisma-client.supabase.ts"
      : "express/prisma-client.default.ts";
  return readTemplate(variant);
}

async function resolveServerSource(
  extraPackages: ExtraPackage[],
  framework: "express" | "hono" | "elysia" = "express",
  authTarget: AuthTarget = "local"
): Promise<string> {
  const hasCors = extraPackages.includes("cors");
  const hasHelmet = extraPackages.includes("helmet");

  let extraImports = "";
  let extraMiddleware = "";

  if (framework === "express") {
    if (hasCors) extraImports += 'import cors from "cors";\n';
    if (hasHelmet) extraImports += 'import helmet from "helmet";\n';
    if (hasHelmet) extraMiddleware += "app.use(helmet());\n";
    if (hasCors) extraMiddleware += "app.use(cors({ origin: 'http://localhost:5173', credentials: true }));\n";
  } else if (framework === "hono") {
    if (hasCors) extraImports += 'import { cors } from "hono/cors";\n';
    if (hasHelmet) extraImports += 'import { secureHeaders } from "hono/secure-headers";\n';
    if (hasHelmet) extraMiddleware += "app.use('*', secureHeaders());\n";
    if (hasCors) extraMiddleware += "app.use('*', cors({ origin: 'http://localhost:5173', credentials: true }));\n";
  } else if (framework === "elysia") {
    if (hasCors) extraImports += 'import { cors } from "@elysiajs/cors";\n';
    if (hasHelmet) extraImports += 'import { helmet } from "elysia-helmet";\n';
    if (hasHelmet) extraMiddleware += "\n  .use(helmet())";
    if (hasCors) extraMiddleware += "\n  .use(cors({ origin: 'http://localhost:5173', credentials: true }))";
  }

  let authImport = 'import { authRouter } from "./routes/auth.routes";\n';
  let authRoute = "";
  if (framework === "express") authRoute = 'app.use("/api/auth", authRouter);\n';
  else if (framework === "hono") authRoute = 'app.route("/api/auth", authRouter);\n';
  else if (framework === "elysia") authRoute = '  .use(authRouter)\n';

  const raw = await readTemplate(`${framework}/server.ts`);
  return injectVariables(raw, {
    EXTRA_IMPORTS: extraImports,
    EXTRA_MIDDLEWARE: extraMiddleware,
    AUTH_IMPORT: authImport,
    AUTH_ROUTE: authRoute,
  });
}

async function resolveUserController(
  extraPackages: ExtraPackage[],
): Promise<string> {
  const variant = extraPackages.includes("zod")
    ? "express/user.controller.zod.ts"
    : "express/user.controller.default.ts";
  return readTemplate(variant);
}

async function resolveUserService(cachingTarget: CachingTarget): Promise<string> {
  let redisImport = "";
  let redisCacheCheck = "";
  let redisCacheSet = "";
  let redisCacheInvalidate = "";

  if (cachingTarget !== "none") {
    redisImport = 'import { redis } from "../lib/redis";\n';
    redisCacheCheck = `    const cached = await redis.get("users:list");\n    if (cached) return typeof cached === "string" ? JSON.parse(cached) : cached;\n`;
    
    if (cachingTarget === "upstash") {
      redisCacheSet = `    await redis.set("users:list", JSON.stringify(users), { ex: 60 });\n`;
    } else {
      redisCacheSet = `    await redis.set("users:list", JSON.stringify(users), "EX", 60);\n`;
    }
    
    redisCacheInvalidate = `    await redis.del("users:list");\n`;
  }

  const raw = await readTemplate("express/user.service.ts");
  return injectVariables(raw, {
    REDIS_IMPORT: redisImport,
    REDIS_CACHE_CHECK: redisCacheCheck,
    REDIS_CACHE_SET: redisCacheSet,
    REDIS_CACHE_INVALIDATE: redisCacheInvalidate,
  });
}

// ---------------------------------------------------------------------------
// Main generator
// ---------------------------------------------------------------------------

export async function generateExpressProject(options: ProjectOptions) {
  const targetDir = join(process.cwd(), options.projectName);

  // Generate cryptographically secure secrets once per scaffold run.
  // These are never printed to the terminal.
  const jwtSecret = generateJwtSecret();
  const dbPassword = generateDbPassword();

  // Create directory structure
  await Promise.all(
    PROJECT_FOLDERS.map((folder) =>
      mkdir(join(targetDir, folder), { recursive: true }),
    ),
  );

  // Resolve all template contents in parallel
  const [
    prismaSchema,
    prismaConfig,
    tsconfig,
    envFile,
    prismaClient,
    serverSource,
    errorMiddleware,
    healthRoutes,
    userRoutes,
    userController,
    userService,
    authController,
    authMiddleware,
    authRoutes,
    waitForPostgres,
    dockerCompose,
    exampleTest,
  ] = await Promise.all([
    readTemplate("express/schema.prisma"),
    readTemplate("express/prisma.config.ts"),
    readTemplate("express/tsconfig.json"),
    resolveEnvFile(
      options.dbTarget,
      options.projectName,
      jwtSecret,
      dbPassword,
      options.authTarget,
      options.cachingTarget,
      options.dbPort,
      options.redisPort
    ),
    resolvePrismaClient(options.dbTarget),
    resolveServerSource(options.extraPackages, "express", options.authTarget),
    readTemplate("express/error.middleware.ts"),
    readTemplate("express/health.routes.ts"),
    readTemplate("express/user.routes.ts"),
    resolveUserController(options.extraPackages),
    resolveUserService(options.cachingTarget),
    readTemplate(`express/auth.controller${options.authTarget === 'local' ? '' : '.' + options.authTarget}.ts`),
    readTemplate(`express/auth.middleware${options.authTarget === 'local' ? '' : '.' + options.authTarget}.ts`),
    readTemplate("express/auth.routes.ts"),
    options.dbTarget === "docker" ? readTemplate("express/wait-for-postgres.ts") : Promise.resolve(null),
    options.dbTarget === "docker" || options.cachingTarget === "docker"
      ? resolveDockerCompose(options.projectName, dbPassword, options.dbTarget, options.cachingTarget, options.dbPort, options.redisPort)
      : Promise.resolve(null),
    readTemplate("express/example.test.ts"),
  ]);

  // Assemble file list
  const files: Array<[string, string]> = [
    ["prisma/schema.prisma", prismaSchema],
    ["prisma.config.ts", prismaConfig],
    ["tsconfig.json", tsconfig],
    [".env", envFile],
    ["src/lib/prisma.ts", prismaClient],
    ["src/index.ts", serverSource],
    ["src/index.test.ts", exampleTest],
    ["src/middlewares/error.middleware.ts", errorMiddleware],
    ["src/middlewares/auth.middleware.ts", authMiddleware],
    ["src/routes/health.routes.ts", healthRoutes],
    ["src/routes/user.routes.ts", userRoutes],
    ["src/routes/auth.routes.ts", authRoutes!],
    ["src/controllers/user.controller.ts", userController!],
    ["src/controllers/auth.controller.ts", authController!],
    ["src/services/user.service.ts", userService!],
  ];

  if (options.dbTarget === "docker" && waitForPostgres) {
    files.splice(5, 0, ["src/lib/wait-for-postgres.ts", waitForPostgres!]);
  }

  if (options.dbTarget === "docker" || options.cachingTarget === "docker") {
    files.push(["docker-compose.yml", dockerCompose!]);
  }

  if (options.cachingTarget === "docker") {
    files.push(["src/lib/redis.ts", await readTemplate("express/redis.docker.ts")]);
  } else if (options.cachingTarget === "upstash") {
    files.push(["src/lib/redis.ts", await readTemplate("express/redis.upstash.ts")]);
  }

  // Write all files + package.json in parallel
  await Promise.all([
    ...files.map(([path, content]) =>
      writeFile(join(targetDir, path), content),
    ),
    createPackageJson(
      options.projectName,
      options.dbTarget,
      options.extraPackages,
      options.cachingTarget,
      options.authTarget,
    ).then((pkgJson) => writeJson(join(targetDir, "package.json"), pkgJson)),
  ]);
}

async function generateLaravelProject(options: ProjectOptions) {
  const targetDir = join(process.cwd(), options.projectName);
  const dbPassword = generateDbPassword();

  console.log(`\n🚀Fetching the latest Laravel framework via Composer`);
  await rm(targetDir, { recursive: true, force: true }).catch(() => {});

  const proc = Bun.spawn({
    cmd: [
      "composer",
      "create-project",
      "laravel/laravel",
      options.projectName,
      "--no-scripts",
    ],
    cwd: process.cwd(),
    stdout: "pipe",
    stderr: "pipe",
    env: { ...process.env },
  });

  const exitCode = await proc.exited;
  if (exitCode !== 0) {
    const errText = await new Response(proc.stderr).text();
    throw new Error(
      `Composer failed to install Laravel. Error: ${errText}`
    );
  }

  if (options.cachingTarget === "upstash" || options.cachingTarget === "docker") {
    console.log(`\n📦 Installing predis for Redis caching...`);
    const procRedis = Bun.spawn({
      cmd: ["composer", "require", "predis/predis"],
      cwd: targetDir,
      stdout: "ignore",
      stderr: "ignore",
      env: { ...process.env },
    });
    await procRedis.exited;
  }

  console.log(`◑  Scaffolding qwykz architecture..✅ Laravel installation complete!\n`);

  console.log(`\n🏗️  Installing API Routes & Sanctum...`);
  const apiProc = Bun.spawn(
    ["php", "artisan", "install:api", "--without-migration-prompt"],
    {
      cwd: targetDir,
      stdout: "ignore",
      stderr: "ignore",
      env: { ...process.env },
    },
  );
  await apiProc.exited;

  const apiRoutePath = join(targetDir, "routes/api.php");
  const stub = await readTemplate("laravel/routes/api.stub");
  const existing = await Bun.file(apiRoutePath).text();
  await Bun.write(apiRoutePath, existing + "\n" + stub);

  console.log(`\n🔑 Enabling API Tokens on User Model...`);
  const userModelPath = join(targetDir, "app/Models/User.php");
  let userModelContent = await Bun.file(userModelPath).text();
  userModelContent = userModelContent.replace(
    "use HasFactory, Notifiable;",
    "use \\Laravel\\Sanctum\\HasApiTokens, HasFactory, Notifiable;",
  );
  await Bun.write(userModelPath, userModelContent);

  console.log(`\n💉 Injecting PostgreSQL configuration.
  ..`);

  const envExamplePath = join(targetDir, ".env.example");
  const envPath = join(targetDir, ".env");

  let envContent = await Bun.file(envExamplePath).text();

  envContent = envContent.replace(
    "DB_CONNECTION=sqlite",
    "DB_CONNECTION=pgsql",
  );
  
  envContent += "\n# CORS / Frontend\nFRONTEND_URL=http://localhost:5173\nSANCTUM_STATEFUL_DOMAINS=localhost:5173,localhost:3000\n";

  if (options.dbTarget === "supabase") {
    const parsed = new URL(
      options.supabaseDbUrl ||
        "postgresql://postgres:postgres@aws-0-eu-central-1.pooler.supabase.com:5432/postgres",
    );
    envContent = envContent.replace(
      "# DB_HOST=127.0.0.1",
      `DB_HOST=${parsed.hostname}`,
    );
    envContent = envContent.replace(
      "# DB_PORT=3306",
      `DB_PORT=${parsed.port || "5432"}`,
    );
    envContent = envContent.replace(
      "# DB_DATABASE=laravel",
      `DB_DATABASE=postgres`,
    );
    envContent = envContent.replace(
      "# DB_USERNAME=root",
      `DB_USERNAME=${parsed.username}`,
    );
    envContent = envContent.replace(
      "# DB_PASSWORD=",
      `DB_PASSWORD=${parsed.password}`,
    );
  } else {
    envContent = envContent.replace("# DB_HOST=127.0.0.1", "DB_HOST=127.0.0.1");
    envContent = envContent.replace(
      "# DB_PORT=3306",
      `DB_PORT=${options.dbTarget === "docker" ? options.dbPort : "5432"}`,
    );
    const dbName = options.projectName.replace(/[\\/]/g, "-");
    envContent = envContent.replace(
      "# DB_DATABASE=laravel",
      `DB_DATABASE=${dbName}`,
    );
    envContent = envContent.replace(
      "# DB_USERNAME=root",
      "DB_USERNAME=postgres",
    );
    envContent = envContent.replace(
      "# DB_PASSWORD=",
      `DB_PASSWORD=${options.dbTarget === "docker" ? dbPassword : "postgres"}`,
    );
  }

  if (options.cachingTarget === "upstash") {
    envContent = envContent.replace("CACHE_STORE=database", "CACHE_STORE=redis");
    envContent = envContent.replace("SESSION_DRIVER=database", "SESSION_DRIVER=redis");
    envContent += "\n# Upstash Redis\nREDIS_CLIENT=predis\nREDIS_HOST=your-upstash-endpoint\nREDIS_PASSWORD=your-upstash-password\nREDIS_PORT=6379\n";
  } else if (options.cachingTarget === "docker") {
    envContent = envContent.replace("CACHE_STORE=database", "CACHE_STORE=redis");
    envContent = envContent.replace("SESSION_DRIVER=database", "SESSION_DRIVER=redis");
    envContent += "\nREDIS_CLIENT=predis";
    envContent = envContent.replace("REDIS_HOST=127.0.0.1", "REDIS_HOST=127.0.0.1");
    envContent = envContent.replace("REDIS_PORT=6379", `REDIS_PORT=${options.redisPort}`);
  }

  await writeFile(envPath, envContent);

  if (options.dbTarget === "docker" || options.cachingTarget === "docker") {
    console.log(`\n🐳 Generating docker-compose.yml...
  `);

    const dockerCompose = await resolveDockerCompose(
      options.projectName,
      dbPassword,
      options.dbTarget,
      options.cachingTarget,
      options.dbPort,
      options.redisPort
    );

    await writeFile(join(targetDir, "docker-compose.yml"), dockerCompose);
  } else if (options.dbTarget === "local") {
  } else if (options.dbTarget === "supabase") {
  }

  // Create advanced Service structure
  console.log(`\n🏗️  Scaffolding Pro Architecture (Services & Controllers)...`);

  await mkdir(join(targetDir, "app/Services"), { recursive: true });
  await mkdir(join(targetDir, "app/Http/Controllers/Api"), { recursive: true });

  const [authService, userService, authController, userController] =
    await Promise.all([
      readTemplate("laravel/app/Services/AuthService.php"),
      readTemplate("laravel/app/Services/UserService.php"),
      readTemplate("laravel/app/Http/Controllers/Api/AuthController.php"),
      readTemplate("laravel/app/Http/Controllers/Api/UserController.php"),
    ]);

  await Promise.all([
    writeFile(join(targetDir, "app/Services/AuthService.php"), authService),
    writeFile(join(targetDir, "app/Services/UserService.php"), userService),
    writeFile(
      join(targetDir, "app/Http/Controllers/Api/AuthController.php"),
      authController,
    ),
    writeFile(
      join(targetDir, "app/Http/Controllers/Api/UserController.php"),
      userController,
    ),
  ]);

  const pkgPath = join(targetDir, "package.json");
  if (await Bun.file(pkgPath).exists()) {
    const pkg = await Bun.file(pkgPath).json();
    pkg.name = options.projectName.split("/").pop() || "backend";
    await Bun.write(pkgPath, JSON.stringify(pkg, null, 2));
  }
}

async function generateNextJsProject(options: ProjectOptions) {
  const targetDir = join(process.cwd(), options.projectName);
  const dbPassword = generateDbPassword();

  console.log(`\n🚀 Scaffolding Next.js App Router...`);

  await mkdir(join(targetDir, "app"), { recursive: true });

  const nextDependencies: PackageMap = {
    "@prisma/adapter-pg": packageVersions.dependencies["@prisma/adapter-pg"],
    "@prisma/client": packageVersions.dependencies["@prisma/client"],
    next: "^16.2.10",
    pg: packageVersions.dependencies.pg,
    react: "^19.2.7",
    "react-dom": "^19.2.7",
  };
  const nextDevDependencies: PackageMap = {
    "@prisma/config": packageVersions.devDependencies["@prisma/config"],
    "@types/node": packageVersions.devDependencies["@types/node"],
    "@types/pg": packageVersions.devDependencies["@types/pg"],
    "@types/react": "^19.2.17",
    "@types/react-dom": "^19.2.3",
    eslint: "^9.0.0",
    "eslint-config-next": "^16.2.10",
    prisma: packageVersions.devDependencies.prisma,
    typescript: packageVersions.devDependencies.typescript,
  };
  if (options.authTarget === "local") {
    nextDependencies.zod = "^3.23.0";
    nextDependencies.bcryptjs = "^2.4.3";
    nextDependencies.jsonwebtoken = packageVersions.dependencies.jsonwebtoken;
    nextDevDependencies["@types/jsonwebtoken"] = packageVersions.devDependencies["@types/jsonwebtoken"];
    nextDevDependencies["@types/bcryptjs"] = "^2.4.6";
  } else if (options.authTarget === "supabase") {
    nextDependencies.zod = "^3.23.0";
    nextDependencies["@supabase/supabase-js"] = "^2.43.0";
  } else if (options.authTarget === "clerk") {
    nextDependencies["@clerk/nextjs"] = "^7.0.0";
  }

  if (options.cachingTarget === "docker") {
    nextDependencies.ioredis = "^5.4.1";
  } else if (options.cachingTarget === "upstash") {
    nextDependencies["@upstash/redis"] = "^1.31.5";
  }

  const pkgJson = {
    name: options.projectName.split("/").pop() || "nextjs-app",
    version: "0.1.0",
    private: true,
    scripts: {
      dev: "next dev",
      build: "next build",
      start: "next start",
      test: "bun test",
      postinstall: "prisma generate",
      "db:generate": "bunx --bun prisma generate",
      "db:push": "bunx --bun prisma db push",
      "db:studio": "bunx --bun prisma studio",
    },
    dependencies: nextDependencies,
    devDependencies: nextDevDependencies,
  };

  console.log(
    `\n🔒 Configuring Security Headers (Helmet & CORS) & Database...`,
  );

  const envPath = join(targetDir, ".env");
  let envContent = "";
  if (options.dbTarget === "supabase") {
    const parsed = new URL(options.supabaseDbUrl || "postgresql://postgres:postgres@aws-0-eu-central-1.pooler.supabase.com:5432/postgres");
    envContent = `DATABASE_URL="${options.supabaseDbUrl}"\nDIRECT_URL="postgresql://${parsed.username}:${parsed.password}@${parsed.hostname}:5432/postgres"\nJWT_SECRET="${generateJwtSecret()}"\n`;
  } else {
    const port = options.dbTarget === "docker" ? (options.dbPort ?? 54320).toString() : "5432";
    const pass = options.dbTarget === "docker" ? dbPassword : "postgres";
    const dbName = options.projectName.replace(/[\\/]/g, "-");
    envContent = `DATABASE_URL="postgresql://postgres:${pass}@localhost:${port}/${dbName}?schema=public"\nJWT_SECRET="${generateJwtSecret()}"\n`;
  }
  if (options.authTarget === "clerk") {
    envContent += `\n# Clerk Auth\nNEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="YOUR_CLERK_PUBLISHABLE_KEY"\nCLERK_SECRET_KEY="YOUR_CLERK_SECRET_KEY"\n`;
  } else if (options.authTarget === "supabase") {
    envContent += `\n# Supabase Auth\nNEXT_PUBLIC_SUPABASE_URL="https://your-project.supabase.co"\nNEXT_PUBLIC_SUPABASE_ANON_KEY="your-anon-key"\n`;
  }
  await Bun.write(envPath, envContent);

  const prismaClientStub = options.dbTarget === "supabase" 
    ? await readTemplate("express/prisma-client.supabase.ts") 
    : await readTemplate("express/prisma-client.default.ts");

  const files: Array<[string, string | undefined]> = [
    ["package.json", JSON.stringify(pkgJson, null, 2)],
    ["next-env.d.ts", "/// <reference types=\"next\" />\n/// <reference types=\"next/image-types/global\" />\n\n// This file is generated by Next.js. Do not edit it directly.\n"],
    ["next.config.mjs", await readTemplate("nextjs/next.config.mjs")],
    ["tsconfig.json", JSON.stringify({
      compilerOptions: {
        target: "ES2017",
        lib: ["dom", "dom.iterable", "esnext"],
        allowJs: true,
        skipLibCheck: true,
        strict: true,
        noEmit: true,
        esModuleInterop: true,
        module: "esnext",
        moduleResolution: "bundler",
        resolveJsonModule: true,
        isolatedModules: true,
        jsx: "react-jsx",
        incremental: true,
        plugins: [{ name: "next" }],
        paths: { "@/*": ["./*"] },
      },
      include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ".next/dev/types/**/*.ts"],
      exclude: ["node_modules"],
    }, null, 2)],
    ["app/layout.tsx", "import type { ReactNode } from \"react\";\nimport \"./globals.css\";\n\nexport const metadata = {\n  title: \"Qwykz Next App\",\n  description: \"Generated by qwykz\",\n};\n\nexport default function RootLayout({ children }: Readonly<{ children: ReactNode }>) {\n  return (\n    <html lang=\"en\">\n      <body>{children}</body>\n    </html>\n  );\n}\n"],
    ["app/globals.css", ":root {\n  color-scheme: light;\n}\n\n* {\n  box-sizing: border-box;\n}\n\nbody {\n  margin: 0;\n  background: #f8fafc;\n  color: #111827;\n  font-family: Arial, Helvetica, sans-serif;\n}\n\nbutton,\ninput {\n  font: inherit;\n}\n"],
    ["prisma/schema.prisma", await readTemplate("express/schema.prisma")],
    ["prisma.config.ts", await readTemplate("express/prisma.config.ts")],
    ["lib/prisma.ts", prismaClientStub],
    ["app/api/health/route.ts", await readTemplate("nextjs/health.route.ts")],
    ["__tests__/example.test.ts", await readTemplate("nextjs/example.test.ts.stub")],
  ];

  if (options.authTarget === "local") {
    files.push(["app/api/auth/register/route.ts", await readTemplate("nextjs/auth.route.ts")]);
    files.push(["app/api/auth/login/route.ts", await readTemplate("nextjs/login.route.ts")]);
  }

  if (options.authTarget === "clerk") {
    files.push(["middleware.ts", await readTemplate("nextjs/clerk-middleware.ts.stub")]);
    files.push(["app/page.tsx", await readTemplate("nextjs/page.clerk.tsx.stub")]);
  } else if (options.authTarget === "supabase") {
    files.push(["app/page.tsx", await readTemplate("nextjs/page.supabase.tsx.stub")]);
    const supabaseClient = await readTemplate("react/supabase.ts.stub");
    files.push(["lib/supabase.ts", supabaseClient.replace(/import\.meta\.env\.VITE/g, "process.env.NEXT_PUBLIC")]);
    files.push(["lib/AuthContext.tsx", await readTemplate("react/AuthContext.tsx.stub")]);
  } else {
    files.push(["app/page.tsx", await readTemplate("nextjs/page.local.tsx.stub")]);
  }

  if (options.dbTarget === "docker" || options.cachingTarget === "docker") {
    files.push(["docker-compose.yml", await resolveDockerCompose(options.projectName, dbPassword, options.dbTarget, options.cachingTarget, options.dbPort, options.redisPort)]);
  }

  if (options.cachingTarget === "docker") {
    files.push(["lib/redis.ts", await readTemplate("express/redis.docker.ts")]);
  } else if (options.cachingTarget === "upstash") {
    files.push(["lib/redis.ts", await readTemplate("express/redis.upstash.ts")]);
  }

  await Promise.all(
    files.map(async ([path, content]) => {
      const fullPath = join(targetDir, path);
      await mkdir(dirname(fullPath), { recursive: true });
      await Bun.write(fullPath, content || "");
    })
  );

  if (options.authTarget === "clerk") {
    const layoutPath = join(targetDir, "app", "layout.tsx");
    let layoutContent = await Bun.file(layoutPath).text();
    layoutContent = layoutContent.replace(
      "import \"./globals.css\";",
      "import \"./globals.css\";\nimport { ClerkProvider } from \"@clerk/nextjs\";"
    );
    layoutContent = layoutContent.replace(
      "<body>{children}</body>",
      "<body><ClerkProvider>{children}</ClerkProvider></body>"
    );
    await Bun.write(layoutPath, layoutContent);
  }

}

function stripBackendStatus(content: string): string {
  const stripped = content
    .replace(/import\s*\{\s*useState,\s*useEffect\s*\}\s*from\s*["']react["'];?/g, 'import { useState } from "react";')
    .replace(/\s*const \[backendStatus[^\n]*/g, "")
    .replace(/\s*const \{ getToken \} = useAuth\(\);?/g, "")
    .replace(/\s*const backendStatus = ref.*?;/g, "")
    .replace(/\s*const \[users, setUsers\] = useState<any\[\]>\(\[\]\);/g, "")
    .replace(/\s*const testBackend = async \(\) => \{[\s\S]*?\}\s*\};\s*/g, "")
    .replace(/\s*const testBackend = async \(\) => \{[\s\S]*?catch \(e\) \{[\s\S]*?\}\s*\};/g, "")
    .replace(/\s*useEffect\(\(\) => \{[\s\S]*?testBackend\(\)[\s\S]*?\}, \[.*?\]\);?/g, "")
    .replace(/\s*onMounted\(async \(\) => \{[\s\S]*?catch \(err\) \{[\s\S]*?\}\s*\}\)/g, "")
    .replace(/\s*<div className="mt-8 p-4 bg-gray-50 rounded-md border border-gray-200 w-full max-w-md[^>]*">[\s\S]*?Backend Connection Status[\s\S]*?<\/div>/g, "")
    .replace(/\s*<div class="mt-8 p-4 bg-gray-50 rounded-md border border-gray-200 w-full max-w-md[^>]*">[\s\S]*?Backend Connection Status[\s\S]*?<\/div>/g, "")
    .replace(/\s*<div className="bg-white p-6 rounded-2xl shadow-sm border border-gray-100">\s*<h2[^>]*>Backend Connection Status[\s\S]*?<\/p>\s*<\/div>\s*<\/div>\s*<\/div>/g, "")
    .replace(/\s*<div class="bg-white p-6 rounded-2xl shadow-sm border border-gray-100">\s*<h2[^>]*>Backend Connection Status[\s\S]*?<\/p>\s*<\/div>\s*<\/div>\s*<\/div>/g, "")
    .replace(/\s*\{users\.length > 0 && \([\s\S]*?<\/div>\s*\)\}/g, "")
    .replace(/\s*<div v-if="users\.length > 0"[\s\S]*?Users API Response[\s\S]*?<\/div>/g, "");

  return stripped.replace(
    /,\s*useAuth(?=\s*\}\s*from\s*["']@clerk\/react["'];?)/g,
    "",
  );
}

async function generateReactProject(options: ProjectOptions) {
  console.log(`\n🚀 Scaffolding React + Vite...`);
  const targetDir = join(process.cwd(), options.projectName);
  await mkdir(join(targetDir, "src", "lib"), { recursive: true });

  const viteConfig = await readTemplate("react/vite.config.ts.stub");
  const indexCss = await readTemplate("react/index.css.stub");

  if (options.authTarget === "clerk") {
    let clerkProvider = await readTemplate("react/clerk-provider.tsx.stub");
    if (!options.backendFramework) clerkProvider = stripBackendStatus(clerkProvider);
    await Bun.write(join(targetDir, "src", "App.tsx"), clerkProvider);
  } else if (options.authTarget === "supabase") {
    const supabaseTs = await readTemplate("react/supabase.ts.stub");
    const authContextTsx = await readTemplate("react/AuthContext.tsx.stub");
    let appTsx = await readTemplate("react/App.tsx.stub");
    if (!options.backendFramework) appTsx = stripBackendStatus(appTsx);
    await Bun.write(join(targetDir, "src", "lib", "supabase.ts"), supabaseTs);
    await Bun.write(join(targetDir, "src", "lib", "AuthContext.tsx"), authContextTsx);
    await Bun.write(join(targetDir, "src", "App.tsx"), appTsx);
  } else {
    // Local Auth App.tsx
    let localAppTsx = await readTemplate("react/App.local.tsx.stub");
    if (!options.backendFramework) localAppTsx = stripBackendStatus(localAppTsx);
    await Bun.write(join(targetDir, "src", "App.tsx"), localAppTsx);
  }

  await Bun.write(join(targetDir, "vite.config.ts"), viteConfig);
  await Bun.write(join(targetDir, "src", "index.css"), indexCss);
  await writeReactScaffold(targetDir);

  const pkgJson = await createVitePackageJson(options.projectName, "react", options.authTarget);
  await writeJson(join(targetDir, "package.json"), pkgJson);

  const apiUrl = resolveFrontendApiUrl(options.backendFramework);

  if (options.authTarget === "clerk") {
    const envContent = `VITE_API_URL="${apiUrl}"\nVITE_CLERK_PUBLISHABLE_KEY="YOUR_CLERK_PUBLISHABLE_KEY"\n`;
    await Bun.write(join(targetDir, ".env"), envContent);
    await Bun.write(join(targetDir, ".env.example"), envContent);
  } else if (options.authTarget === "supabase") {
    const envContent = `VITE_API_URL="${apiUrl}"\nVITE_SUPABASE_URL="https://YOUR_PROJECT_REF.supabase.co"\nVITE_SUPABASE_ANON_KEY="YOUR_ANON_KEY"\n`;
    await Bun.write(join(targetDir, ".env"), envContent);
    await Bun.write(join(targetDir, ".env.example"), envContent);
  } else {
    await Bun.write(join(targetDir, ".env"), `VITE_API_URL="${apiUrl}"\n`);
  }
}

async function generateVueProject(options: ProjectOptions) {
  console.log(`\n🚀 Scaffolding Vue + Vite...`);
  const targetDir = join(process.cwd(), options.projectName);
  await mkdir(join(targetDir, "src", "lib"), { recursive: true });

  const viteConfig = await readTemplate("vue/vite.config.ts.stub");
  const styleCss = await readTemplate("vue/style.css.stub");

  if (options.authTarget === "clerk") {
    const clerkPlugin = await readTemplate("vue/clerk-plugin.ts.stub");
    let appVue = await readTemplate("vue/App.clerk.vue.stub");
    if (!options.backendFramework) appVue = stripBackendStatus(appVue);
    await Bun.write(join(targetDir, "src", "lib", "clerk.ts"), clerkPlugin);
    await Bun.write(join(targetDir, "src", "App.vue"), appVue);
    await Bun.write(join(targetDir, "src", "main.ts"), `import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import { setupClerk } from './lib/clerk'

const app = createApp(App)
setupClerk(app)
app.mount('#app')`);
  } else if (options.authTarget === "supabase") {
    const supabaseTs = await readTemplate("vue/supabase.ts.stub");
    const authTs = await readTemplate("vue/auth.ts.stub");
    let appVue = await readTemplate("vue/App.vue.stub");
    if (!options.backendFramework) appVue = stripBackendStatus(appVue);
    await Bun.write(join(targetDir, "src", "lib", "supabase.ts"), supabaseTs);
    await Bun.write(join(targetDir, "src", "lib", "auth.ts"), authTs);
    await Bun.write(join(targetDir, "src", "App.vue"), appVue);
  } else {
    let localAppVue = await readTemplate("vue/App.local.vue.stub");
    if (!options.backendFramework) localAppVue = stripBackendStatus(localAppVue);
    await Bun.write(join(targetDir, "src", "App.vue"), localAppVue);
  }

  await Bun.write(join(targetDir, "vite.config.ts"), viteConfig);
  await Bun.write(join(targetDir, "src", "style.css"), styleCss);
  await writeVueScaffold(targetDir, options.authTarget === "clerk");

  const pkgJson = await createVitePackageJson(options.projectName, "vue", options.authTarget);
  await writeJson(join(targetDir, "package.json"), pkgJson);

  const apiUrl = resolveFrontendApiUrl(options.backendFramework);

  if (options.authTarget === "clerk") {
    const envContent = `VITE_API_URL="${apiUrl}"\nVITE_CLERK_PUBLISHABLE_KEY="YOUR_CLERK_PUBLISHABLE_KEY"\n`;
    await Bun.write(join(targetDir, ".env"), envContent);
    await Bun.write(join(targetDir, ".env.example"), envContent);
  } else if (options.authTarget === "supabase") {
    const envContent = `VITE_API_URL="${apiUrl}"\nVITE_SUPABASE_URL="https://YOUR_PROJECT_REF.supabase.co"\nVITE_SUPABASE_ANON_KEY="YOUR_ANON_KEY"\n`;
    await Bun.write(join(targetDir, ".env"), envContent);
    await Bun.write(join(targetDir, ".env.example"), envContent);
  } else {
    await Bun.write(join(targetDir, ".env"), `VITE_API_URL="${apiUrl}"\n`);
  }
}

async function generatePythonProject(options: ProjectOptions) {
  const targetDir = join(process.cwd(), options.projectName);
  console.log(`\n🚀 Scaffolding Python (FastAPI)...`);
  
  await copyDirectoryRecursive(
    "python",
    targetDir,
    { "qwykz-app": options.projectName }
  );
  
  const jwtSecret = generateJwtSecret();
  const dbPassword = generateDbPassword();
  let envContent = await resolveEnvFile(options.dbTarget, options.projectName, jwtSecret, dbPassword, options.authTarget, options.cachingTarget, options.dbPort, options.redisPort);
  envContent = envContent.replace('?schema=public', '');
  
  if (options.cachingTarget !== "none") {
    const redisStub = await readTemplate("python/redis.py.stub");
    await Bun.write(join(targetDir, "app/core/redis.py"), redisStub);
    const reqPath = join(targetDir, "requirements.txt");
    const reqText = await Bun.file(reqPath).text();
    await Bun.write(reqPath, reqText + "redis>=5.0.1\n");
  }

  if (options.dbTarget === "docker" || options.cachingTarget === "docker") {
    const dc = await resolveDockerCompose(options.projectName, dbPassword, options.dbTarget, options.cachingTarget, options.dbPort, options.redisPort);
    await Bun.write(join(targetDir, "docker-compose.yml"), dc);
  }

  await Bun.write(join(targetDir, ".env"), envContent);
}

async function generateGoProject(options: ProjectOptions) {
  const targetDir = join(process.cwd(), options.projectName);
  console.log(`\n🚀 Scaffolding Go (Fiber)...`);
  
  await copyDirectoryRecursive(
    "go",
    targetDir,
    { "qwykz-app": options.projectName }
  );

  const jwtSecret = generateJwtSecret();
  const dbPassword = generateDbPassword();
  let envContent = await resolveEnvFile(options.dbTarget, options.projectName, jwtSecret, dbPassword, options.authTarget, options.cachingTarget, options.dbPort, options.redisPort);
  envContent = envContent.replace('?schema=public', '');

  if (options.cachingTarget !== "none") {
    const redisStub = await readTemplate("go/redis.go.stub");
    await Bun.spawn(["mkdir", "-p", join(targetDir, "internal/cache")]).exited;
    await Bun.write(join(targetDir, "internal/cache/redis.go"), redisStub);
    const modPath = join(targetDir, "go.mod");
    const modText = await Bun.file(modPath).text();
    await Bun.write(modPath, modText + "\nrequire github.com/redis/go-redis/v9 v9.5.1\n");
  }

  if (options.dbTarget === "docker" || options.cachingTarget === "docker") {
    const dc = await resolveDockerCompose(options.projectName, dbPassword, options.dbTarget, options.cachingTarget, options.dbPort, options.redisPort);
    await Bun.write(join(targetDir, "docker-compose.yml"), dc);
  }

  await Bun.write(join(targetDir, ".env"), envContent);
}

async function generateRustProject(options: ProjectOptions) {
  const targetDir = join(process.cwd(), options.projectName);
  console.log(`\n🚀 Scaffolding Rust (Axum)...`);
  
  await copyDirectoryRecursive(
    "rust",
    targetDir,
    { "qwykz-app": options.projectName }
  );

  const jwtSecret = generateJwtSecret();
  const dbPassword = generateDbPassword();
  let envContent = await resolveEnvFile(options.dbTarget, options.projectName, jwtSecret, dbPassword, options.authTarget, options.cachingTarget, options.dbPort, options.redisPort);

  if (options.cachingTarget !== "none") {
    const redisStub = await readTemplate("rust/redis.rs.stub");
    await Bun.spawn(["mkdir", "-p", join(targetDir, "src/cache")]).exited;
    await Bun.write(join(targetDir, "src/cache/mod.rs"), "pub mod redis;\n");
    await Bun.write(join(targetDir, "src/cache/redis.rs"), redisStub);
    const cargoPath = join(targetDir, "Cargo.toml");
    const cargoText = await Bun.file(cargoPath).text();
    await Bun.write(cargoPath, cargoText + "redis = { version = \"0.25.3\", features = [\"tokio-comp\", \"tokio-rustls-comp\"] }\n");
    
    const mainPath = join(targetDir, "src/main.rs");
    const mainText = await Bun.file(mainPath).text();
    await Bun.write(mainPath, mainText.replace("mod db;\n", "mod db;\npub mod cache;\n"));
    
    const usersPath = join(targetDir, "src/api/handlers/users.rs");
    await Bun.write(usersPath, `use axum::{
    extract::State,
    http::StatusCode,
    Json,
};
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
use redis::AsyncCommands;
use crate::api::AppState;

#[derive(Serialize, Deserialize, FromRow)]
pub struct UserResponse {
    pub id: uuid::Uuid,
    pub email: String,
    pub name: Option<String>,
    pub role: String,
}

pub async fn get_users(
    State(state): State<AppState>,
) -> Result<Json<Vec<UserResponse>>, (StatusCode, String)> {
    let client = crate::cache::redis::get_client();
    if let Ok(mut con) = client.get_multiplexed_async_connection().await {
        if let Ok(cached_users) = con.get::<_, String>("users:all").await {
            if let Ok(users) = serde_json::from_str::<Vec<UserResponse>>(&cached_users) {
                return Ok(Json(users));
            }
        }
    }

    let users = sqlx::query_as::<_, UserResponse>(
        "SELECT id, email, name, role::text as role FROM users ORDER BY created_at DESC"
    )
    .fetch_all(&state.db)
    .await
    .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Database error: {}", e)))?;

    if let Ok(mut con) = client.get_multiplexed_async_connection().await {
        if let Ok(json_str) = serde_json::to_string(&users) {
            let _: redis::RedisResult<()> = con.set_ex("users:all", json_str, 60).await;
        }
    }

    Ok(Json(users))
}`);
  }

  if (options.dbTarget === "docker" || options.cachingTarget === "docker") {
    const dc = await resolveDockerCompose(options.projectName, dbPassword, options.dbTarget, options.cachingTarget, options.dbPort, options.redisPort);
    await Bun.write(join(targetDir, "docker-compose.yml"), dc);
  }

  await Bun.write(join(targetDir, ".env"), envContent);
}

async function generateHonoProject(options: ProjectOptions) {
  const targetDir = join(process.cwd(), options.projectName);
  const jwtSecret = generateJwtSecret();
  const dbPassword = generateDbPassword();

  await Promise.all(
    PROJECT_FOLDERS.map((folder) =>
      mkdir(join(targetDir, folder), { recursive: true }),
    ),
  );

  const [
    prismaSchema, prismaConfig, tsconfig, envFile, prismaClient, serverSource, errorMiddleware, healthRoutes, userRoutes, userController, userService, authController, authMiddleware, authRoutes, waitForPostgres, dockerCompose, exampleTest
  ] = await Promise.all([
    readTemplate("express/schema.prisma"),
    readTemplate("express/prisma.config.ts"),
    readTemplate("express/tsconfig.json"),
    resolveEnvFile(options.dbTarget, options.projectName, jwtSecret, dbPassword, options.authTarget, options.cachingTarget, options.dbPort, options.redisPort),
    resolvePrismaClient(options.dbTarget),
    resolveServerSource(options.extraPackages, "hono", options.authTarget),
    readTemplate("hono/error.middleware.ts"),
    readTemplate("hono/health.routes.ts"),
    readTemplate("hono/user.routes.ts"),
    options.extraPackages.includes("zod") ? readTemplate("hono/user.controller.zod.ts") : readTemplate("hono/user.controller.default.ts"),
    resolveUserService(options.cachingTarget),
    readTemplate(`hono/auth.controller${options.authTarget === 'local' ? '' : '.' + options.authTarget}.ts`),
    readTemplate(`hono/auth.middleware${options.authTarget === 'local' ? '' : '.' + options.authTarget}.ts`),
    readTemplate("hono/auth.routes.ts"),
    options.dbTarget === "docker" ? readTemplate("express/wait-for-postgres.ts") : Promise.resolve(null),
    options.dbTarget === "docker" || options.cachingTarget === "docker" ? resolveDockerCompose(options.projectName, dbPassword, options.dbTarget, options.cachingTarget, options.dbPort, options.redisPort) : Promise.resolve(null),
    readTemplate("express/example.test.ts"),
  ]);

  const files: Array<[string, string]> = [
    ["prisma/schema.prisma", prismaSchema],
    ["prisma.config.ts", prismaConfig],
    ["tsconfig.json", tsconfig],
    [".env", envFile],
    ["src/lib/prisma.ts", prismaClient],
    ["src/index.ts", serverSource],
    ["src/middlewares/error.middleware.ts", errorMiddleware],
    ["src/middlewares/auth.middleware.ts", authMiddleware],
    ["src/routes/health.routes.ts", healthRoutes],
    ["src/routes/user.routes.ts", userRoutes],
    ["src/routes/auth.routes.ts", authRoutes!],
    ["src/controllers/user.controller.ts", userController],
    ["src/controllers/auth.controller.ts", authController!],
    ["src/services/user.service.ts", userService],
    ["src/index.test.ts", exampleTest],
  ];

  if (options.dbTarget === "docker" && waitForPostgres) {
    files.splice(5, 0, ["src/lib/wait-for-postgres.ts", waitForPostgres!]);
  }

  if (options.dbTarget === "docker" || options.cachingTarget === "docker") {
    files.push(["docker-compose.yml", dockerCompose!]);
  }

  if (options.cachingTarget === "docker") {
    files.push(["src/lib/redis.ts", await readTemplate("express/redis.docker.ts")]);
  } else if (options.cachingTarget === "upstash") {
    files.push(["src/lib/redis.ts", await readTemplate("express/redis.upstash.ts")]);
  }

  await Promise.all([
    ...files.map(([path, content]) => writeFile(join(targetDir, path), content)),
    createPackageJson(options.projectName, options.dbTarget, options.extraPackages, options.cachingTarget, options.authTarget, "hono").then((pkg) => {
      // Override for Hono
      pkg.dependencies.hono = "^4.0.0";
      pkg.dependencies["@hono/node-server"] = "^1.11.0";
      delete pkg.dependencies.cors;
      delete pkg.dependencies.helmet;
      delete pkg.devDependencies["@types/cors"];
      delete pkg.dependencies.express;
      delete pkg.devDependencies["@types/express"];
      return writeJson(join(targetDir, "package.json"), pkg);
    }),
  ]);
}

async function generateElysiaProject(options: ProjectOptions) {
  const targetDir = join(process.cwd(), options.projectName);
  const jwtSecret = generateJwtSecret();
  const dbPassword = generateDbPassword();

  await Promise.all(
    PROJECT_FOLDERS.map((folder) =>
      mkdir(join(targetDir, folder), { recursive: true }),
    ),
  );

  const [
    prismaSchema, prismaConfig, tsconfig, envFile, prismaClient, serverSource, errorMiddleware, healthRoutes, userRoutes, userController, userService, authController, authMiddleware, authRoutes, waitForPostgres, dockerCompose, exampleTest
  ] = await Promise.all([
    readTemplate("express/schema.prisma"),
    readTemplate("express/prisma.config.ts"),
    readTemplate("express/tsconfig.json"),
    resolveEnvFile(options.dbTarget, options.projectName, jwtSecret, dbPassword, options.authTarget, options.cachingTarget, options.dbPort, options.redisPort),
    resolvePrismaClient(options.dbTarget),
    resolveServerSource(options.extraPackages, "elysia", options.authTarget),
    readTemplate("elysia/error.middleware.ts"),
    readTemplate("elysia/health.routes.ts"),
    readTemplate("elysia/user.routes.ts"),
    options.extraPackages.includes("zod") ? readTemplate("elysia/user.controller.zod.ts") : readTemplate("elysia/user.controller.default.ts"),
    resolveUserService(options.cachingTarget),
    readTemplate(`elysia/auth.controller${options.authTarget === 'local' ? '' : '.' + options.authTarget}.ts`),
    readTemplate(`elysia/auth.middleware${options.authTarget === 'local' ? '' : '.' + options.authTarget}.ts`),
    readTemplate("elysia/auth.routes.ts"),
    options.dbTarget === "docker" ? readTemplate("express/wait-for-postgres.ts") : Promise.resolve(null),
    options.dbTarget === "docker" || options.cachingTarget === "docker" ? resolveDockerCompose(options.projectName, dbPassword, options.dbTarget, options.cachingTarget, options.dbPort, options.redisPort) : Promise.resolve(null),
    readTemplate("express/example.test.ts"),
  ]);

  const files: Array<[string, string]> = [
    ["prisma/schema.prisma", prismaSchema],
    ["prisma.config.ts", prismaConfig],
    ["tsconfig.json", tsconfig],
    [".env", envFile],
    ["src/lib/prisma.ts", prismaClient],
    ["src/index.ts", serverSource],
    ["src/middlewares/error.middleware.ts", errorMiddleware],
    ["src/middlewares/auth.middleware.ts", authMiddleware],
    ["src/routes/health.routes.ts", healthRoutes],
    ["src/routes/user.routes.ts", userRoutes],
    ["src/routes/auth.routes.ts", authRoutes!],
    ["src/controllers/user.controller.ts", userController],
    ["src/controllers/auth.controller.ts", authController!],
    ["src/services/user.service.ts", userService],
    ["src/index.test.ts", exampleTest],
  ];

  if (options.dbTarget === "docker" && waitForPostgres) {
    files.splice(5, 0, ["src/lib/wait-for-postgres.ts", waitForPostgres!]);
  }

  if (options.dbTarget === "docker" || options.cachingTarget === "docker") {
    files.push(["docker-compose.yml", dockerCompose!]);
  }

  if (options.cachingTarget === "docker") {
    files.push(["src/lib/redis.ts", await readTemplate("express/redis.docker.ts")]);
  } else if (options.cachingTarget === "upstash") {
    files.push(["src/lib/redis.ts", await readTemplate("express/redis.upstash.ts")]);
  }

  await Promise.all([
    ...files.map(([path, content]) => writeFile(join(targetDir, path), content)),
    createPackageJson(options.projectName, options.dbTarget, options.extraPackages, options.cachingTarget, options.authTarget, "elysia").then((pkg) => {
      // Override for Elysia
      pkg.dependencies.elysia = "^1.0.0";
      if (options.extraPackages.includes("cors")) pkg.dependencies["@elysiajs/cors"] = "^1.0.2";
      if (options.extraPackages.includes("helmet")) pkg.dependencies["elysia-helmet"] = "^3.1.0";
      delete pkg.dependencies.cors;
      delete pkg.dependencies.helmet;
      delete pkg.devDependencies["@types/cors"];
      delete pkg.dependencies.express;
      delete pkg.devDependencies["@types/express"];
      return writeJson(join(targetDir, "package.json"), pkg);
    }),
  ]);
}

export async function generateProject(options: ProjectOptions) {
  if (options.framework === "express") {
    await generateExpressProject(options);
  } else if (options.framework === "laravel") {
    await generateLaravelProject(options);
  } else if (options.framework === "nextjs") {
    await generateNextJsProject(options);
  } else if (options.framework === "react") {
    await generateReactProject(options);
  } else if (options.framework === "vue") {
    await generateVueProject(options);
  } else if (options.framework === "python") {
    await generatePythonProject(options);
  } else if (options.framework === "go") {
    await generateGoProject(options);
  } else if (options.framework === "rust") {
    await generateRustProject(options);
  } else if (options.framework === "hono") {
    await generateHonoProject(options);
  } else if (options.framework === "elysia") {
    await generateElysiaProject(options);
  } else if (options.framework === "monorepo") {
    const rootName = options.projectName;
    const targetDir = join(process.cwd(), rootName);
    
    // Generate backend
    options.framework = options.backendFramework!;
    options.projectName = `${rootName}/backend`;
    await generateProject(options);
    
    // Generate frontend
    options.framework = options.frontendFramework!;
    options.projectName = `${rootName}/frontend`;
    await generateProject(options);
    
    // Generate root orchestration
    let backendCmd = "bun dev";
    if (options.backendFramework === "laravel") backendCmd = "php artisan serve";
    if (options.backendFramework === "python") backendCmd = process.platform === "win32" ? "venv\\\\Scripts\\\\uvicorn app.main:app --reload" : "venv/bin/uvicorn app.main:app --reload";
    if (options.backendFramework === "go") backendCmd = "go run cmd/api/main.go";
    if (options.backendFramework === "rust") backendCmd = "cargo run";

    const includeBackendWorkspace = ["express", "hono", "elysia", "laravel"].includes(options.backendFramework!);
    const hasPrismaBackend = ["express", "hono", "elysia"].includes(options.backendFramework!);
    const rootPkg = {
      name: rootName,
      private: true,
      workspaces: includeBackendWorkspace ? ["backend", "frontend"] : ["frontend"],
      scripts: {
        dev: `bunx concurrently "cd backend && ${backendCmd}" "cd frontend && bun dev"`,
        ...(hasPrismaBackend
          ? {
              "db:generate": "cd backend && bun run db:generate",
              "db:push": "cd backend && bun run db:push",
              "db:studio": "cd backend && bun run db:studio",
            }
          : options.backendFramework === "laravel"
            ? { "db:migrate": "cd backend && php artisan migrate" }
            : {}),
      },
      // `bunx concurrently` resolves this local dependency instead of fetching
      // an undeclared package the first time `bun run dev` is executed.
      devDependencies: {
        concurrently: packageVersions.devDependencies.concurrently,
      },
    };
    await Bun.write(join(targetDir, "package.json"), JSON.stringify(rootPkg, null, 2));
    
    // Restore project name and framework
    options.projectName = rootName;
    options.framework = "monorepo";
  }
}
