import { createFileRoute } from "@tanstack/react-router";
import { useEffect, useMemo, useState } from "react";
import JSZip from "jszip";
import { PageShell } from "@/components/page-shell";
import { toolSeo } from "@/lib/tool-seo";

export const Route = createFileRoute("/tools/website-builder")({
  head: () =>
    toolSeo({
      path: "/tools/website-builder",
      title: "AI Website Builder — Generate 100+ page sites in any stack | Gatavase AI Creative",
      shortTitle: "AI Website Builder — Gatavase AI Creative",
      description:
        "Build a real, standalone website inside Gatavase AI Creative — no external editor, no vendor lock-in. Pick a template, choose how many pages you need (from a single landing page to more than 100), select a visual style and a stack — plain HTML/CSS/JS, Bootstrap, Tailwind, TypeScript, PHP, Python/Flask, Node/Express or React — and let the AI plan and write every page, stylesheet, script, form and backend file for you. Edit any file in the browser with a live preview, then download the finished project as a ZIP you can host anywhere: GitHub Pages, Netlify, cPanel, shared PHP hosting or your own server. Built in Uganda by Gatavase Corporation for hustlers, NGOs, churches, schools and agencies who want a professional, mobile-friendly, fullstack-ready presence without hiring a developer.",
      ogDescription: "Plan and generate 100+ page websites in HTML, Bootstrap, TypeScript, PHP, Python and more — edit live and download as ZIP.",
      category: "WebApplication",
    }),
  component: WebsiteBuilder,
});

/* ------------------------------------------------------------------ */
/* Templates, stacks and styles                                        */
/* ------------------------------------------------------------------ */

type Template = {
  id: string;
  name: string;
  blurb: string;
  pages: string[];
};

const TEMPLATES: Template[] = [
  { id: "business", name: "Business / Corporate", blurb: "Company site with services and contact.", pages: ["index", "about", "services", "team", "pricing", "contact"] },
  { id: "shop", name: "Online Shop", blurb: "Catalogue, product pages, cart and checkout.", pages: ["index", "shop", "product", "cart", "checkout", "shipping", "contact"] },
  { id: "portfolio", name: "Creative Portfolio", blurb: "Showcase work, case studies and a CV.", pages: ["index", "work", "case-study", "about", "cv", "contact"] },
  { id: "blog", name: "Blog / Magazine", blurb: "Article index, categories and post pages.", pages: ["index", "articles", "post", "categories", "authors", "about", "contact"] },
  { id: "ngo", name: "NGO / Church / Community", blurb: "Programmes, donations, events and volunteers.", pages: ["index", "about", "programmes", "events", "donate", "volunteer", "gallery", "contact"] },
  { id: "school", name: "School / Institution", blurb: "Admissions, academics, staff and news.", pages: ["index", "about", "academics", "admissions", "staff", "news", "gallery", "contact"] },
  { id: "restaurant", name: "Restaurant / Café", blurb: "Menu, reservations, gallery and location.", pages: ["index", "menu", "reservations", "gallery", "about", "contact"] },
  { id: "saas", name: "SaaS / Startup", blurb: "Product, features, pricing, docs and signup.", pages: ["index", "features", "pricing", "docs", "changelog", "login", "signup", "contact"] },
  { id: "events", name: "Events / Conference", blurb: "Schedule, speakers, tickets and venue.", pages: ["index", "schedule", "speakers", "tickets", "venue", "sponsors", "contact"] },
  { id: "realestate", name: "Real Estate", blurb: "Listings, property details and enquiries.", pages: ["index", "listings", "property", "agents", "mortgage", "contact"] },
  { id: "medical", name: "Clinic / Health", blurb: "Departments, doctors, booking and insurance.", pages: ["index", "departments", "doctors", "book", "insurance", "contact"] },
  { id: "personal", name: "Personal Brand", blurb: "Bio, speaking, media kit and newsletter.", pages: ["index", "about", "speaking", "media", "newsletter", "contact"] },
];

type Stack = {
  id: string;
  name: string;
  ext: string;
  note: string;
  fullstack: boolean;
};

