#!/usr/bin/env node
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { dirname, relative, resolve } from "node:path";
import { fileURLToPath } from "node:url";

const cwd = process.cwd();
const args = parseArgs(process.argv.slice(2));
const packageRoot = resolve(fileURLToPath(new URL("..", import.meta.url)));
const ownPackage = readJson(resolve(packageRoot, "package.json")) ?? {};
const defaultBackendUrl = "https://service.orderly.shop";
const shopName = args.name ?? "Orderly Butik";
const targetRoot = resolve(cwd, args.path ?? ".");
const force = Boolean(args.force);
const dryRun = Boolean(args["dry-run"]);
const skipPackageJson = Boolean(args["skip-package-json"]);

if (args.help || args.h) {
  printHelp();
  process.exit(0);
}

const config = {
  accountId: args["account-id"],
  backendUrl: args["base-url"] ?? defaultBackendUrl,
  legalOwnerName: args["legal-owner-name"] ?? shopName,
  legalOwnerCvr: args["legal-owner-cvr"] ?? "",
  packageName: args["package-name"] ?? slugPackageName(shopName),
  shopName
};
const files = scaffoldFiles(config);
const packageJsonPath = resolve(targetRoot, "package.json");
const planned = [...files.map((file) => file.path)];
if (!skipPackageJson) {
  planned.push("package.json");
}

if (dryRun) {
  console.log(`Would initialize ${shopName} in ${relative(cwd, targetRoot) || "."}.`);
  for (const file of planned) {
    console.log(`- ${file}`);
  }
  process.exit(0);
}

mkdirSync(targetRoot, { recursive: true });
for (const file of files) {
  const target = resolve(targetRoot, file.path);
  const relativeTarget = relative(cwd, target);
  const targetExists = existsSync(target);
  if (targetExists && !force) {
    console.warn(`Warning: ${relativeTarget} already exists; leaving it unchanged. Re-run with --force to overwrite.`);
    continue;
  }
  mkdirSync(dirname(target), { recursive: true });
  writeFileSync(target, file.content, "utf8");
  console.log(`${targetExists ? "Overwrote" : "Created"} ${relativeTarget}.`);
}

if (!skipPackageJson) {
  const packageJsonExists = existsSync(packageJsonPath);
  const nextPackageJson = packageJsonSource(packageJsonPath, config);
  writeFileSync(packageJsonPath, `${JSON.stringify(nextPackageJson, null, 2)}\n`, "utf8");
  console.log(`${packageJsonExists ? "Updated" : "Created"} ${relative(cwd, packageJsonPath)}.`);
}

console.log(`\nNext steps:
  npm install
  npm run dev

Then open the local Vite URL and start customizing src/navigation.ts, src/style.css, and src/templates/*.html.`);

function scaffoldFiles(options) {
  return [
    { path: ".gitignore", content: gitignoreSource(), skipIfExists: true },
    { path: "AGENTS.md", content: agentsSource(), skipIfExists: true },
    { path: "README.md", content: readmeSource(options), skipIfExists: true },
    { path: "tsconfig.json", content: tsconfigSource() },
    { path: "vite.config.mjs", content: viteConfigSource() },
    { path: "src/index.html", content: pageSource({ title: options.shopName, element: homeElementSource() }) },
    { path: "src/category.html", content: pageSource({ title: `Kategori | ${options.shopName}`, element: "<orderly-category-page></orderly-category-page>" }) },
    { path: "src/product.html", content: pageSource({ title: `Produkt | ${options.shopName}`, element: productDetailElementSource() }) },
    { path: "src/checkout.html", content: pageSource({ title: `Betaling | ${options.shopName}`, element: checkoutElementSource() }) },
    { path: "src/payment-success.html", content: pageSource({ title: `Tak for din ordre | ${options.shopName}`, element: paymentSuccessElementSource() }) },
    { path: "src/payment-failure.html", content: pageSource({ title: `Betaling kunne ikke gennemføres | ${options.shopName}`, element: paymentFailureElementSource() }) },
    { path: "src/includes/head.html", content: headIncludeSource(options) },
    { path: "src/includes/body-start.html", content: bodyStartSource() },
    { path: "src/includes/body-end.html", content: "<!-- Add shared body-end snippets here. -->\n" },
    { path: "src/navigation.ts", content: navigationSource() },
    { path: "src/shop-query.ts", content: shopQuerySource(options) },
    { path: "src/style.css", content: styleSource() },
    { path: "src/templates/shop-footer.html", content: shopFooterTemplateSource(options) },
    { path: "src/templates/product-tile.html", content: productTileTemplateSource() },
    { path: "src/templates/product-page.html", content: productPageTemplateSource() },
    { path: "src/templates/basket.html", content: basketTemplateSource() }
  ];
}

