#!/usr/bin/env node
import { intro, multiselect, note, outro, spinner, text } from "@clack/prompts";
import boxen from "boxen";
import { execSync } from "child_process";
import { mkdir, writeFile } from "fs/promises";
import { randomUUID } from "node:crypto";
import { parseArgs } from "node:util";
import path from "path";
import color from "picocolors";

const { values } = parseArgs({
    options: {
        db: { type: "boolean" },
        auth: { type: "boolean" },
        reactScan: { type: "boolean" }, // Replaced million with reactScan
        yes: { type: "boolean" },
    },
});

async function main() {
    // Show intro
    intro(
        color.cyan(
            boxen("Create Unstack", {
                padding: 1,
                margin: 1,
                borderStyle: "double",
                title: "🚀 Next.js Scaffolding Tool",
            }),
        ),
    );

    // Project name
    let projectName = "";
    if (values.yes) {
        projectName = "my-app";
        note(`Using default project name: ${color.green(projectName)}`);
    } else {
        projectName = (await text({
            message: "What is your project name?",
            placeholder: "my-app",
            validate(value) {
                if (!value) return "Please enter a project name";
                if (!/^[a-z0-9-_]+$/.test(value))
                    return "Project name can only contain lowercase letters, numbers, hyphens, and underscores";
                return undefined;
            },
        })) as string;
    }

    // Features selection
    let features = {
        db: values.db ?? false,
        auth: values.auth ?? false,
        reactScan: values.reactScan ?? false, // Replaced million with reactScan
    };

    if (!values.yes) {
        const selectedFeatures = (await multiselect({
            message: "Select optional features (press Enter to skip all):",
            options: [
                { value: "db", label: "MongoDB" },
                { value: "auth", label: "Better-Auth (Authentication)" },
                { value: "reactScan", label: "React Scan (Performance)" }, // Replaced million with reactScan
            ],
            required: false, // Allow no selection
        })) as string[] | undefined;

        // Handle case where no features are selected or selectedFeatures is undefined
        const featuresArray = selectedFeatures || [];

        features = {
            db: featuresArray.includes("db"),
            auth: featuresArray.includes("auth"),
            reactScan: featuresArray.includes("reactScan"), // Replaced million with reactScan
        };

        // Show message if no features are selected
        if (featuresArray.length === 0) {
            note(
                color.cyan(
                    "No optional features selected. Creating a minimal Next.js app.",
                ),
            );
        }
    }

    // If auth is selected without db, enable db automatically
    if (features.auth && !features.db) {
        features.db = true;
        note(
            color.yellow(
                "Authentication requires a database. MongoDB has been automatically enabled.",
            ),
        );
    }

    // Create project directory
    const projectDir = path.join(process.cwd(), projectName);
    const s = spinner();
    s.start("Creating project directory");

    try {
        await mkdir(projectDir, { recursive: true });
        s.stop("Project directory created");
    } catch (error) {
        s.stop("Failed to create project directory");
        process.exit(1);
    }

    // Scaffold project
    s.start("Scaffolding project files");

    try {
        // Create package.json
        await writeFile(
            path.join(projectDir, "package.json"),
            JSON.stringify(generatePackageJson(projectName, features), null, 2),
        );
        // Create next.config.js
        await writeFile(
            path.join(projectDir, "next.config.js"),
            generateNextConfig(), // Removed features argument
        );

        // Create tsconfig.json
        await writeFile(
            path.join(projectDir, "tsconfig.json"),
            JSON.stringify(generateTsConfig(), null, 2),
        );

        // Create .env and .env.example
        await writeFile(
            path.join(projectDir, ".env"),
            generateEnvFile(projectName),
        );

        await writeFile(
            path.join(projectDir, ".env.example"),
            generateEnvFile(projectName),
        );

        // Create .gitignore
        await writeFile(path.join(projectDir, ".gitignore"), generateGitignore());

        // Create README.md
        await writeFile(
            path.join(projectDir, "README.md"),
            generateReadme(projectName, features),
        );

        await mkdir(path.join(projectDir, "config"), { recursive: true });
        await writeFile(path.join(projectDir, "config", "site.ts"), generateSite());
        await writeFile(
            path.join(projectDir, "config", "fonts.ts"),
            generateFonts(),
        );
        // Create app directory structure
        await mkdir(path.join(projectDir, "app"), { recursive: true });
        await writeFile(
            path.join(projectDir, "app", "layout.tsx"),
            generateLayout(features),
        );
        await writeFile(
            path.join(projectDir, "app", "page.tsx"),
            generateHomePage(),
        );
        // Create styles folder
        await mkdir(path.join(projectDir, "styles"), { recursive: true });
        await writeFile(
            path.join(projectDir, "styles", "globals.css"),
            generateGlobalCss(),
        );

        // Create components directory
        await mkdir(path.join(projectDir, "components"), { recursive: true });
        await mkdir(path.join(projectDir, "components", "ui"), {
            recursive: true,
        });

        // Create lib directory
        await mkdir(path.join(projectDir, "lib"), { recursive: true });
        await writeFile(path.join(projectDir, "lib", "utils.ts"), generateUtils());

        // Create tailwind.config.js
        await writeFile(
            path.join(projectDir, "tailwind.config.js"),
            generateTailwindConfig(),
        );
        // Create components.json
        await writeFile(
            path.join(projectDir, "components.json"),
            JSON.stringify(generateComponentsJson(), null, 2),
        );
        // Create app/providers.tsx
        await writeFile(
            path.join(projectDir, "app", "providers.tsx"),
            generateProviders(),
        );

        // Create postcss.config.js
        await writeFile(
            path.join(projectDir, "postcss.config.js"),
            generatePostcssConfig(),
        );

        // Create biome.json
        await writeFile(
            path.join(projectDir, "biome.json"),
            generateBiomeConfig(),
        );

        // Create .vscode directory and settings
        await mkdir(path.join(projectDir, ".vscode"), { recursive: true });
        await writeFile(
            path.join(projectDir, ".vscode", "settings.json"),
            JSON.stringify(generateVsCodeSettings(), null, 2),
        );

        // Add MongoDB if selected
        if (features.db) {
            await writeFile(
                path.join(projectDir, "lib", "db.ts"),
                generateMongoDbConfig(),
            );
        }

        if (features.auth) {
            // Create @/lib/auth.ts
            await writeFile(
                path.join(projectDir, "lib", "auth.ts"),
                generateAuthConfig(),
            );

            await writeFile(
                path.join(projectDir, "lib", "auth-client.ts"),
                generateAuthClient(),
            );
            await mkdir(path.join(projectDir, "app", "api"), {
                recursive: true,
            });
            await mkdir(path.join(projectDir, "app", "api", "auth"), {
                recursive: true,
            });
            await mkdir(path.join(projectDir, "app", "api", "auth", "[...all]"), {
                recursive: true,
            });
            await writeFile(
                path.join(projectDir, "app", "api", "auth", "[...all]", "route.ts"),
                generateAuthRoute(),
            );
        }

        s.stop("Project files created successfully");
    } catch (error) {
        s.stop(`Failed to scaffold project: ${error}`);
        process.exit(1);
    }

    // Initialize git repository
    s.start("Initializing git repository");
    try {
        execSync("git init", { cwd: projectDir });
        execSync("git add .", { cwd: projectDir });
        execSync('git commit -m "Initial commit from create-untraceable-stack"', {
            cwd: projectDir,
        });
        s.stop("Git repository initialized");
    } catch (error) {
        s.stop("Failed to initialize git repository");
    }

    // Show success message
    outro(
        boxen(
            `${color.green("✅ Success!")} Your project ${color.cyan(projectName)} has been created.\n\n` +
            `To get started:\n\n` +
            `  ${color.yellow("cd")} ${projectName}\n` +
            `  ${color.yellow("bun install")} ${color.dim("# or npm install / yarn")}\n` +
            `  ${color.yellow("bun dev")} ${color.dim("# or npm run dev / yarn dev")}\n\n` +
            `${color.dim("Happy coding! 🚀")}`,
            {
                padding: 1,
                margin: 1,
                borderStyle: "round",
                title: "🎉 Next Steps",
            },
        ),
    );
}

