import { matchStep } from "./step-conventions.js";
function generateBehaviorBody(behavior, opMeta, context) {
  const result = generateBehaviorWithHelpers(behavior, opMeta, context);
  return result.body;
}
function generateBehaviorWithHelpers(behavior, opMeta, context) {
  const parts = [];
  const helperMethods = [];
  const preconditionDeclared = /* @__PURE__ */ new Set();
  const preconditions = generatePreconditionChecks(
    behavior.preconditions || [],
    context,
    preconditionDeclared
  );
  if (preconditions) parts.push(preconditions);
  const { code, helpers, unmatchedSteps } = generateStepLogic(
    behavior.steps || [],
    context,
    preconditionDeclared
  );
  parts.push(code);
  helperMethods.push(...helpers);
  const postconditions = generatePostconditionVerification(
    behavior.postconditions || []
  );
  if (postconditions) parts.push(postconditions);
  const events = generateEventPublishing(
    behavior.sideEffects || [],
    context.operationName,
    context.parameterNames
  );
  if (events) parts.push(events);
  let body = parts.join("\n\n");
  if (behavior.transactional) {
    body = generateTransactionWrapper(body, context);
  }
  return { body, helperMethods, unmatchedSteps };
}
function generatePreconditionChecks(preconditions, context, declared) {
  if (preconditions.length === 0) return "";
  if (!declared) declared = /* @__PURE__ */ new Set();
  const checks = preconditions.map((pc) => matchPreconditionPattern(pc, context, declared));
  return `    // === PRECONDITIONS ===
${checks.join("\n")}`;
}
function findIdParam(modelName, paramNames) {
  const modelVar = modelName.charAt(0).toLowerCase() + modelName.slice(1);
  const idParam = paramNames.find((p) => p === `${modelVar}Id`);
  if (idParam) return idParam;
  if (paramNames.includes("id")) return "id";
  return `${modelVar}Id`;
}
function matchPreconditionPattern(precondition, context, declared) {
  const pc = precondition.toLowerCase();
  const params = context.parameterNames || [];
  const existsMatch = precondition.match(/^(\w+)\s+exists/i);
  if (existsMatch) {
    const entity = existsMatch[1];
    const entityVar = entity.charAt(0).toLowerCase() + entity.slice(1);
    const idParam = findIdParam(entity, params);
    if (declared.has(entityVar)) {
      return `    // Guard: ${precondition} (already fetched)`;
    }
    declared.add(entityVar);
    return `    const ${entityVar} = await prisma.${entityVar}.findUniqueOrThrow({ where: { id: ${idParam} } });`;
  }
  if (pc.includes("is not empty") || pc.includes("is required")) {
    const fieldMatch = precondition.match(/^(\w+)\s+is/i);
    if (fieldMatch) {
      const field = fieldMatch[1];
      const paramRef = params.includes(field) ? field : `params.${field}`;
      return `    if (!${paramRef}) throw new Error('${field} is required');`;
    }
  }
  if (pc.includes("is valid")) {
    return `    // TODO: Implement validation: ${precondition}`;
  }
  const matchesMatch = precondition.match(/^(\w+)\s+(?:matches|equals)\s+(.+)/i);
  if (matchesMatch) {
    const left = matchesMatch[1].charAt(0).toLowerCase() + matchesMatch[1].slice(1);
    const right = matchesMatch[2].charAt(0).toLowerCase() + matchesMatch[2].slice(1);
    return `    if (${left} !== ${right}) throw new Error('${matchesMatch[1]} must match ${matchesMatch[2]}');`;
  }
  const stateMatch = precondition.match(/^(\w+)\s+is\s+(\w+)$/i);
  if (stateMatch) {
    const model = stateMatch[1];
    const state = stateMatch[2];
    const modelVar = model.charAt(0).toLowerCase() + model.slice(1);
    const idParam = findIdParam(model, params);
    if (!declared.has(modelVar)) {
      declared.add(modelVar);
      return `    const ${modelVar} = await prisma.${modelVar}.findUniqueOrThrow({ where: { id: ${idParam} } });
    if (${modelVar}.status !== '${state}') throw new Error('${model} must be ${state}, got ' + ${modelVar}.status);`;
    }
    return `    if (${modelVar}.status !== '${state}') throw new Error('${model} must be ${state}, got ' + ${modelVar}.status);`;
  }
  return `    // TODO: Implement precondition: ${precondition}`;
}
function generateStepLogic(steps, context, preconditionDeclared) {
  const helpers = [];
  const unmatchedSteps = [];
  const declaredVars = preconditionDeclared || /* @__PURE__ */ new Set();
  if (steps && steps.length > 0) {
    const stepCode = steps.map((stepInput, i) => {
      const stepText = typeof stepInput === "string" ? stepInput : stepInput.step;
      const resultName = typeof stepInput === "object" ? stepInput.as : void 0;
      const returns = typeof stepInput === "object" ? stepInput.returns : void 0;
      if (typeof stepText !== "string") {
        return `    // Step ${i + 1}: Complex operation \u2014 see expanded definition`;
      }
      const ctx = {
        modelName: context.modelName,
        prismaModel: context.prismaModel || context.modelName,
        serviceName: context.serviceName,
        operationName: context.operationName,
        stepNum: i + 1,
        parameterNames: context.parameterNames,
        declaredVars,
        resultName
        // Pass through the named result
      };
      const result = matchStep(stepText, ctx);
      if (result.helperMethod) {
        helpers.push(result.helperMethod);
      }
      if (!result.matched && result.functionName) {
        unmatchedSteps.push({
          step: stepText,
          functionName: result.functionName,
          operationName: context.operationName,
          inputs: result.inputs || [],
          returns,
          resultName: resultName || `step${i + 1}Result`
        });
      }
      return result.call;
    });
    return {
      code: `    // === EXECUTE ===
${stepCode.join("\n\n")}`,
      helpers,
      unmatchedSteps
    };
  }
  return {
    code: `    // === EXECUTE ===
${inferLogicFromOperationName(context)}`,
    helpers,
    unmatchedSteps
  };
}
function inferLogicFromOperationName(context) {
  const op = context.operationName;
  const prismaModel = context.prismaModel || context.modelName;
  const modelVar = prismaModel.charAt(0).toLowerCase() + prismaModel.slice(1);
  if (op.startsWith("handle")) {
    const event = op.replace("handle", "");
    return `    // Event handler: ${op}
    console.log('[${context.serviceName}] Processing ${event}', params);
    return { handled: true, event: '${event}' };`;
  }
  if (op.startsWith("validate")) {
    return `    // Validation: ${op}
    const records = await prisma.${modelVar}.findMany({ where: { id: params.id } });
    return { valid: records.length > 0, checked: records.length };`;
  }
  if (op.startsWith("get") || op.startsWith("list") || op.startsWith("find")) {
    return `    return await prisma.${modelVar}.findMany({});`;
  }
  return `    // TODO: Implement ${op}
    return { success: true };`;
}
function generatePostconditionVerification(postconditions) {
  if (postconditions.length === 0) return "";
  const checks = postconditions.map(
    (pc) => `      console.assert(true, 'POSTCONDITION: ${pc}');`
  );
  return `    // === POSTCONDITIONS (dev-mode) ===
    if (process.env.NODE_ENV === 'development') {
${checks.join("\n")}
    }`;
}
function generateEventPublishing(sideEffects, operationName, parameterNames) {
  if (!sideEffects || sideEffects.length === 0) return "";
  const paramFields = parameterNames?.length ? parameterNames.join(", ") + ", " : "";
  const publishes = sideEffects.map(
    (event) => `    await eventBus.publish('${event}', { ${paramFields}timestamp: new Date().toISOString() } as any);`
  );
  return `    // === EVENTS ===
${publishes.join("\n")}`;
}
function generateTransactionWrapper(body, context) {
  return `    return await prisma.$transaction(async (tx) => {
${body}
    });`;
}
export {
  generateBehaviorBody,
  generateBehaviorWithHelpers,
  generateEventPublishing,
  generatePostconditionVerification,
  generatePreconditionChecks,
  generateTransactionWrapper
};