const STACKS: Stack[] = [
  { id: "html", name: "HTML + CSS + JavaScript", ext: "html", note: "Static site, works on any host.", fullstack: false },
  { id: "bootstrap", name: "Bootstrap 5 (CDN)", ext: "html", note: "Responsive grid & components.", fullstack: false },
  { id: "tailwind", name: "Tailwind CSS (CDN)", ext: "html", note: "Utility-first styling.", fullstack: false },
  { id: "php", name: "PHP (fullstack)", ext: "php", note: "Includes, form handling, MySQL-ready.", fullstack: true },
  { id: "typescript", name: "TypeScript + Vite", ext: "ts", note: "Typed frontend modules.", fullstack: false },
  { id: "react", name: "React (JSX)", ext: "jsx", note: "Component-based SPA pages.", fullstack: false },
  { id: "node", name: "Node.js + Express (fullstack)", ext: "ejs", note: "Server routes, EJS views, API.", fullstack: true },
  { id: "python", name: "Python + Flask (fullstack)", ext: "html", note: "Jinja templates, routes, forms.", fullstack: true },
  { id: "astro", name: "Astro", ext: "astro", note: "Content-first static output.", fullstack: false },
];

const STYLES = [
  "Modern minimal",
  "Bold Ugandan / Afro-futuristic",
  "Corporate professional",
  "Dark neon tech",
  "Warm editorial",
  "Playful & colourful",
  "Luxury elegant",
  "Brutalist",
];

const FEATURES = [
  "Responsive mobile-first layout",
  "Contact & enquiry forms with validation",
  "Image galleries with lazy loading",
  "Navigation with active states",
  "SEO meta tags & JSON-LD",
  "Accessibility (ARIA, contrast)",
  "Dark mode toggle",
  "Newsletter signup",
  "Search / filtering",
  "Backend API endpoints",
  "Database schema (SQL)",
  "Authentication pages",
];

const LOCALES = ["English", "Luganda", "Swahili", "French", "Arabic", "Spanish", "Portuguese"];

/* ------------------------------------------------------------------ */

type Files = Record<string, string>;

const STARTER_HTML = `<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>My Gatavase site</title>
  <link rel="stylesheet" href="style.css" />
</head>
<body>
  <header><h1>Karibu 👋</h1><p>Pick a template above and let the AI build your pages, or edit these files directly.</p></header>
  <main><button id="btn">Click me</button><p id="msg"></p></main>
  <script src="app.js"></script>
</body>
</html>`;

const STARTER_CSS = `:root { color-scheme: dark; }
body { font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; background: #0f0a1f; color: #f4efff; margin: 0; padding: 2rem; }
header h1 { font-size: 2.5rem; background: linear-gradient(90deg,#c084fc,#f59e0b,#ef4444); -webkit-background-clip: text; color: transparent; }
button { background: #7c3aed; color: white; border: 0; padding: .75rem 1.5rem; border-radius: 9999px; font-weight: 600; cursor: pointer; }`;

const STARTER_JS = `document.getElementById("btn").addEventListener("click", () => {
  document.getElementById("msg").textContent = "Hello from your Gatavase site! " + new Date().toLocaleTimeString();
});`;

function extractBlock(text: string, langs: string[]) {
  for (const l of langs) {
    const m = new RegExp("```" + l + "\\s*([\\s\\S]*?)```", "i").exec(text);
    if (m?.[1]) return m[1].trim();
  }
  const any = /```[a-z]*\s*([\s\S]*?)```/i.exec(text);
  return any?.[1]?.trim() ?? text.trim();
}