// Helper functions to generate files
function generatePackageJson(
    projectName: string,
    features: { db: boolean; auth: boolean; reactScan: boolean }, // Replaced million with reactScan
) {
    const dependencies: Record<string, string> = {
        next: "^16.2.4",
        react: "^19.2.5",
        "tailwindcss-animate": "^1.0.7",
        "react-dom": "^19.2.5",
        "@heroui/system": "^2.4.28",
        "@heroui/theme": "^2.4.26",
        "@heroui/toast": "^2.0.22",
        "@heroui/button": "^2.2.32",
        "next-themes": "^0.4.6",
        "class-variance-authority": "^0.7.1",
        clsx: "^2.1.1",
        "lucide-react": "^0.292.0",
        "tailwind-merge": "^2.0.0",
        "ultracite": "^5.0.46",
    };
    
    if (features.db) {
        dependencies["mongodb"] = "^7.2.0";
    }

    if (features.auth) {
        dependencies["better-auth"] = "^1.6.7";
    }
    
    const devDependencies: Record<string, string> = {
        "@types/react": "^19.2.14",
        "@types/react-dom": "^19.2.3",
        "@types/node": "^20.9.0",
        tailwindcss: "^4.2.4",
        typescript: "^5.9.3",
        "@tailwindcss/postcss": "^4.2.4",
        "@biomejs/biome": "^2.4.12",
    };

    return {
        name: projectName,
        version: "0.1.0",
        type: "module",
        private: true,
        scripts: {
            dev: "next dev --turbopack",
            build: "next build --turbopack",
            start: "next start",
            lint: "biome lint .",
            format: "biome format --write .",
        },
        dependencies,
        devDependencies,
    };
}

