const STANDARD_OPS = /* @__PURE__ */ new Set([
  "create",
  "retrieve",
  "retrieve_many",
  "update",
  "delete",
  "validate",
  "evolve",
  "list",
  "query",
  "get",
  "attachProfile",
  "detachProfile",
  "hasProfile",
  "handleChildAdded",
  "handleChildRemoved",
  "validateRelationshipIntegrity",
  "repairRelationshipIntegrity"
]);
function normalizeParameters(raw) {
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
  const out = {};
  for (const [name, def] of Object.entries(raw)) {
    let type;
    if (typeof def === "string") {
      type = def;
    } else if (def && typeof def === "object" && "type" in def && typeof def.type === "string") {
      type = def.type;
    } else {
      type = "String";
    }
    out[name] = type.split(/\s+/)[0] || "String";
  }
  return Object.keys(out).length > 0 ? out : void 0;
}
function collectOperationViews(spec) {
  const out = [];
  const seen = /* @__PURE__ */ new Set();
  const controllers = spec.controllers ?? {};
  for (const [ctlName, ctl] of Object.entries(controllers)) {
    const ops = ctl?.operations ?? ctl?.commands ?? {};
    for (const [opName, op] of Object.entries(ops)) {
      if (STANDARD_OPS.has(opName)) continue;
      const viewName = capitalize(opName) + "View";
      if (seen.has(viewName)) continue;
      seen.add(viewName);
      out.push({
        viewName,
        label: humanize(opName),
        serviceName: ctlName,
        operationName: opName,
        parameters: normalizeParameters(op?.parameters ?? op?.params),
        requires: op?.requires,
        returns: op?.returns,
        source: "controller"
      });
    }
  }
  const services = spec.services ?? {};
  for (const [svcName, svc] of Object.entries(services)) {
    const rawOps = svc?.operations;
    const opEntries = Array.isArray(rawOps) ? rawOps.map((o) => [o.name, o]) : Object.entries(rawOps ?? {});
    for (const [opName, op] of opEntries) {
      if (!opName) continue;
      if (STANDARD_OPS.has(opName)) continue;
      const viewName = capitalize(opName) + "View";
      if (seen.has(viewName)) continue;
      seen.add(viewName);
      out.push({
        viewName,
        label: humanize(opName),
        serviceName: svcName,
        operationName: opName,
        parameters: normalizeParameters(op?.parameters ?? op?.params),
        requires: op?.requires,
        returns: op?.returns,
        source: "service"
      });
    }
  }
  return out;
}
function emitOperationView(desc) {
  const paramsJson = desc.parameters ? JSON.stringify(desc.parameters, null, 2).replace(/\n/g, "\n        ") : "undefined";
  const requiresJson = desc.requires ? JSON.stringify(desc.requires) : "undefined";
  const returnsPill = desc.returns ? `
        <span className="text-xs px-2 py-0.5 bg-gray-200 dark:bg-gray-700 text-gray-600 dark:text-gray-300 rounded font-mono">
          \u2192 ${escapeJsx(desc.returns)}
        </span>` : "";
  return `/**
 * ${desc.viewName} \u2014 generated by @specverse/realize (ReactAppStarter)
 *
 * Auto-generated operation view for ${desc.source} ${desc.serviceName}.${desc.operationName}.
 * Safe to edit; the generator will not overwrite a hand-edited file
 * (content-hashing in .specverse-gen/hashes.json).
 */
import { OperationExecutor } from '../lib/OperationExecutor';

export function ${desc.viewName}() {
  return (
    <div className="p-6 space-y-4">
      <div className="flex items-center gap-2">
        <h2 className="text-xl font-semibold text-gray-900 dark:text-gray-100">
          ${escapeJsx(desc.label)}
        </h2>${returnsPill}
      </div>
      <p className="text-sm text-gray-500 dark:text-gray-400">
        Execute ${escapeJsx(desc.serviceName)}.${escapeJsx(desc.operationName)}
      </p>
      <div className="max-w-lg">
        <OperationExecutor
          serviceName="${desc.serviceName}"
          operationName="${desc.operationName}"
          parameters={${paramsJson}}
          requires={${requiresJson}}
          source="${desc.source}"
        />
      </div>
    </div>
  );
}
`;
}
function capitalize(s) {
  return s ? s.charAt(0).toUpperCase() + s.slice(1) : s;
}
function humanize(s) {
  return s.replace(/([A-Z])/g, " $1").replace(/^./, (c) => c.toUpperCase()).trim();
}
function escapeJsx(s) {
  return s.replace(/[<>&]/g, (ch) => ({ "<": "&lt;", ">": "&gt;", "&": "&amp;" })[ch]);
}
export {
  collectOperationViews,
  emitOperationView
};