function packageJsonSource(file, options) {
  const existing = readJson(file);
  const packageJson = existing ?? {
    name: options.packageName,
    version: "0.1.0",
    private: true,
    type: "module"
  };
  packageJson.type ??= "module";
  packageJson.scripts = {
    dev: "vite",
    build: "orderly-build-category-pages --build-command \"tsc --noEmit && vite build\" && orderly-generate-server-renderers",
    preview: "vite preview",
    "generate:categories": "orderly-generate-category-pages",
    "clean:categories": "orderly-generate-category-pages --clean",
    "build:category-pages": "orderly-build-category-pages --build-command \"tsc --noEmit && vite build\" && orderly-generate-server-renderers",
    ...(packageJson.scripts ?? {})
  };
  packageJson.dependencies = {
    "@orderlyshop/core-client": ownPackage.dependencies?.["@orderlyshop/core-client"] ?? "^0.1.0",
    "@orderlyshop/web-components": `^${ownPackage.version ?? "0.1.0"}`,
    ...(packageJson.dependencies ?? {})
  };
  packageJson.devDependencies = {
    typescript: ownPackage.devDependencies?.typescript ?? "^5.9.3",
    vite: "^7.3.2",
    ...(packageJson.devDependencies ?? {})
  };
  return packageJson;
}

function gitignoreSource() {
  return `node_modules
dist
.env
.DS_Store
`;
}

function agentsSource() {
  return `# Agent Guide

- This shop was scaffolded with \`npx orderly-init-shop\` from \`@orderlyshop/web-components\`.
- These instructions are optimized for GPT-5.5-class coding agents. Work from the requested storefront outcome, keep changes narrow, and verify with the nearest shop script.
- Read \`node_modules/@orderlyshop/web-components/AGENTS.md\`, \`DESIGN.md\`, \`docs/components/README.md\`, and \`docs/search-syntax.md\` before changing package integration patterns.
- Ask the user for the Orderly account id, legal webshop owner name, legal owner CVR, and a reference website URL for the desired visual style before customizing the scaffold.
- Keep storefront logic in Orderly web components. Customize navigation, content, templates, and CSS instead of replacing package components.
- Start visual theming from the package \`DESIGN.md\` semantic tokens before using component-local selectors.
- Use the reference website as design direction for palette, radius, spacing, density, typography feel, and navigation treatment. Do not copy proprietary assets, text, logos, or brand marks unless the user confirms they own or may use them.
- Configure shop-wide backend, default query, navigation, page layout, and component registration in \`src/includes/head.html\` through \`configureShop(...)\`.
- Configure legal owner name and CVR in \`src/includes/head.html\` through \`defaultShop.legalOwnerName\` and \`defaultShop.legalOwnerCvr\`.
- Use \`src/navigation.ts\` for category/navigation structure. Every category needs a stable globally unique \`slug\`.
- Use \`src/shop-query.ts\` for the shop-wide Core \`SearchQuery\`, such as tenant/account scoping.
- Put shop-specific component templates in \`src/templates/*.html\` and include them from \`src/includes/body-start.html\`.
- \`npm run dev\` serves product/category URLs with package SSR by default, so View Source shows semantic product/category HTML.
- \`npm run build\` generates real category URL files, hydrates built homepage/category pages, and emits PHP SSR renderers for product/category URLs.
- Use \`npm run generate:categories\` for local source inspection and \`npm run clean:categories\` to remove generated source pages.
`;
}