function generateNextConfig() {
    return `/** @type {import('next').NextConfig} */
const nextConfig = {};

export default nextConfig;
`;
}

function generateTsConfig() {
    return {
        compilerOptions: {
            target: "es2020",
            lib: ["dom", "dom.iterable", "es2020"],
            allowJs: true,
            skipLibCheck: true,
            strict: true,
            forceConsistentCasingInFileNames: true,
            noEmit: true,
            esModuleInterop: true,
            module: "es2020",
            moduleResolution: "node",
            resolveJsonModule: true,
            isolatedModules: true,
            jsx: "preserve",
            incremental: true,
            plugins: [
                {
                    name: "next",
                },
            ],
            paths: {
                "@/*": ["./*"],
            },
        },
        include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
        exclude: ["node_modules"],
    };
}

function generateEnvFile(projectName: string) {
    return `MONGODB_URI="mongodb://localhost:27017/${projectName}"
BETTER_AUTH_SECRET="${randomUUID()}"
BETTER_AUTH_URL="http://localhost:3000"
`;
}

function generateGitignore() {
    return `# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local
.env

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
`;
}

function generateReadme(
    projectName: string,
    features: { db: boolean; auth: boolean; reactScan: boolean },
) {
    let featuresSection = `
## Features

- 🎨 **TailwindCSS v4** - Utility-first CSS framework
- 🧩 **ShadCN UI** - Accessible and customizable component library
- 🔍 **Biome** - Code linting and formatting
- 🔄 **Git** - Version control with initial commit
`;

    if (features.db) {
        featuresSection += `- 🗄️ **MongoDB** - Database with MongoDB\n`;
    }

    if (features.auth) {
        featuresSection += `- 🔐 **Better-Auth** - Best Authentication system\n`;
    }

    if (features.reactScan) {
        featuresSection += `- ⚡ **React Scan** - Performance analysis for React\n`;
    }

    return `# ${projectName}

This project was bootstrapped with [create-untraceable-stack](https://github.com/TheUntraceable/create-untraceable-stack).

${featuresSection}

## Getting Started

First, install the dependencies:

\`\`\`bash
bun install
# or
npm install
# or
yarn install
\`\`\`

Then, run the development server:

\`\`\`bash
bun dev
# or
npm run dev
# or
yarn dev
\`\`\`

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

## Learn More

To learn more about the technologies used in this project:

- [Next.js Documentation](https://nextjs.org/docs)
- [TailwindCSS Documentation](https://tailwindcss.com/docs)
- [ShadCN UI Documentation](https://ui.shadcn.com)
${features.db ? "- [MongoDB Documentation](https://mongodb.com/docs)\\n" : ""}
${features.auth ? "- [Better-Auth Documentation](https://better-auth.dev)\\n" : ""}
${features.reactScan ? "- [React Scan Documentation](https://github.com/aidenybai/react-scan)\\n" : ""} // Updated link and text
`;
}