function WebsiteBuilder() {
  const [files, setFiles] = useState<Files>({
    "index.html": STARTER_HTML,
    "style.css": STARTER_CSS,
    "app.js": STARTER_JS,
  });
  const [active, setActive] = useState("index.html");

  const [brief, setBrief] = useState("");
  const [templateId, setTemplateId] = useState("business");
  const [stackId, setStackId] = useState("html");
  const [style, setStyle] = useState(STYLES[1]);
  const [pageCount, setPageCount] = useState(6);
  const [features, setFeatures] = useState<string[]>([FEATURES[0], FEATURES[1], FEATURES[4]]);
  const [locales, setLocales] = useState<string[]>(["English"]);

  const [plan, setPlan] = useState<Array<{ slug: string; title: string; purpose: string }> | null>(null);
  const [busy, setBusy] = useState<null | string>(null);
  const [progress, setProgress] = useState({ done: 0, total: 0 });
  const [error, setError] = useState<string | null>(null);

  const stack = STACKS.find((s) => s.id === stackId)!;
  const template = TEMPLATES.find((t) => t.id === templateId)!;

  /* ---------------- preview ---------------- */
  const previewDoc = useMemo(() => {
    const src = files[active] ?? "";
    if (!/\.(html|php|astro|ejs)$/i.test(active)) return "";
    const css = Object.entries(files).filter(([n]) => n.endsWith(".css")).map(([, c]) => c).join("\n");
    const js = Object.entries(files).filter(([n]) => n.endsWith(".js") && !n.includes("server")).map(([, c]) => c).join("\n");
    return src
      .replace(/<\?php[\s\S]*?\?>/g, "")
      .replace(/{%[\s\S]*?%}/g, "")
      .replace(/<link\s+[^>]*href=["'][^"']*\.css["'][^>]*>/gi, `<style>${css}</style>`)
      .replace(/<script\s+[^>]*src=["'][^"']*\.js["'][^>]*><\/script>/gi, `<script>${js}<\/script>`);
  }, [files, active]);

  const [debounced, setDebounced] = useState(previewDoc);
  useEffect(() => {
    const t = setTimeout(() => setDebounced(previewDoc), 300);
    return () => clearTimeout(t);
  }, [previewDoc]);

  /* ---------------- generation ---------------- */

  const baseContext = () =>
    `Brief: """${brief || template.blurb}"""
Template: ${template.name}
Visual style: ${style}
Stack: ${stack.name}${stack.fullstack ? " (include backend files)" : ""}
Required features: ${features.join(", ") || "standard"}
Content languages: ${locales.join(", ")}`;

  async function ai(prompt: string) {
    const { generateText } = await import("@/lib/ai.functions");
    const res = await generateText({ data: { kind: "document", prompt } });
    return res.text;
  }

  async function buildPlan() {
    setBusy("Planning pages…");
    setError(null);
    try {
      const text = await ai(
        `${baseContext()}

Plan exactly ${pageCount} pages for this website. Suggested starting points: ${template.pages.join(", ")}. Invent additional meaningful pages (sub-services, locations, categories, legal pages, landing pages) until you reach ${pageCount}.

Return ONLY a JSON array in a \`\`\`json code block, each item: {"slug":"kebab-case","title":"Page title","purpose":"one sentence"}. The first item MUST have slug "index".`,
      );
      const raw = extractBlock(text, ["json"]);
      const parsed = JSON.parse(raw) as Array<{ slug: string; title: string; purpose: string }>;
      const cleaned = parsed
        .filter((p) => p && typeof p.slug === "string")
        .map((p) => ({ slug: p.slug.replace(/[^a-z0-9-]/gi, "-").toLowerCase(), title: p.title ?? p.slug, purpose: p.purpose ?? "" }))
        .slice(0, pageCount);
      if (cleaned.length === 0) throw new Error("Empty plan");
      setPlan(cleaned);
    } catch (e) {
      setError(e instanceof Error ? `Planning failed: ${e.message}` : "Planning failed");
    } finally {
      setBusy(null);
    }
  }

  async function buildShared() {
    const text = await ai(
      `${baseContext()}

Write the SHARED assets for this site in the "${style}" style.
Return exactly two fenced blocks and nothing else:
\`\`\`css
/* complete, production-quality stylesheet: layout, typography, nav, hero, cards, forms, footer, responsive breakpoints, dark mode if requested */
\`\`\`
\`\`\`js
// shared JS: mobile nav toggle, form validation, gallery lazy loading, any interactivity for the required features
\`\`\``,
    );
    const css = extractBlock(text, ["css"]);
    const js = /```(?:js|javascript)\s*([\s\S]*?)```/i.exec(text)?.[1]?.trim() ?? "";
    return { css, js };
  }

  async function buildPage(p: { slug: string; title: string; purpose: string }, nav: string[]) {
    const filename = `${p.slug}.${stack.ext === "ts" ? "html" : stack.ext}`;
    const text = await ai(
      `${baseContext()}

Write the complete file "${filename}" for the page "${p.title}" (${p.purpose}).
Site navigation (link to these): ${nav.join(", ")}.
Rules:
- Full, valid, production-ready ${stack.name} code — no placeholders like "lorem ipsum" and no TODOs.
- Realistic written copy in ${locales[0]}${locales.length > 1 ? ` (add a language switcher for ${locales.slice(1).join(", ")})` : ""}.
- Link the shared stylesheet "style.css" and script "app.js".
- Use semantic HTML, accessible markup, responsive layout, real form fields where relevant, and <img> tags with descriptive alt text using https://picsum.photos placeholders.
- Include SEO title/meta description and Open Graph tags.
${stack.fullstack ? "- Include server-side handling appropriate to the stack (form POST handling, includes/partials, DB queries)." : ""}

Return ONLY one fenced code block with the file contents.`,
    );
    return { filename, content: extractBlock(text, ["html", "php", "jsx", "tsx", "astro", "ejs", "python", "js"]) };
  }

  async function buildBackend() {
    const text = await ai(
      `${baseContext()}

Write the BACKEND for this site using ${stack.name}. Return separate fenced blocks, each preceded by a line "FILE: <path>", covering: the server/entry file, a form/contact handler, a small data/API endpoint, database schema SQL, and a README with setup and deployment steps.`,
    );
    const out: Files = {};
    const re = /FILE:\s*([^\n`]+)\n+```[a-z]*\s*([\s\S]*?)```/gi;
    let m: RegExpExecArray | null;
    while ((m = re.exec(text))) out[m[1].trim().replace(/^\/+/, "")] = m[2].trim();
    return out;
  }

  async function generateSite() {
    const pages = plan;
    if (!pages) return;
    setError(null);
    setProgress({ done: 0, total: pages.length + (stack.fullstack ? 2 : 1) });
    const next: Files = {};
    try {
      setBusy("Generating shared styles & scripts…");
      const shared = await buildShared();
      if (shared.css) next["style.css"] = shared.css;
      if (shared.js) next["app.js"] = shared.js;
      setProgress((p) => ({ ...p, done: p.done + 1 }));

      const nav = pages.map((p) => `${p.slug}.${stack.ext === "ts" ? "html" : stack.ext}`);

      // Generate in small parallel batches so 100+ page sites finish in reasonable time.
      const BATCH = 4;
      for (let i = 0; i < pages.length; i += BATCH) {
        const slice = pages.slice(i, i + BATCH);
        setBusy(`Writing pages ${i + 1}–${Math.min(i + BATCH, pages.length)} of ${pages.length}…`);
        const results = await Promise.all(
          slice.map((p) =>
            buildPage(p, nav).catch((e) => ({
              filename: `${p.slug}.${stack.ext === "ts" ? "html" : stack.ext}`,
              content: `<!-- Generation failed for ${p.slug}: ${e instanceof Error ? e.message : "error"} -->`,
            })),
          ),
        );
        for (const r of results) next[r.filename] = r.content;
        setProgress((prev) => ({ ...prev, done: prev.done + slice.length }));
        setFiles((f) => ({ ...f, ...next }));
      }

      if (stack.fullstack || features.includes("Backend API endpoints") || features.includes("Database schema (SQL)")) {
        setBusy("Generating backend & database files…");
        const backend = await buildBackend();
        Object.assign(next, backend);
        setProgress((p) => ({ ...p, done: p.done + 1 }));
      }

      setFiles((f) => {
        const merged = { ...f, ...next };
        return merged;
      });
      const first = Object.keys(next).find((n) => n.startsWith("index."));
      if (first) setActive(first);
    } catch (e) {
      setError(e instanceof Error ? e.message : "Generation failed");
    } finally {
      setBusy(null);
    }
  }

  async function download() {
    const zip = new JSZip();
    Object.entries(files).forEach(([name, content]) => zip.file(name, content));
    if (!files["README.md"]) {
      zip.file(
        "README.md",
        `# ${template.name} website built with Gatavase AI Creative\n\nStack: ${stack.name}\nPages: ${Object.keys(files).filter((f) => /\.(html|php|astro|ejs|jsx)$/.test(f)).length}\n\nUpload these files to any host (Netlify, Vercel, GitHub Pages, cPanel${stack.fullstack ? ", or a PHP/Node/Python server" : ""}).\n`,
      );
    }
    const blob = await zip.generateAsync({ type: "blob" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = "gatavase-website.zip";
    a.click();
    setTimeout(() => URL.revokeObjectURL(url), 1000);
  }

  const fileNames = Object.keys(files).sort();
  const pct = progress.total ? Math.round((progress.done / progress.total) * 100) : 0;

  return (
    <PageShell
      eyebrow="Development · Website Builder"
      title="Build a real website — any stack, any size"
      lead="Pick a template, choose how many pages you need (1 to 100+), select a style and a stack — HTML, Bootstrap, Tailwind, TypeScript, PHP, React, Node or Python — then edit everything live and download the project as a ZIP."
    >
      {/* Configurator */}
      <div className="glow-card mb-6 space-y-4 rounded-2xl p-5">
        <div>
          <label className="mb-1 block text-xs font-medium text-muted-foreground">Describe your website</label>
          <textarea
            rows={2}
            value={brief}
            onChange={(e) => setBrief(e.target.value)}
            placeholder="e.g. Naiga Coffee — a Ugandan single-origin roaster in Mbale selling beans online and hosting cupping events…"
            className="w-full resize-none rounded-lg border border-border bg-input px-3 py-2 text-sm outline-none focus:border-primary"
          />
        </div>

        <div>
          <div className="mb-2 text-xs font-medium text-muted-foreground">Template</div>
          <div className="grid gap-2 sm:grid-cols-2 lg:grid-cols-3">
            {TEMPLATES.map((t) => (
              <button
                key={t.id}
                onClick={() => { setTemplateId(t.id); setPageCount(Math.max(pageCount, t.pages.length)); }}
                className={`rounded-xl border p-3 text-left text-sm transition ${templateId === t.id ? "border-primary bg-primary/10" : "border-border hover:bg-card"}`}
              >
                <div className="font-medium">{t.name}</div>
                <div className="text-xs text-muted-foreground">{t.blurb}</div>
              </button>
            ))}
          </div>
        </div>

        <div className="grid gap-4 md:grid-cols-3">
          <div>
            <label className="mb-1 block text-xs font-medium text-muted-foreground">Stack / language</label>
            <select value={stackId} onChange={(e) => setStackId(e.target.value)} className="w-full rounded-lg border border-border bg-input px-3 py-2 text-sm">
              {STACKS.map((s) => (
                <option key={s.id} value={s.id}>{s.name}</option>
              ))}
            </select>
            <div className="mt-1 text-xs text-muted-foreground">{stack.note}</div>
          </div>
          <div>
            <label className="mb-1 block text-xs font-medium text-muted-foreground">Visual style</label>
            <select value={style} onChange={(e) => setStyle(e.target.value)} className="w-full rounded-lg border border-border bg-input px-3 py-2 text-sm">
              {STYLES.map((s) => <option key={s}>{s}</option>)}
            </select>
          </div>
          <div>
            <label className="mb-1 block text-xs font-medium text-muted-foreground">Number of pages: {pageCount}</label>
            <input
              type="range" min={1} max={120} value={pageCount}
              onChange={(e) => setPageCount(Number(e.target.value))}
              className="w-full accent-primary"
            />
            <input
              type="number" min={1} max={250} value={pageCount}
              onChange={(e) => setPageCount(Math.min(250, Math.max(1, Number(e.target.value) || 1)))}
              className="mt-1 w-24 rounded-lg border border-border bg-input px-2 py-1 text-sm"
            />
            <div className="mt-1 text-xs text-muted-foreground">Up to 250 pages. Large sites generate in batches.</div>
          </div>
        </div>

        <div className="grid gap-4 md:grid-cols-2">
          <div>
            <div className="mb-2 text-xs font-medium text-muted-foreground">Requirements</div>
            <div className="flex flex-wrap gap-2">
              {FEATURES.map((f) => {
                const on = features.includes(f);
                return (
                  <button
                    key={f}
                    onClick={() => setFeatures(on ? features.filter((x) => x !== f) : [...features, f])}
                    className={`rounded-full border px-3 py-1 text-xs transition ${on ? "border-primary bg-primary/15 text-foreground" : "border-border text-muted-foreground hover:bg-card"}`}
                  >
                    {f}
                  </button>
                );
              })}
            </div>
          </div>
          <div>
            <div className="mb-2 text-xs font-medium text-muted-foreground">Content languages</div>
            <div className="flex flex-wrap gap-2">
              {LOCALES.map((l) => {
                const on = locales.includes(l);
                return (
                  <button
                    key={l}
                    onClick={() => setLocales(on ? locales.filter((x) => x !== l) || ["English"] : [...locales, l])}
                    className={`rounded-full border px-3 py-1 text-xs transition ${on ? "border-primary bg-primary/15 text-foreground" : "border-border text-muted-foreground hover:bg-card"}`}
                  >
                    {l}
                  </button>
                );
              })}
            </div>
          </div>
        </div>

        <div className="flex flex-wrap items-center gap-3">
          <button onClick={buildPlan} disabled={!!busy} className="rounded-lg border border-primary px-5 py-2 text-sm font-medium text-primary disabled:opacity-50">
            1 · Plan {pageCount} pages
          </button>
          <button onClick={generateSite} disabled={!!busy || !plan} className="rounded-lg bg-primary px-5 py-2 text-sm font-medium text-primary-foreground disabled:opacity-50">
            2 · Generate website
          </button>
          <button onClick={download} className="rounded-lg border border-border px-5 py-2 text-sm hover:bg-card">Download ZIP</button>
          {busy && <span className="text-sm text-muted-foreground">{busy}</span>}
        </div>

        {progress.total > 0 && (
          <div className="h-2 w-full overflow-hidden rounded-full bg-card">
            <div className="h-full bg-primary transition-all" style={{ width: `${pct}%` }} />
          </div>
        )}

        {error && <div className="rounded-lg border border-destructive/50 bg-destructive/10 px-3 py-2 text-sm text-destructive">{error}</div>}

        {plan && (
          <div className="rounded-xl border border-border bg-background/50 p-3">
            <div className="mb-2 text-xs uppercase tracking-widest text-muted-foreground">Planned pages ({plan.length})</div>
            <div className="flex max-h-40 flex-wrap gap-1.5 overflow-y-auto">
              {plan.map((p) => (
                <span key={p.slug} className="rounded-full border border-border px-2.5 py-1 text-xs text-muted-foreground" title={p.purpose}>
                  {p.slug}
                </span>
              ))}
            </div>
          </div>
        )}
      </div>

      {/* Editor + preview */}
      <div className="grid gap-6 lg:grid-cols-[220px,1fr,1fr]">
        <div className="glow-card rounded-2xl p-3">
          <div className="mb-2 px-1 text-xs uppercase tracking-widest text-muted-foreground">Files ({fileNames.length})</div>
          <ul className="max-h-[520px] space-y-0.5 overflow-y-auto">
            {fileNames.map((n) => (
              <li key={n}>
                <button
                  onClick={() => setActive(n)}
                  className={`w-full truncate rounded-md px-2 py-1.5 text-left font-mono text-xs ${active === n ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-card"}`}
                >
                  {n}
                </button>
              </li>
            ))}
          </ul>
        </div>

        <div className="glow-card rounded-2xl p-4">
          <div className="mb-3 flex items-center justify-between">
            <div className="truncate font-mono text-xs text-muted-foreground">{active}</div>
            <button
              onClick={() => {
                const name = prompt("New file name (e.g. contact.php)");
                if (name) { setFiles({ ...files, [name]: "" }); setActive(name); }
              }}
              className="rounded-lg border border-border px-2 py-1 text-xs hover:bg-card"
            >
              + File
            </button>
          </div>
          <textarea
            value={files[active] ?? ""}
            onChange={(e) => setFiles({ ...files, [active]: e.target.value })}
            spellCheck={false}
            className="h-[520px] w-full resize-none rounded-lg border border-border bg-background/60 p-3 font-mono text-xs text-foreground outline-none focus:border-primary"
          />
        </div>

        <div className="glow-card rounded-2xl p-4">
          <div className="mb-3 text-xs uppercase tracking-widest text-muted-foreground">Live preview</div>
          {debounced ? (
            <iframe title="Preview" srcDoc={debounced} sandbox="allow-scripts" className="h-[520px] w-full rounded-lg border border-border bg-white" />
          ) : (
            <div className="flex h-[520px] items-center justify-center rounded-lg border border-border bg-background/40 text-sm text-muted-foreground">
              Select an HTML/PHP page to preview it.
            </div>
          )}
        </div>
      </div>
    </PageShell>
  );
}