function readmeSource(options) {
  return `# ${options.shopName}

Vanilla storefront scaffolded with \`@orderlyshop/web-components\`.

## Commands

\`\`\`sh
npm install
npm run dev
npm run build
npm run preview
\`\`\`

Test the shop locally from \`http://localhost:61677\` during normal development, or \`https://localhost:61677\` if a local TLS proxy terminates HTTPS in front of the dev server. Keep the origin on \`localhost:61677\`, because the backend CORS development policy expects that local origin. If live API requests behave differently across local URLs, use \`localhost:61677\`, stop the conflicting process, and avoid \`127.0.0.1\` or random fallback ports.

Dev mode server-renders product and category URLs by default. Open View Source on \`http://localhost:61677/categories/<slug>/\` or \`http://localhost:61677/products/<product-url>/\` to inspect semantic SSR markup. Set \`ORDERLY_DEV_SSR=0\` to debug pure client-side rendering.

Override the backend during local development:

\`\`\`sh
VITE_ORDERLY_BASE_URL=${options.backendUrl} npm run dev
\`\`\`

Production builds generate real category URL pages from \`src/navigation.ts\`, hydrate built homepage/category pages with server-rendered fallback HTML, and emit Apache/PHP SSR renderers:

\`\`\`sh
npm run build
\`\`\`

Use \`npm run generate:categories\` when you want to inspect generated source pages during development. Generated category source pages are removed automatically after \`npm run build\`.

## Customize

- For consistent theming across all components, start with the semantic token contract in \`node_modules/@orderlyshop/web-components/DESIGN.md\`.
- For agent-assisted visual setup, provide a reference website URL. Use it to choose semantic tokens, radius, spacing, and navigation treatment in \`src/style.css\` without copying protected assets or text.
- \`src/navigation.ts\` defines storefront navigation and category queries. Read \`node_modules/@orderlyshop/web-components/docs/search-syntax.md\`; use \`|\` for OR text and avoid multiple tags for alternatives.
- \`src/shop-query.ts\` defines the shop-wide Core \`SearchQuery\`.
- \`src/includes/head.html\` calls \`configureShop(...)\`.
- \`src/includes/head.html\` contains the legal owner name and CVR shown in the required package-owned footer notice.
- \`src/templates/*.html\` contains global component templates.
- \`src/style.css\` owns the shop look and feel.
- The default page layout supports desktop horizontal navigation with an inline mobile burger through \`primary-nav-mobile-placement="header"\` plus \`orderly-navigation layout-desktop="horizontal" layout-mobile="burgermenu"\`.
`;
}

function tsconfigSource() {
  return `{
  "compilerOptions": {
    "target": "ES2022",
    "useDefineForClassFields": true,
    "module": "ES2022",
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
    "types": ["vite/client"],
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "isolatedModules": true,
    "moduleDetection": "force",
    "noEmit": true,
    "strict": true
  },
  "include": ["src"]
}
`;
}