function generateLayout(features: {
    db: boolean;
    auth: boolean;
    reactScan: boolean;
}) {

    const reactScanComponent = features.reactScan ? `<Head>
                <script src="https://cdn.jsdelivr.net/npm/react-scan/dist/auto.global.js" />
            </Head>` : "";

    return `import "@/styles/globals.css";
import clsx from "clsx";
import { Metadata, Viewport } from "next";

import { fontSans } from "@/config/fonts";
import { siteConfig } from "@/config/site";

import { Providers } from "./providers";
import Head from "next/head";

export const metadata: Metadata = {
    description: siteConfig.description,
    icons: {
        icon: "/favicon.ico",
    },
    title: {
        default: siteConfig.name,
        template: \`%s - \${siteConfig.name}\`,
    },
};

export const viewport: Viewport = {
    themeColor: [
        { color: "white", media: "(prefers-color-scheme: light)" },
        { color: "black", media: "(prefers-color-scheme: dark)" },
    ],
};

export default function RootLayout({
    children,
}: {
    children: React.ReactNode;
}) {
    return (
        <html suppressHydrationWarning lang="en">
            ${reactScanComponent}
            <body
                className={clsx(
                    "min-h-screen bg-background font-sans antialiased",
                    fontSans.variable,
                )}
            >
                <Providers
                    themeProps={{ attribute: "class", defaultTheme: "dark" }}
                >
                    <div className="flex flex-col">
                        <main className="grow">{children}</main>
                    </div>
                </Providers>
            </body>
        </html>
    );
}`;
}

function generateFonts() {
    return `import { Fira_Code as FontMono, Inter as FontSans } from "next/font/google";

export const fontSans = FontSans({
    subsets: ["latin"],
    variable: "--font-sans",
});

export const fontMono = FontMono({
    subsets: ["latin"],
    variable: "--font-mono",
});
`;
}
function generateSite() {
    return `export type SiteConfig = typeof siteConfig;

export const siteConfig = {
    name: "Create Untraceable Stack",
    description:
        "Get up and running fast with Untraceable Stack.",
};`;
}



function generateHomePage() {
    return `import { Button } from '@heroui/button';

export default function Home() {
  return (
    <div className="flex min-h-screen flex-col items-center justify-center p-4">
      <div className="max-w-3xl text-center">
        <h1 className="mb-4 text-4xl font-bold tracking-tight sm:text-5xl">
          Welcome to <span className="text-primary">Untraceable Stack</span>
        </h1>
        <p className="mb-8 text-lg text-muted-foreground">
          A modern Next.js application with TailwindCSS, ShadCN UI, and more.
        </p>
        <div className="flex flex-wrap justify-center gap-4">
          <Button variant="shadow" color="primary">
            <a href="https://heroui.org/docs" target="_blank" rel="noopener noreferrer">
              Next.js Docs
            </a>
          </Button>
          <Button variant="bordered">
            <a href="https://ui.shadcn.com" target="_blank" rel="noopener noreferrer">
              ShadCN UI
            </a>
          </Button>
        </div>
      </div>
    </div>
  );
}
`;
}


