"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SkeletonService = void 0;
// @generated by mycontext — Page Skeleton Pattern service
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const chalk_1 = __importDefault(require("chalk"));
const GENERATED_HEADER = "// @generated by mycontext — do not edit manually\n";
const IGNORE_DIRS = new Set([
    "node_modules", ".next", ".git", "dist", "build", ".turbo",
    ".pnpm-store", "coverage", ".cache", ".vercel", "__pycache__",
    ".mycontext", "out",
]);
// ─── SkeletonService ──────────────────────────────────────────────
class SkeletonService {
    constructor(projectRoot) {
        this.projectRoot = projectRoot;
    }
    async scanPages() {
        const pages = [];
        const appDir = await this.findAppDir();
        if (!appDir)
            return pages;
        const pageFiles = await this.findFiles(appDir, /page\.(tsx|jsx)$/);
        for (const pagePath of pageFiles) {
            const routeDir = path.dirname(pagePath);
            const absRouteDir = path.join(this.projectRoot, routeDir);
            const clientComponent = await this.findClientComponent(routeDir);
            const hasLoading = await this.fileExists(path.join(routeDir, "loading.tsx")) ||
                await this.fileExists(path.join(routeDir, "loading.jsx"));
            const hasError = await this.fileExists(path.join(routeDir, "error.tsx")) ||
                await this.fileExists(path.join(routeDir, "error.jsx"));
            const hasNotFound = await this.fileExists(path.join(routeDir, "not-found.tsx")) ||
                await this.fileExists(path.join(routeDir, "not-found.jsx"));
            const dirName = path.basename(routeDir);
            const isDynamicRoute = /^\[.+\]$/.test(dirName);
            pages.push({
                pagePath,
                clientComponentPath: clientComponent,
                routeDir,
                hasLoading,
                hasError,
                hasNotFound,
                isDynamicRoute,
            });
        }
        return pages;
    }
    async analyzeComponent(filePath) {
        const absPath = path.join(this.projectRoot, filePath);
        const content = await fs.readFile(absPath, "utf8");
        const lines = content.split("\n");
        const componentName = this.extractComponentName(content, filePath);
        const isClientComponent = content.includes('"use client"') || content.includes("'use client'");
        const hasIsLoading = /if\s*\(\s*isLoading\s*\)/.test(content);
        const hasAsyncData = /useQuery|useSWR|fetch\(|\.useQuery|isLoading/.test(content);
        const imports = this.extractImports(content);
        const wrapperClasses = this.extractWrapperClasses(content);
        const stickyHeaderClasses = this.extractStickyHeader(content);
        const shellJsx = this.extractShellJsx(content);
        const contentSlots = this.detectContentSlots(content, filePath);
        const parentLayoutClasses = await this.getParentLayoutClasses(filePath);
        return {
            filePath,
            componentName,
            wrapperClasses,
            hasIsLoading,
            hasAsyncData,
            shellJsx,
            contentSlots,
            imports,
            stickyHeaderClasses,
            parentLayoutClasses,
            isClientComponent,
        };
    }
    generatePageSkeleton(analysis) {
        const skeletonName = `${analysis.componentName.replace(/Client$|View$|Page$/, "")}Skeleton`;
        const cardSkeletons = [];
        const contentJsx = [];
        for (const slot of analysis.contentSlots) {
            switch (slot.type) {
                case "card-list": {
                    const cardSkName = `${skeletonName}Card`;
                    cardSkeletons.push(this.generateCardSkeleton(cardSkName, slot.fields));
                    contentJsx.push(`        <div className="space-y-4">\n` +
                        `          {[1, 2, 3].map((i) => (\n` +
                        `            <${cardSkName} key={i} />\n` +
                        `          ))}\n` +
                        `        </div>`);
                    break;
                }
                case "table": {
                    contentJsx.push(this.generateTableSkeleton(slot.fields));
                    break;
                }
                case "stats": {
                    contentJsx.push(this.generateStatsSkeleton(slot.fields));
                    break;
                }
                case "detail": {
                    contentJsx.push(this.generateDetailSkeleton(slot.fields));
                    break;
                }
                case "form": {
                    contentJsx.push(this.generateFormSkeleton(slot.fields));
                    break;
                }
                case "filter": {
                    contentJsx.push(this.generateFilterSkeleton());
                    break;
                }
            }
        }
        if (contentJsx.length === 0) {
            contentJsx.push(`        <div className="space-y-4">\n` +
                `          {[1, 2, 3].map((i) => (\n` +
                `            <div key={i} className="rounded-lg border p-4">\n` +
                `              <Skeleton className="h-5 w-3/4 mb-2" />\n` +
                `              <Skeleton className="h-4 w-1/2" />\n` +
                `            </div>\n` +
                `          ))}\n` +
                `        </div>`);
        }
        const wrapperCls = analysis.wrapperClasses || "flex min-h-0 flex-col h-full";
        const stickySection = analysis.stickyHeaderClasses
            ? `\n      {/* Shell: static header */}\n` +
                `      <div className="${analysis.stickyHeaderClasses}">\n` +
                analysis.shellJsx.map(s => `        ${s}`).join("\n") +
                `\n      </div>\n`
            : analysis.shellJsx.length > 0
                ? `\n      {/* Shell: static structure */}\n` +
                    analysis.shellJsx.map(s => `      ${s}`).join("\n") + "\n"
                : "";
        const code = [
            GENERATED_HEADER,
            `import { Skeleton } from "@/components/ui/skeleton";\n`,
            ...cardSkeletons,
            `export function ${skeletonName}() {`,
            `  return (`,
            `    <div className="${wrapperCls}">`,
            stickySection,
            `      {/* Content: skeleton placeholders */}`,
            `      <div className="min-h-0 flex-1 overflow-y-auto">`,
            `        <div className="p-6 space-y-6">`,
            ...contentJsx,
            `        </div>`,
            `      </div>`,
            `    </div>`,
            `  );`,
            `}`,
            "",
        ].join("\n");
        return code;
    }
    generateLoadingPage(skeletonName, skeletonImportPath) {
        return [
            GENERATED_HEADER,
            `import { ${skeletonName} } from "${skeletonImportPath}";\n`,
            `export default function Loading() {`,
            `  return <${skeletonName} />;`,
            `}`,
            "",
        ].join("\n");
    }
    generateErrorPage() {
        return [
            `"use client";\n`,
            `import { useEffect } from "react";`,
            `\nexport default function Error({`,
            `  error,`,
            `  reset,`,
            `}: {`,
            `  error: Error & { digest?: string };`,
            `  reset: () => void;`,
            `}) {`,
            `  useEffect(() => {`,
            `    console.error(error);`,
            `  }, [error]);\n`,
            `  return (`,
            `    <div className="flex min-h-[400px] flex-col items-center justify-center gap-4 p-6">`,
            `      <h2 className="text-xl font-semibold">Something went wrong</h2>`,
            `      {error.message && (`,
            `        <p className="text-sm text-muted-foreground">{error.message}</p>`,
            `      )}`,
            `      <button`,
            `        onClick={reset}`,
            `        className="rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground hover:bg-primary/90"`,
            `      >`,
            `        Try again`,
            `      </button>`,
            `    </div>`,
            `  );`,
            `}`,
            "",
        ].join("\n");
    }
    generateNotFoundPage() {
        return [
            `import Link from "next/link";\n`,
            `export default function NotFound() {`,
            `  return (`,
            `    <div className="flex min-h-[400px] flex-col items-center justify-center gap-4 p-6">`,
            `      <div className="text-6xl font-bold text-muted-foreground">404</div>`,
            `      <h2 className="text-xl font-semibold">Page not found</h2>`,
            `      <p className="text-sm text-muted-foreground">`,
            `        Sorry, we couldn&apos;t find the page you&apos;re looking for.`,
            `      </p>`,
            `      <Link`,
            `        href="/"`,
            `        className="rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground hover:bg-primary/90"`,
            `      >`,
            `        Go back home`,
            `      </Link>`,
            `    </div>`,
            `  );`,
            `}`,
            "",
        ].join("\n");
    }
    async ensureSkeletonComponent() {
        const possiblePaths = [
            "components/ui/skeleton.tsx",
            "src/components/ui/skeleton.tsx",
        ];
        for (const p of possiblePaths) {
            if (await this.fileExists(p))
                return true;
        }
        const hasShadcn = await this.fileExists("components.json");
        if (hasShadcn) {
            try {
                const { execSync } = await Promise.resolve().then(() => __importStar(require("child_process")));
                execSync("npx shadcn@latest add skeleton -y", {
                    cwd: this.projectRoot,
                    stdio: "pipe",
                });
                return true;
            }
            catch {
                // Fall through to manual creation
            }
        }
        const uiDir = (await this.fileExists("src/components/ui"))
            ? "src/components/ui"
            : "components/ui";
        const skeletonPath = path.join(uiDir, "skeleton.tsx");
        const absDir = path.join(this.projectRoot, uiDir);
        await fs.ensureDir(absDir);
        const skeletonCode = [
            `import { cn } from "@/lib/utils";\n`,
            `export function Skeleton({`,
            `  className,`,
            `  ...props`,
            `}: React.HTMLAttributes<HTMLDivElement>) {`,
            `  return (`,
            `    <div`,
            `      className={cn("animate-pulse rounded-md bg-muted", className)}`,
            `      {...props}`,
            `    />`,
            `  );`,
            `}`,
            "",
        ].join("\n");
        await fs.writeFile(path.join(this.projectRoot, skeletonPath), skeletonCode);
        return true;
    }
    async auditSkeletons() {
        const suggestions = [];
        const pages = await this.scanPages();
        for (const page of pages) {
            const componentPath = page.clientComponentPath;
            if (!componentPath) {
                // Server component page — check for loading.tsx
                const pageContent = await this.readFile(page.pagePath);
                if (!pageContent)
                    continue;
                const hasAsyncData = pageContent.includes("async function") &&
                    (pageContent.includes("fetch(") || pageContent.includes("await "));
                if (!hasAsyncData)
                    continue;
            }
            const analysis = componentPath
                ? await this.analyzeComponent(componentPath)
                : null;
            if (analysis && (analysis.hasIsLoading || analysis.hasAsyncData)) {
                const skeletonName = `${analysis.componentName.replace(/Client$|View$|Page$/, "")}Skeleton`;
                const hasExistingSkeleton = await this.hasSkeletonExport(skeletonName);
                if (!hasExistingSkeleton) {
                    const code = this.generatePageSkeleton(analysis);
                    suggestions.push({
                        type: "missing-skeleton",
                        pagePath: page.pagePath,
                        skeletonName,
                        generatedCode: code,
                        targetFile: await this.getSkeletonsFilePath(),
                    });
                }
            }
            if (!page.hasLoading && (analysis?.hasAsyncData || analysis?.hasIsLoading)) {
                const skeletonName = analysis
                    ? `${analysis.componentName.replace(/Client$|View$|Page$/, "")}Skeleton`
                    : "Loading";
                const skeletonsFile = await this.getSkeletonsFilePath();
                const importPath = this.resolveImportPath(page.routeDir, skeletonsFile);
                suggestions.push({
                    type: "missing-loading",
                    pagePath: page.pagePath,
                    skeletonName,
                    generatedCode: this.generateLoadingPage(skeletonName, importPath),
                    targetFile: path.join(page.routeDir, "loading.tsx"),
                });
            }
            if (!page.hasError) {
                suggestions.push({
                    type: "missing-error",
                    pagePath: page.pagePath,
                    skeletonName: "Error",
                    generatedCode: this.generateErrorPage(),
                    targetFile: path.join(page.routeDir, "error.tsx"),
                });
            }
            if (page.isDynamicRoute && !page.hasNotFound) {
                suggestions.push({
                    type: "missing-not-found",
                    pagePath: page.pagePath,
                    skeletonName: "NotFound",
                    generatedCode: this.generateNotFoundPage(),
                    targetFile: path.join(page.routeDir, "not-found.tsx"),
                });
            }
        }
        return suggestions;
    }
    async applySuggestion(suggestion) {
        try {
            const absPath = path.join(this.projectRoot, suggestion.targetFile);
            if (suggestion.type === "missing-skeleton") {
                await fs.ensureDir(path.dirname(absPath));
                if (await fs.pathExists(absPath)) {
                    const existing = await fs.readFile(absPath, "utf8");
                    if (existing.includes(`export function ${suggestion.skeletonName}`)) {
                        return true; // Already exists
                    }
                    // Append to existing file
                    await fs.appendFile(absPath, "\n" + suggestion.generatedCode);
                }
                else {
                    await fs.writeFile(absPath, suggestion.generatedCode);
                }
            }
            else {
                await fs.ensureDir(path.dirname(absPath));
                if (await fs.pathExists(absPath)) {
                    const existing = await fs.readFile(absPath, "utf8");
                    if (!existing.includes(GENERATED_HEADER.trim())) {
                        return false; // Don't overwrite hand-written files
                    }
                }
                await fs.writeFile(absPath, suggestion.generatedCode);
            }
            return true;
        }
        catch (e) {
            console.error(chalk_1.default.red(`[SkeletonService] Failed to write ${suggestion.targetFile}:`), e);
            return false;
        }
    }
    // ─── Private: File Discovery ────────────────────────────────────
    async findAppDir() {
        for (const candidate of ["app", "src/app"]) {
            if (await this.fileExists(candidate))
                return candidate;
        }
        return null;
    }
    async findClientComponent(routeDir) {
        const absDir = path.join(this.projectRoot, routeDir);
        if (!(await fs.pathExists(absDir)))
            return null;
        try {
            const entries = await fs.readdir(absDir);
            // Look for *Client.tsx, *View.tsx patterns
            const clientPatterns = /(?:Client|View|Content)\.(tsx|jsx)$/;
            for (const entry of entries) {
                if (clientPatterns.test(entry)) {
                    const filePath = path.join(routeDir, entry);
                    const content = await this.readFile(filePath);
                    if (content && (content.includes('"use client"') || content.includes("'use client'"))) {
                        return filePath;
                    }
                }
            }
            // Also check page.tsx itself for client imports
            const pageContent = await this.readFile(path.join(routeDir, "page.tsx"));
            if (pageContent) {
                const importMatch = /import\s+(?:\w+|\{[^}]+\})\s+from\s+["']\.\/(\w+)["']/.exec(pageContent);
                if (importMatch?.[1]) {
                    const importedFile = path.join(routeDir, `${importMatch[1]}.tsx`);
                    if (await this.fileExists(importedFile)) {
                        const content = await this.readFile(importedFile);
                        if (content && (content.includes('"use client"') || content.includes("'use client'"))) {
                            return importedFile;
                        }
                    }
                }
            }
        }
        catch { /* ignore */ }
        return null;
    }
    async findFiles(dir, pattern, maxDepth = 8) {
        const results = [];
        const walk = async (currentDir, depth) => {
            if (depth > maxDepth)
                return;
            try {
                const absDir = path.join(this.projectRoot, currentDir);
                const entries = await fs.readdir(absDir, { withFileTypes: true });
                for (const entry of entries) {
                    if (IGNORE_DIRS.has(entry.name))
                        continue;
                    const rel = path.join(currentDir, entry.name);
                    if (entry.isDirectory()) {
                        await walk(rel, depth + 1);
                    }
                    else if (pattern.test(entry.name)) {
                        results.push(rel);
                    }
                }
            }
            catch { /* ignore */ }
        };
        await walk(dir, 0);
        return results;
    }
    async fileExists(relativePath) {
        return fs.pathExists(path.join(this.projectRoot, relativePath));
    }
    async readFile(relativePath) {
        try {
            return await fs.readFile(path.join(this.projectRoot, relativePath), "utf8");
        }
        catch {
            return null;
        }
    }
    // ─── Private: Component Analysis ────────────────────────────────
    extractComponentName(content, filePath) {
        // export default function FooClient
        const defaultExport = /export\s+default\s+function\s+(\w+)/.exec(content);
        if (defaultExport?.[1])
            return defaultExport[1];
        // export function FooClient
        const namedExport = /export\s+function\s+(\w+)/.exec(content);
        if (namedExport?.[1])
            return namedExport[1];
        // function FooClient
        const fnDecl = /function\s+([A-Z]\w+)/.exec(content);
        if (fnDecl?.[1])
            return fnDecl[1];
        // Derive from filename
        const base = path.basename(filePath, path.extname(filePath));
        return base.replace(/[-_](\w)/g, (_, c) => c.toUpperCase());
    }
    extractImports(content) {
        const imports = [];
        const regex = /import\s+(?:{[^}]+}|\w+)\s+from\s+["']([^"']+)["']/g;
        let match;
        while ((match = regex.exec(content)) !== null) {
            if (match[1])
                imports.push(match[1]);
        }
        return imports;
    }
    extractWrapperClasses(content) {
        // Find the return statement and get the first div's className
        const returnMatch = /return\s*\(\s*<div\s+className=["']([^"']+)["']/.exec(content);
        return returnMatch?.[1] || "flex min-h-0 flex-col h-full";
    }
    extractStickyHeader(content) {
        const stickyMatch = /className=["']([^"']*(?:sticky|top-0)[^"']*)["']/.exec(content);
        return stickyMatch?.[1] || null;
    }
    extractShellJsx(content) {
        const shell = [];
        // Extract tab labels
        const tabMatches = content.matchAll(/<(?:Tab|TabsTrigger)[^>]*>([^<]+)<\//g);
        for (const m of tabMatches) {
            if (m[1]?.trim()) {
                shell.push(`<span className="text-sm font-medium">${m[1].trim()}</span>`);
            }
        }
        // Extract stat card labels (text in small/muted that are string literals)
        const labelMatches = content.matchAll(/<(?:span|p|div)[^>]*className=["'][^"']*(?:text-\[?\d|text-xs|text-sm|font-bold)[^"']*["'][^>]*>([A-Z][^<{]+)<\//g);
        for (const m of labelMatches) {
            if (m[1]?.trim() && !m[1].includes("{")) {
                shell.push(`<span className="text-xs font-bold">${m[1].trim()}</span>`);
            }
        }
        return shell;
    }
    detectContentSlots(content, filePath) {
        const slots = [];
        // Card / Row list: .map() on data
        if (/\w+\.map\s*\(/.test(content)) {
            const fields = this.detectFieldsFromContent(content);
            slots.push({ type: "card-list", fields });
        }
        // Table
        if (/<(?:table|Table|thead|DataTable)/i.test(content)) {
            const fields = this.detectTableFields(content);
            slots.push({ type: "table", fields });
        }
        // Stats/KPI cards
        if (/grid\s+grid-cols/.test(content) && /\{\s*\w+(?:\.\w+)*\s*\}/.test(content) && !/\.map\s*\(/.test(content)) {
            slots.push({
                type: "stats",
                fields: [
                    { kind: "numeric", width: "w-12", height: "h-6", rounded: "rounded-md" },
                ],
            });
        }
        // Form with prefilled data
        if (/<(?:form|Form)/i.test(content) && /useQuery|useSWR|fetch\(/.test(content)) {
            const fields = this.detectFormFields(content);
            slots.push({ type: "form", fields });
        }
        // Filters with dynamic options
        if (/<(?:Select|DropdownMenu|Combobox)/i.test(content) && /options=\{|items=\{/.test(content)) {
            slots.push({ type: "filter", fields: [] });
        }
        // Detail page (single entity with interpolated values, no list)
        if (slots.length === 0 && /\{\s*\w+\.\w+\s*\}/.test(content) && !/\.map\s*\(/.test(content)) {
            const fields = this.detectDetailFields(content);
            if (fields.length > 0) {
                slots.push({ type: "detail", fields });
            }
        }
        return slots;
    }
    detectFieldsFromContent(content) {
        const fields = [];
        if (/rounded-full.*(?:h-\d+|w-\d+)|<img|<Image/.test(content)) {
            fields.push({ kind: "avatar", width: "w-10", height: "h-10", rounded: "rounded-full" });
        }
        if (/font-bold|text-lg|text-xl|font-semibold/.test(content)) {
            fields.push({ kind: "title", width: "w-3/4", height: "h-5" });
        }
        if (/text-sm|text-muted|text-gray/.test(content)) {
            fields.push({ kind: "subtitle", width: "w-1/2", height: "h-4" });
        }
        if (/<Badge/.test(content)) {
            fields.push({ kind: "badge", width: "w-16", height: "h-5", rounded: "rounded-full" });
        }
        if (/toLocaleString|toLocaleDateString|format.*date/i.test(content)) {
            fields.push({ kind: "date", width: "w-24", height: "h-4" });
        }
        if (fields.length === 0) {
            fields.push({ kind: "title", width: "w-3/4", height: "h-5" }, { kind: "subtitle", width: "w-1/2", height: "h-4" });
        }
        return fields;
    }
    detectTableFields(content) {
        const headerCount = (content.match(/<th|<TableHead/gi) || []).length;
        const count = Math.max(headerCount, 3);
        return Array.from({ length: count }, () => ({
            kind: "text",
            width: "w-24",
            height: "h-4",
        }));
    }
    detectFormFields(content) {
        const inputCount = (content.match(/<(?:input|Input|textarea|Textarea)/gi) || []).length;
        const count = Math.max(inputCount, 3);
        return Array.from({ length: count }, () => ({
            kind: "input",
            width: "w-full",
            height: "h-10",
        }));
    }
    detectDetailFields(content) {
        const fields = [];
        const interpolations = content.match(/\{\s*\w+\.\w+\s*\}/g) || [];
        for (const interp of interpolations.slice(0, 6)) {
            const varName = interp.replace(/[{}\s]/g, "").split(".").pop() || "";
            if (/title|name|label/i.test(varName)) {
                fields.push({ kind: "title", width: "w-3/4", height: "h-6" });
            }
            else if (/desc|bio|summary|content/i.test(varName)) {
                fields.push({ kind: "text", width: "w-full", height: "h-4" });
            }
            else if (/date|time|created|updated/i.test(varName)) {
                fields.push({ kind: "date", width: "w-24", height: "h-4" });
            }
            else if (/count|total|amount|price|num/i.test(varName)) {
                fields.push({ kind: "numeric", width: "w-12", height: "h-6", rounded: "rounded-md" });
            }
            else {
                fields.push({ kind: "text", width: "w-1/2", height: "h-4" });
            }
        }
        return fields;
    }
    // ─── Private: Skeleton Generators ───────────────────────────────
    generateCardSkeleton(name, fields) {
        const fieldJsx = fields.map(f => {
            const cls = [f.height, f.width, f.rounded].filter(Boolean).join(" ");
            return `      <Skeleton className="${cls}" />`;
        }).join("\n");
        return [
            `function ${name}() {`,
            `  return (`,
            `    <div className="rounded-lg border p-4">`,
            `      <div className="flex items-start gap-3">`,
            fields.some(f => f.kind === "avatar")
                ? `        <Skeleton className="h-10 w-10 rounded-full shrink-0" />`
                : "",
            `        <div className="flex-1 space-y-2">`,
            fieldJsx,
            `        </div>`,
            `      </div>`,
            `    </div>`,
            `  );`,
            `}\n`,
        ].filter(Boolean).join("\n");
    }
    generateTableSkeleton(fields) {
        const cellSkeletons = fields
            .map(() => `                <td className="p-3"><Skeleton className="h-4 w-24" /></td>`)
            .join("\n");
        const headerPlaceholders = fields
            .map((_, i) => `              <th className="p-3 text-left text-sm font-medium text-muted-foreground">Column ${i + 1}</th>`)
            .join("\n");
        return [
            `        <div className="rounded-md border">`,
            `          <table className="w-full">`,
            `            <thead className="border-b bg-muted/50">`,
            `              <tr>`,
            headerPlaceholders,
            `              </tr>`,
            `            </thead>`,
            `            <tbody>`,
            `              {[1, 2, 3].map((i) => (`,
            `                <tr key={i} className="border-b last:border-0">`,
            cellSkeletons,
            `                </tr>`,
            `              ))}`,
            `            </tbody>`,
            `          </table>`,
            `        </div>`,
        ].join("\n");
    }
    generateStatsSkeleton(fields) {
        return [
            `        <div className="grid grid-cols-2 gap-3">`,
            `          {[1, 2, 3, 4].map((i) => (`,
            `            <div key={i} className="rounded-xl border bg-card p-3">`,
            `              <span className="text-xs font-bold text-muted-foreground">Stat</span>`,
            `              <Skeleton className="h-6 w-12 rounded-md mt-1" />`,
            `            </div>`,
            `          ))}`,
            `        </div>`,
        ].join("\n");
    }
    generateDetailSkeleton(fields) {
        const fieldJsx = fields.map(f => {
            const cls = [f.height, f.width, f.rounded].filter(Boolean).join(" ");
            return `          <Skeleton className="${cls}" />`;
        }).join("\n");
        return [
            `        <div className="space-y-4">`,
            fieldJsx,
            `        </div>`,
        ].join("\n");
    }
    generateFormSkeleton(fields) {
        const fieldJsx = fields.map(() => [
            `            <div className="space-y-2">`,
            `              <Skeleton className="h-4 w-1/4" />`,
            `              <Skeleton className="h-10 w-full rounded-md" />`,
            `            </div>`,
        ].join("\n")).join("\n");
        return [
            `        <div className="space-y-6">`,
            fieldJsx,
            `          <div className="flex justify-end gap-4">`,
            `            <Skeleton className="h-10 w-24 rounded-md" />`,
            `            <Skeleton className="h-10 w-32 rounded-md" />`,
            `          </div>`,
            `        </div>`,
        ].join("\n");
    }
    generateFilterSkeleton() {
        return [
            `        <div className="flex items-center gap-3">`,
            `          <Skeleton className="h-10 w-32 rounded-md" />`,
            `          <Skeleton className="h-10 w-32 rounded-md" />`,
            `        </div>`,
        ].join("\n");
    }
    // ─── Private: Skeleton File Management ──────────────────────────
    async getSkeletonsFilePath() {
        const candidates = [
            "components/ui/page-skeletons.tsx",
            "src/components/ui/page-skeletons.tsx",
        ];
        for (const c of candidates) {
            if (await this.fileExists(c))
                return c;
        }
        // Default: match project structure
        return (await this.fileExists("src/components"))
            ? "src/components/ui/page-skeletons.tsx"
            : "components/ui/page-skeletons.tsx";
    }
    async hasSkeletonExport(name) {
        const filePath = await this.getSkeletonsFilePath();
        const content = await this.readFile(filePath);
        if (!content)
            return false;
        return content.includes(`export function ${name}`);
    }
    resolveImportPath(fromDir, toFile) {
        if (toFile.startsWith("src/")) {
            return "@/" + toFile.replace(/^src\//, "").replace(/\.tsx$/, "");
        }
        return "@/" + toFile.replace(/\.tsx$/, "");
    }
    async getParentLayoutClasses(filePath) {
        const classes = [];
        let dir = path.dirname(filePath);
        const appDir = await this.findAppDir();
        if (!appDir)
            return classes;
        while (dir !== appDir && dir !== "." && dir !== "") {
            dir = path.dirname(dir);
            const layoutPath = path.join(dir, "layout.tsx");
            const content = await this.readFile(layoutPath);
            if (content) {
                const wrapperMatch = /className=["']([^"']+)["']/.exec(content);
                if (wrapperMatch?.[1]) {
                    classes.push(wrapperMatch[1]);
                }
            }
        }
        return classes;
    }
}
exports.SkeletonService = SkeletonService;
//# sourceMappingURL=SkeletonService.js.map