function viteConfigSource() {
  return `import { readFileSync, readdirSync, statSync } from "node:fs";
import { dirname, relative, resolve } from "node:path";
import { defineConfig } from "vite";
import { orderlySsrDevServer } from "@orderlyshop/web-components/server/vite";

export default defineConfig({
  server: {
    host: "localhost",
    port: 61677,
    strictPort: true
  },
  preview: {
    host: "localhost",
    port: 61677,
    strictPort: true
  },
  plugins: [htmlIncludes(), orderlySsrDevServer(), rootHtmlOutput()],
  build: {
    rollupOptions: {
      input: htmlInputs()
    }
  }
});

function htmlIncludes() {
  return {
    name: "orderly-html-includes",
    transformIndexHtml: {
      order: "pre",
      handler(html) {
        return html
          .replace("<!-- orderly-head-includes -->", include("head.html"))
          .replace("<!-- orderly-body-start-includes -->", include("body-start.html"))
          .replace("<!-- orderly-body-end-includes -->", include("body-end.html"));
      }
    }
  };
}

function rootHtmlOutput() {
  return {
    name: "orderly-root-html-output",
    enforce: "post",
    generateBundle(_, bundle) {
      for (const [fileName, output] of Object.entries(bundle)) {
        if (!fileName.startsWith("src/") || !fileName.endsWith(".html")) {
          continue;
        }
        delete bundle[fileName];
        output.fileName = fileName.slice("src/".length);
        bundle[output.fileName] = output;
      }
    }
  };
}

function include(fileName) {
  return includeFile(resolve(process.cwd(), "src/includes", fileName));
}

function includeFile(filePath) {
  return expandTemplateIncludes(readFileSync(filePath, "utf8").trim(), dirname(filePath));
}

function expandTemplateIncludes(html, baseDir) {
  return html.replace(/<!--\\s*orderly-include-template:\\s*([^>]+?)\\s*-->/g, (_, templatePath) => {
    return includeFile(resolve(baseDir, templatePath.trim()));
  });
}

function htmlInputs(root = process.cwd()) {
  const inputs = {};
  for (const file of listHtmlFiles(root)) {
    const name = htmlInputName(root, file);
    inputs[name] = file;
  }
  return inputs;
}

function htmlInputName(root, file) {
  const name = relative(root, file).replace(/\\\\/g, "/").replace(/\\.html$/, "");
  return name.startsWith("src/") ? name.slice("src/".length) : name;
}

function listHtmlFiles(dir) {
  const files = [];
  for (const entry of readdirSync(dir)) {
    if (entry === "dist" || entry === "node_modules") {
      continue;
    }
    const fullPath = resolve(dir, entry);
    if (isHtmlPartial(fullPath)) {
      continue;
    }
    const stat = statSync(fullPath);
    if (stat.isDirectory()) {
      files.push(...listHtmlFiles(fullPath));
    } else if (entry.endsWith(".html")) {
      files.push(fullPath);
    }
  }
  return files;
}

function isHtmlPartial(file) {
  const path = relative(process.cwd(), file).replace(/\\\\/g, "/");
  return path.startsWith("src/includes") || path.startsWith("src/templates");
}

`;
}

function pageSource({ title, element }) {
  return `<!doctype html>
<html lang="da">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>${escapeHtml(title)}</title>
    <!-- orderly-head-includes -->
  </head>
  <body>
    <!-- orderly-body-start-includes -->
    ${element}
    <!-- orderly-body-end-includes -->
  </body>
</html>
`;
}

function homeElementSource() {
  return `<orderly-home-page
      eyebrow="Nye varer"
      title="Find næste favorit"
      rail-cta-label="Se alle"
      empty-label="Der blev ikke fundet varer."
      checkout-label="Gå til betaling">
      <div slot="utility" class="shop-utility-strip" aria-label="Kundefordele">
        <span>Hurtig levering</span>
        <span>Nem retur</span>
        <span>Sikker betaling</span>
      </div>
    </orderly-home-page>`;
}

function productDetailElementSource() {
  return `<orderly-product-detail-page
      add-label="Læg i kurven"
      loading-label="Indlæser produkt..."
      not-found-label="Produktet blev ikke fundet."
      error-label="Produktet kunne ikke indlæses.">
      <div slot="utility" class="shop-utility-strip" aria-label="Kundefordele">
        <span>Hurtig levering</span>
        <span>Nem retur</span>
        <span>Sikker betaling</span>
      </div>
    </orderly-product-detail-page>`;
}

function checkoutElementSource() {
  return `<orderly-checkout-page>
      <div slot="utility" class="shop-utility-strip" aria-label="Kundefordele">
        <span>Hurtig levering</span>
        <span>Nem retur</span>
        <span>Sikker betaling</span>
      </div>
    </orderly-checkout-page>`;
}

function paymentSuccessElementSource() {
  return `<orderly-payment-success-page>
      <div slot="utility" class="shop-utility-strip" aria-label="Kundefordele">
        <span>Hurtig levering</span>
        <span>Nem retur</span>
        <span>Sikker betaling</span>
      </div>
    </orderly-payment-success-page>`;
}

function paymentFailureElementSource() {
  return `<orderly-payment-failure-page>
      <div slot="utility" class="shop-utility-strip" aria-label="Kundefordele">
        <span>Hurtig levering</span>
        <span>Nem retur</span>
        <span>Sikker betaling</span>
      </div>
    </orderly-payment-failure-page>`;
}