function generateGlobalCss() {
    return `@import "tailwindcss";
@config "../tailwind.config.js";

@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 222.2 84% 4.9%;

    --card: 0 0% 100%;
    --card-foreground: 222.2 84% 4.9%;
 
    --popover: 0 0% 100%;
    --popover-foreground: 222.2 84% 4.9%;
 
    --primary: 222.2 47.4% 11.2%;
    --primary-foreground: 210 40% 98%;
 
    --secondary: 210 40% 96.1%;
    --secondary-foreground: 222.2 47.4% 11.2%;
 
    --muted: 210 40% 96.1%;
    --muted-foreground: 215.4 16.3% 46.9%;
 
    --accent: 210 40% 96.1%;
    --accent-foreground: 222.2 47.4% 11.2%;
 
    --destructive: 0 84.2% 60.2%;
    --destructive-foreground: 210 40% 98%;

    --border: 214.3 31.8% 91.4%;
    --input: 214.3 31.8% 91.4%;
    --ring: 222.2 84% 4.9%;
 
    --radius: 0.5rem;
  }
 
  .dark {
    --background: 222.2 84% 4.9%;
    --foreground: 210 40% 98%;
 
    --card: 222.2 84% 4.9%;
    --card-foreground: 210 40% 98%;
 
    --popover: 222.2 84% 4.9%;
    --popover-foreground: 210 40% 98%;
 
    --primary: 210 40% 98%;
    --primary-foreground: 222.2 47.4% 11.2%;
 
    --secondary: 217.2 32.6% 17.5%;
    --secondary-foreground: 210 40% 98%;
 
    --muted: 217.2 32.6% 17.5%;
    --muted-foreground: 215 20.2% 65.1%;
 
    --accent: 217.2 32.6% 17.5%;
    --accent-foreground: 210 40% 98%;
 
    --destructive: 0 62.8% 30.6%;
    --destructive-foreground: 210 40% 98%;
 
    --border: 217.2 32.6% 17.5%;
    --input: 217.2 32.6% 17.5%;
    --ring: 212.7 26.8% 83.9%;
  }
}
 
@layer base {
  * {
    @apply border-border;
  }
  body {
    @apply bg-background text-foreground;
  }
}`;
}

function generateUtils() {
    return `import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}
`;
}

function generateTailwindConfig() {
    return `
import { heroui } from "@heroui/theme";
/** @type {import('tailwindcss').Config} */
export default {
    content: [
        "./components/**/*.{js,ts,jsx,tsx,mdx}",
        "./app/**/*.{js,ts,jsx,tsx,mdx}",
        "./node_modules/@heroui/theme/dist/**/*.{js,ts,jsx,tsx}",
    ],
    theme: {
        extend: {
            fontFamily: {
                sans: ["var(--font-sans)"],
                mono: ["var(--font-mono)"],
            },
            borderRadius: {
                lg: "var(--radius)",
                md: "calc(var(--radius) - 2px)",
                sm: "calc(var(--radius) - 4px)",
            },
            colors: {
                border: {
                    DEFAULT: "hsl(var(--border))",
                    hover: "hsl(var(--border-hover))",
                },
            },
        },
    },
    darkMode: "class",
    plugins: [heroui(), require("tailwindcss-animate")],
};
`;
}

function generatePostcssConfig() {
    return `export default {
  plugins: {
  "@tailwindcss/postcss": {}
  },
}`;
}



function generateBiomeConfig() {
    return `{
  "$schema": "https://biomejs.dev/schemas/2.0.6/schema.json",
  "extends": ["ultracite"],
  "linter": {
    "enabled": true,
    "includes": [
      "**/*.ts",
      "**/*.tsx",
      "**/*.js",
      "**/*.jsx",
      "**/*.json",
      "**/*.md"
    ],
    "rules": {
      "style": {
        "noNonNullAssertion": "off"
      }
    }
  },
  "files": {
    "experimentalScannerIgnores": ["node_modules", ".git", ".next"]
  },
  "formatter": {
    "enabled": true,
    "indentWidth": 4,
    "indentStyle": "space"
  },
  "vcs": {
    "enabled": true,
    "clientKind": "git",
    "useIgnoreFile": true
  }
}
`
}