function headIncludeSource(options) {
  return `<!-- Add shared head snippets here, for example analytics, consent, or preconnect tags. -->
<link rel="icon" href="https://orderly.shop/home/App_Icon.svg" type="image/svg+xml">
<link rel="stylesheet" href="/src/style.css">
<script type="module">
  import { configureShop } from "@orderlyshop/web-components";
  import { navigationDefinitions } from "/src/navigation.ts";
  import { defaultQuery } from "/src/shop-query.ts";

  const categoryUrlMode = import.meta.env.VITE_ORDERLY_CATEGORY_URL_MODE === "hash" ? "hash" : "path";
  const productUrlMode = import.meta.env.VITE_ORDERLY_PRODUCT_URL_MODE === "hash" ? "hash" : "path";
  const googleTagManagerId = import.meta.env.VITE_ORDERLY_GOOGLE_TAG_MANAGER_ID?.trim();
  const productHref = productUrlMode === "hash" ? "/product.html" : "/products/";

  configureShop({
    uiLanguage: "DA",
    defaultShop: {
      baseUrl: import.meta.env.VITE_ORDERLY_BASE_URL ?? ${JSON.stringify(options.backendUrl)},
      defaultQuery,
      brandLabel: ${JSON.stringify(options.shopName)},
      legalOwnerName: ${JSON.stringify(options.legalOwnerName)},
      legalOwnerCvr: ${JSON.stringify(options.legalOwnerCvr)},
      homeHref: "/",
      productHref,
      productUrlMode,
      productPathRoot: "/products/",
      checkoutHref: "/checkout.html",
      navigationDefinitions,
      categoryPageRoot: categoryUrlMode === "hash" ? "/category.html" : "/categories/",
      categoryUrlMode
    },
    pageLayout: {
      logoSrc: "https://orderly.shop/home/App_Icon.svg",
      logoAlt: ${JSON.stringify(options.shopName)},
      logoHref: "/"
    },
    consent: googleTagManagerId ? {
      enabled: true,
      policyHref: "/information/cookies/",
      managedCookies: [
        {
          name: "_ga",
          category: "statistics",
          provider: "Google Analytics",
          purpose: "Skelner mellem besøgende i statistikmåling.",
          duration: "Typisk op til 2 år"
        },
        {
          name: "_ga_*",
          category: "statistics",
          provider: "Google Analytics",
          purpose: "Bevarer sessionsstatus for statistikmåling.",
          duration: "Typisk op til 2 år"
        },
        {
          name: "_gcl_au",
          category: "marketing",
          provider: "Google",
          purpose: "Måler annonce- og konverteringseffekt.",
          duration: "Typisk op til 90 dage"
        }
      ]
    } : undefined,
    analytics: googleTagManagerId ? {
      googleTagManagerId,
      defaultCurrency: "DKK",
      affiliation: ${JSON.stringify(options.shopName)}
    } : undefined
  });
</script>
`;
}

function bodyStartSource() {
  return `<!-- Add shared body-start snippets here, for example consent markup or a manually pasted Google Tag Manager noscript fallback. -->
<!-- orderly-include-template: ../templates/shop-footer.html -->
<!-- orderly-include-template: ../templates/product-tile.html -->
<!-- orderly-include-template: ../templates/product-page.html -->
<!-- orderly-include-template: ../templates/basket.html -->
`;
}

function navigationSource() {
  return `import type { NavigationDefinition } from "@orderlyshop/web-components";

export const navigationDefinitions: NavigationDefinition[] = [
  {
    label: "Nyheder",
    slug: "nyheder",
    heroImage: "https://images.unsplash.com/photo-1496747611176-843222e1e57c?auto=format&fit=crop&w=1800&q=80",
    query: { query: "nyheder" },
    children: [
      { label: "Dame", slug: "dame", query: { query: "dame | mode" } },
      { label: "Herre", slug: "herre", query: { query: "herre | mode" } },
      { label: "Børn", slug: "boern", query: { query: "børn | baby" } }
    ]
  },
  {
    label: "Sko",
    slug: "sko",
    heroImage: "https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=1800&q=80",
    query: { query: "sko | sneakers" },
    children: [
      { label: "Damesko", slug: "damesko", query: { query: "damesko | sneakers" } },
      { label: "Herresko", slug: "herresko", query: { query: "herresko | sneakers" } },
      { label: "Sportssko", slug: "sportssko", query: { query: "sportssko | løb" } }
    ]
  },
  {
    label: "Bolig",
    slug: "bolig",
    heroImage: "https://images.unsplash.com/photo-1618221195710-dd6b41faaea6?auto=format&fit=crop&w=1800&q=80",
    query: { query: "bolig | indretning" },
    children: [
      { label: "Møbler", slug: "moebler", query: { query: "møbler | sofa | stol | bord" } },
      { label: "Belysning", slug: "belysning", query: { query: "belysning | lampe" } },
      { label: "Dekoration", slug: "dekoration", query: { query: "dekoration | kunst | bolig" } }
    ]
  }
];
`;
}

function shopQuerySource(options) {
  if (!options.accountId) {
    return `import type { SearchQuery } from "@orderlyshop/core-client";

// Add shop-wide SearchQuery constraints here, for example SourceAccountId.
// This query is merged into every category, rail, and product grid search.
export const defaultQuery: SearchQuery | undefined = undefined;
`;
  }
  return `import { create } from "@bufbuild/protobuf";
import { AccountIdSchema, SearchQuerySchema, UUIDSchema } from "@orderlyshop/core-client";

export const defaultQuery = create(SearchQuerySchema, {
  SourceAccountId: create(AccountIdSchema, {
    Id: create(UUIDSchema, { Value: ${JSON.stringify(options.accountId)} })
  })
});
`;
}

function styleSource() {
  return `* {
  box-sizing: border-box;
}

:root {
  --shop-accent: #ef5a24;
  --shop-border: #e2e2e2;
  --shop-muted: #5f5f5f;
  color: #141414;
  background: #eeeeee;
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

body {
  min-width: 320px;
  margin: 0;
  overflow-x: hidden;
  background: #eeeeee;
}

body.orderly-navigation-menu-open {
  overflow: hidden;
}

orderly-home-page:not(:defined),
orderly-category-page:not(:defined),
orderly-product-detail-page:not(:defined),
orderly-checkout-page:not(:defined),
orderly-payment-success-page:not(:defined),
orderly-payment-failure-page:not(:defined) {
  display: block;
  min-height: 100vh;
  background: #f6f8f9;
}

orderly-home-page:not(:defined)::before,
orderly-category-page:not(:defined)::before,
orderly-product-detail-page:not(:defined)::before,
orderly-checkout-page:not(:defined)::before,
orderly-payment-success-page:not(:defined)::before,
orderly-payment-failure-page:not(:defined)::before {
  content: "";
  display: block;
  height: 62px;
  border-bottom: 1px solid #d8dee3;
  background: #ffffff;
}

button,
input,
select {
  font: inherit;
}

.shop-utility-strip {
  display: flex;
  justify-content: center;
  gap: clamp(14px, 4vw, 64px);
  padding: 8px 16px;
  background: #141414;
  color: #ffffff;
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
}

.orderly-page-layout__header {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 24px;
  border-bottom: 1px solid var(--shop-border);
  background: #ffffff;
}

.orderly-page-layout__primary-nav,
.orderly-page-layout__footer {
  background: #ffffff;
}

.orderly-product-grid__items,
.orderly-product-rail__items {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 18px;
}

.orderly-product-rail__items {
  display: flex;
  overflow-x: auto;
  padding-bottom: 12px;
}

.orderly-product-rail__item {
  flex: 0 0 min(240px, 70vw);
}

.orderly-product-tile {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  height: 100%;
  border: 1px solid var(--shop-border);
  border-radius: 8px;
  background: #ffffff;
  overflow: hidden;
}

.orderly-product-tile__image {
  width: 100%;
  aspect-ratio: 1;
  background: #ffffff;
}

.orderly-product-tile__body {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
  padding: 12px;
}

.orderly-product-tile__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: auto;
}

.orderly-product-tile__add,
.orderly-basket-icon__button {
  min-width: 44px;
  min-height: 44px;
  border: 1px solid #141414;
  border-radius: 999px;
  background: #141414;
  color: #ffffff;
}

.orderly-product-tile__add-icon,
.orderly-product-tile__add-svg,
.orderly-product-tile__remove-svg {
  display: block;
}

.orderly-shop-footer {
  display: grid;
  gap: 24px;
  padding: 40px 24px;
  border-top: 1px solid var(--shop-border);
}

@media (min-width: 760px) {
  .orderly-shop-footer {
    grid-template-columns: 2fr repeat(3, 1fr);
  }
}
`;
}