function generateVsCodeSettings() {
    return {
        "editor.defaultFormatter": "biomejs.biome",
        "editor.formatOnSave": true,
        "editor.codeActionsOnSave": {
            "quickfix.biome": "explicit",
            "source.organizeImports.biome": "explicit",
        },
        "[json]": {
            "editor.defaultFormatter": "biomejs.biome",
        },
        "[jsonc]": {
            "editor.defaultFormatter": "biomejs.biome",
        },
        "[javascript]": {
            "editor.defaultFormatter": "biomejs.biome",
        },
        "[typescript]": {
            "editor.defaultFormatter": "biomejs.biome",
        },
        "[javascriptreact]": {
            "editor.defaultFormatter": "biomejs.biome",
        },
        "[typescriptreact]": {
            "editor.defaultFormatter": "biomejs.biome",
        },
        "typescript.tsdk": "node_modules/typescript/lib",
        "typescript.enablePromptUseWorkspaceTsdk": true,
    };
}

function generateMongoDbConfig() {
    return `import { MongoClient } from "mongodb";

if (!process.env.MONGODB_URI) {
    throw new Error('Invalid/Missing environment variable: "MONGODB_URI"');
}

const uri = process.env.MONGODB_URI;
const options = {};

let client: MongoClient;

if (process.env.NODE_ENV === "development") {
    let globalWithMongo = global as typeof globalThis & {
        _mongoClient?: MongoClient;
    };

    if (!globalWithMongo._mongoClient) {
        globalWithMongo._mongoClient = new MongoClient(uri, options);
    }
    client = globalWithMongo._mongoClient;
} else {
    client = new MongoClient(uri, options);
}

export { client };`;
}

function generateAuthConfig() {
    return `import { betterAuth } from "better-auth";
import { mongodbAdapter } from "better-auth/adapters/mongodb";
import { client } from "@/lib/db";

const db = client.db("auth");

export const auth = betterAuth({
    database: mongodbAdapter(db)
});`;
}

function generateAuthClient() {
    return `import { createAuthClient } from "better-auth/react"
export const authClient = createAuthClient({
    baseURL: "http://localhost:3000"
})`;
}

function generateComponentsJson() {
    return {
        $schema: "https://ui.shadcn.com/schema.json",
        style: "new-york",
        rsc: true,
        tsx: true,
        tailwind: {
            config: "tailwind.config.js",
            css: "styles/globals.css",
            baseColor: "zinc",
            cssVariables: false,
            prefix: "",
        },
        aliases: {
            components: "@/components",
            utils: "@/lib/utils",
            ui: "@/components/ui",
            lib: "@/lib",
            hooks: "@/hooks",
        },
        iconLibrary: "lucide",
    };
}

function generateProviders() {
    return `"use client";

import type { ThemeProviderProps } from "next-themes";
import { ThemeProvider as NextThemesProvider } from "next-themes";
import { useRouter } from "next/navigation";
import * as React from "react";

import { HeroUIProvider } from "@heroui/system";
import { ToastProvider } from "@heroui/toast";

export interface ProvidersProps {
    children: React.ReactNode;
    themeProps?: ThemeProviderProps;
}

declare module "@react-types/shared" {
    interface RouterConfig {
        routerOptions: NonNullable<
            Parameters<ReturnType<typeof useRouter>["push"]>[1]
        >;
    }
}

export const Providers = ({ children, themeProps }: ProvidersProps) => {
    const router = useRouter();

    return (
        <HeroUIProvider navigate={router.push}>
            <ToastProvider />
            <NextThemesProvider {...themeProps}>
                {children}
            </NextThemesProvider>
        </HeroUIProvider>
    );
};`;
}

function generateAuthRoute() {
    return `import { auth } from "@/lib/auth";
import { toNextJsHandler } from "better-auth/next-js";
 
export const { POST, GET } = toNextJsHandler(auth);`;
}

main().catch(console.error);