function shopFooterTemplateSource(options) {
  return `<template data-orderly-template="footer" data-orderly-for="shop-footer">
  <div class="orderly-shop-footer">
    <div class="orderly-shop-footer__brand">
      <a class="orderly-shop-footer__logo" href="/" aria-label="${escapeAttribute(options.shopName)}">
        <img class="orderly-shop-footer__logo-image" src="https://orderly.shop/home/App_Icon.svg" alt="${escapeAttribute(options.shopName)}">
      </a>
      <p class="orderly-shop-footer__about">A storefront built with Orderly web components.</p>
    </div>
    <section class="orderly-shop-footer__section">
      <h2 class="orderly-shop-footer__heading">Contact</h2>
      <p>hello@example.com</p>
      <p>+45 12 34 56 78</p>
    </section>
    <section class="orderly-shop-footer__section">
      <h2 class="orderly-shop-footer__heading">Opening hours</h2>
      <p>Monday - Friday: 09.00 - 17.00</p>
      <p>Saturday: 10.00 - 14.00</p>
    </section>
    <section class="orderly-shop-footer__section">
      <h2 class="orderly-shop-footer__heading">Information</h2>
      <ul class="orderly-shop-footer__list">
        <li><a href="/information/terms/">Terms</a></li>
        <li><a href="/information/delivery/">Delivery and returns</a></li>
        <li><a href="/information/privacy/">Privacy policy</a></li>
      </ul>
    </section>
  </div>
</template>
`;
}

function productTileTemplateSource() {
  return `<template data-orderly-template="product" data-orderly-for="product-tile">
  <article class="orderly-product-tile" data-orderly-product>
    <orderly-stored-image class="orderly-product-tile__image" data-orderly-bind="image" fit="contain" image-role="product-tile"></orderly-stored-image>
    <link data-orderly-bind="schema-url" data-orderly-schema-prop="url">
    <link data-orderly-bind="schema-image" data-orderly-schema-prop="image">
    <meta data-orderly-bind="schema-description" data-orderly-schema-prop="description">
    <meta data-orderly-bind="schema-sku" data-orderly-schema-prop="sku">
    <div class="orderly-product-tile__body">
      <h3 class="orderly-product-tile__title">
        <a class="orderly-product-tile__link" href="/product.html" data-orderly-bind="share-url">
          <span data-orderly-bind="title"></span>
        </a>
      </h3>
      <p class="orderly-product-tile__brand" data-orderly-schema-brand><span data-orderly-bind="brand"></span></p>
      <div class="orderly-product-tile__footer">
        <div class="orderly-product-tile__offer" data-orderly-schema-offer>
          <link data-orderly-bind="schema-url" data-orderly-schema-prop="url">
          <meta data-orderly-bind="schema-price-currency" data-orderly-schema-prop="priceCurrency">
          <meta data-orderly-bind="schema-price" data-orderly-schema-prop="price">
          <link data-orderly-bind="schema-availability" data-orderly-schema-prop="availability">
          <p class="orderly-product-tile__price" data-orderly-bind="price"></p>
        </div>
        <button class="orderly-product-tile__add" type="button" data-orderly-action="add-to-basket">
          <span class="orderly-product-tile__add-icon" data-orderly-bind="basket-action-icon" aria-hidden="true"></span>
        </button>
      </div>
    </div>
  </article>
</template>
`;
}

function productPageTemplateSource() {
  return `<template data-orderly-template="product" data-orderly-for="product-page">
  <section class="orderly-product-page">
    <div class="orderly-product-page__media" style="display: grid; gap: 12px; align-content: start; justify-self: center; width: 100%; max-width: 520px; min-width: 0;">
      <orderly-stored-image class="orderly-product-page__image" data-orderly-bind="image" fit="contain" variant="object" image-role="product-detail" style="display: block; width: 100%; max-width: 520px; min-width: 0; aspect-ratio: 1 / 1; overflow: hidden;"></orderly-stored-image>
      <div class="orderly-product-page__thumbnails" data-orderly-slot="thumbnails"></div>
    </div>
    <div class="orderly-product-page__details" style="min-width: 0;">
      <p data-orderly-bind="brand"></p>
      <h1 data-orderly-bind="title"></h1>
      <p data-orderly-bind="price"></p>
      <p data-orderly-bind="description"></p>
      <button type="button" data-orderly-action="add-to-basket">
        <span data-orderly-bind="basket-action-label"></span>
      </button>
    </div>
  </section>
</template>
`;
}

function basketTemplateSource() {
  return `<template data-orderly-template="basket" data-orderly-for="basket">
  <section class="orderly-basket">
    <header class="orderly-basket__header">
      <h2 data-orderly-bind="title"></h2>
      <button type="button" data-orderly-action="clear"><span data-orderly-bind="clearLabel"></span></button>
    </header>
    <p class="orderly-basket__empty" data-orderly-bind="emptyLabel"></p>
    <ul class="orderly-basket__lines" data-orderly-slot="lines"></ul>
    <footer class="orderly-basket__summary">
      <p><span data-orderly-bind="subtotalLabel"></span> <strong data-orderly-bind="subtotal"></strong></p>
      <p><span data-orderly-bind="totalLabel"></span> <strong data-orderly-bind="total"></strong></p>
      <a class="orderly-basket__checkout" data-orderly-action="checkout" data-orderly-bind="checkoutHref">
        <span data-orderly-bind="checkoutLabel"></span>
      </a>
    </footer>
  </section>
</template>
`;
}

function parseArgs(values) {
  const parsed = {};
  for (let index = 0; index < values.length; index += 1) {
    const value = values[index];
    if (!value.startsWith("--")) {
      continue;
    }
    const [name, inlineValue] = value.slice(2).split("=", 2);
    if (inlineValue !== undefined) {
      parsed[name] = inlineValue;
    } else if (values[index + 1] && !values[index + 1].startsWith("--")) {
      parsed[name] = values[index + 1];
      index += 1;
    } else {
      parsed[name] = true;
    }
  }
  return parsed;
}

function printHelp() {
  console.log(`Usage: orderly-init-shop [options]

Create a vanilla TypeScript storefront using @orderlyshop/web-components.

Options:
  --path <dir>            Target directory. Defaults to the current directory.
  --name <name>           Shop display name. Defaults to "Orderly Butik".
  --package-name <name>   package.json name when package.json does not exist.
  --base-url <url>        Orderly backend URL. Defaults to ${defaultBackendUrl}.
  --account-id <id>       Optional tenant/account id written into src/shop-query.ts.
  --legal-owner-name <n>  Legal webshop owner name. Defaults to the shop display name.
  --legal-owner-cvr <cvr> Legal webshop owner CVR shown in the required footer notice.
  --skip-package-json     Do not create or update package.json.
  --force                 Overwrite scaffold files that already exist.
  --dry-run               Print files that would be written without mutating the project.
  --help, -h              Show this help.

Agent workflow:
  1. If no shop scaffold exists, run: npx orderly-init-shop
  2. Existing scaffold files are skipped with warnings. Use --force only when the user explicitly wants overwrite.
  3. Ask the user for the shop account id, legal owner name, legal owner CVR, and reference website URL.
  4. Re-run with --account-id <id> --legal-owner-name <name> --legal-owner-cvr <cvr>, or edit src/shop-query.ts and src/includes/head.html.
  5. Customize src/navigation.ts with categories and SearchQuery values.
  6. Translate the reference website into src/style.css with DESIGN.md semantic tokens first.
`);
}

function readJson(file) {
  if (!existsSync(file)) {
    return undefined;
  }
  return JSON.parse(readFileSync(file, "utf8"));
}

function slugPackageName(value) {
  const slug = value
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-+|-+$/g, "");
  return slug || "orderly-shop";
}

function escapeHtml(value) {
  return String(value)
    .replaceAll("&", "&amp;")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;");
}

function escapeAttribute(value) {
  return escapeHtml(value).replaceAll("\"", "&quot;");
}
