import { inferHttpMethod as sharedInferHttpMethod, inferPath as sharedInferPath, curedToEndpoints as sharedCuredToEndpoints } from "@specverse/types/spec-rules";
function generateFastifyRoutes(context) {
  const { controller, model, spec, implType } = context;
  if (!controller) {
    throw new Error("Controller is required in template context");
  }
  const modelName = model?.name || controller.modelReference;
  const controllerName = controller.name;
  const routeName = controllerName || `${modelName}Controller`;
  const isModelController = !!modelName;
  const handlerName = isModelController ? `${modelName}Controller` : controllerName;
  const imports = generateImports(controller, modelName, handlerName, isModelController, implType);
  let endpoints = controller.endpoints;
  if (!endpoints || endpoints.length === 0) {
    if (controller.cured) {
      endpoints = curedToEndpoints(controller.cured, modelName);
    }
  }
  if (controller.actions) {
    if (!endpoints) endpoints = [];
    for (const [actionName, action] of Object.entries(controller.actions)) {
      const params = action.parameters || {};
      const hasIdParam = Object.keys(params).some((p) => p === "id" || p === `${modelName?.charAt(0).toLowerCase()}${modelName?.slice(1)}Id`);
      endpoints.push({
        operation: actionName,
        method: "POST",
        path: hasIdParam ? `/:id/${actionName}` : `/${actionName}`,
        parameters: params,
        description: action.description || `Custom action: ${actionName}`
      });
    }
  }
  if (!endpoints || endpoints.length === 0) {
    console.warn(`Warning: Controller ${controllerName} has no endpoints. Generating empty routes file.`);
  }
  const routeHandlers = endpoints?.map((endpoint) => {
    return generateRouteHandler(endpoint, modelName, handlerName, isModelController, implType, controllerName);
  }).join("\n\n") || "";
  return `${imports}

/**
 * ${routeName} Routes
 * Generated from SpecVerse specification
 *
 * ${isModelController ? `Model: ${modelName}` : `Service: ${controllerName}`}
 * Operations: ${controller.endpoints?.map((e) => e.operation).join(", ") || "CURED"}
 */
export default async function ${routeName.replace("Controller", "")}Routes(
  fastify: FastifyInstance,
  options: any
) {
  const handler = ${isModelController ? "options.controllers" : "options.services"}.${handlerName};

${routeHandlers.split("\n").map((line) => "  " + line).join("\n")}
}
`;
}
function generateImports(controller, modelName, handlerName, isModelController, implType) {
  const imports = [
    `import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';`
  ];
  if (implType?.technology?.validation === "zod" && modelName) {
    imports.push(`import { ${modelName}Schema } from '../validation/${modelName}.schema.js';`);
  }
  return imports.join("\n");
}
function generateRouteHandler(endpoint, modelName, handlerName, isModelController, implType, controllerName) {
  let operation = endpoint.operation || endpoint.name;
  if (!operation || operation === "custom") {
    const serviceOp = endpoint.serviceOperation?.type;
    if (serviceOp === "custom" && endpoint.path) {
      const pathParts = endpoint.path.split("/").filter((p) => p);
      const lastPart = pathParts[pathParts.length - 1];
      operation = lastPart.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
    } else if (!operation) {
      operation = serviceOp;
    }
  }
  if (!operation) {
    operation = inferOperationFromMethodAndPath(endpoint.method, endpoint.path);
  }
  if (!operation || operation === "unknown") {
    console.warn(`Warning: Could not determine operation for endpoint in ${controllerName || "controller"}. Endpoint data:`, {
      operation: endpoint.operation,
      name: endpoint.name,
      method: endpoint.method,
      path: endpoint.path,
      serviceOperation: endpoint.serviceOperation
    });
  }
  const method = endpoint.method?.toLowerCase() || inferHttpMethod(operation);
  const path = inferPath(operation, endpoint);
  const handler = generateHandlerBody(operation, modelName, handlerName, isModelController, implType, endpoint);
  let route = `// ${operation} ${modelName}
`;
  route += `fastify.${method}('${path}', {
`;
  if (implType?.technology?.validation === "zod") {
    route += `  schema: {
`;
    if (operation === "create" || operation === "update" || operation === "evolve") {
      route += `    body: ${modelName}Schema.${operation},
`;
    }
    if (operation === "retrieve" || operation === "update" || operation === "delete") {
      route += `    params: ${modelName}Schema.params,
`;
    }
    route += `    response: {
`;
    route += `      200: ${modelName}Schema.response
`;
    route += `    }
`;
    route += `  },
`;
  }
  const usesRequest = ["create", "retrieve", "update", "evolve", "delete", "validate"].includes(operation) || !["list"].includes(operation);
  const requestParam = usesRequest ? "request" : "_request";
  route += `  handler: async (${requestParam}: FastifyRequest, reply: FastifyReply) => {
`;
  route += handler.split("\n").map((line) => "    " + line).join("\n") + "\n";
  route += `  }
`;
  route += `});`;
  return route;
}
function generateHandlerBody(operation, modelName, handlerName, isModelController, implType, endpoint) {
  const rawLowerModel = modelName?.toLowerCase() || "item";
  const RESERVED_WORDS = /* @__PURE__ */ new Set(["import", "export", "default", "class", "function", "return", "delete", "new", "this", "switch", "case", "break", "continue", "for", "while", "do", "if", "else", "try", "catch", "finally", "throw", "typeof", "instanceof", "in", "of", "let", "const", "var", "void", "with", "yield", "async", "await", "enum", "implements", "interface", "package", "private", "protected", "public", "static", "super", "extends"]);
  const lowerModel = RESERVED_WORDS.has(rawLowerModel) ? `${rawLowerModel}Item` : rawLowerModel;
  const operationMap = {
    "custom": "create",
    // POST without ID -> create
    "findUnique": "retrieve",
    // GET with ID -> retrieve
    "findMany": "list",
    // GET without ID -> list
    "updateUnique": "update",
    // PUT with ID -> update
    "deleteUnique": "delete"
    // DELETE with ID -> delete
  };
  const mappedOperation = operationMap[operation] || operation;
  switch (mappedOperation) {
    case "create":
      return `try {
  const ${lowerModel} = await handler.create(request.body as any);
  return reply.status(201).send(${lowerModel});
} catch (error) {
  return reply.status(400).send({
    error: 'Failed to create ${lowerModel}',
    message: error instanceof Error ? error.message : String(error)
  });
}`;
    case "retrieve":
      return `try {
  const { id } = request.params as { id: string };
  const ${lowerModel} = await handler.retrieve(id);

  if (!${lowerModel}) {
    return reply.status(404).send({ error: '${modelName} not found' });
  }

  return reply.send(${lowerModel});
} catch (error) {
  return reply.status(500).send({
    error: 'Failed to retrieve ${lowerModel}',
    message: error instanceof Error ? error.message : String(error)
  });
}`;
    case "update":
    case "evolve":
      return `try {
  const { id } = request.params as { id: string };
  const ${lowerModel} = await handler.${operation}(id, request.body as any);
  return reply.send(${lowerModel});
} catch (error) {
  return reply.status(400).send({
    error: 'Failed to ${operation} ${lowerModel}',
    message: error instanceof Error ? error.message : String(error)
  });
}`;
    case "delete":
      return `try {
  const { id } = request.params as { id: string };
  await handler.delete(id);
  return reply.status(204).send();
} catch (error) {
  return reply.status(500).send({
    error: 'Failed to delete ${lowerModel}',
    message: error instanceof Error ? error.message : String(error)
  });
}`;
    case "list":
      return `try {
  const ${lowerModel}s = await handler.retrieveAll();
  return reply.send(${lowerModel}s);
} catch (error) {
  return reply.status(500).send({
    error: 'Failed to list ${lowerModel}s',
    message: error instanceof Error ? error.message : String(error)
  });
}`;
    case "validate":
      return `try {
  const { data, operation: op } = request.body as { data: any; operation: string };
  const result = handler.validate(data, { operation: op });
  return reply.send(result);
} catch (error) {
  return reply.status(400).send({
    error: 'Validation failed',
    message: error instanceof Error ? error.message : String(error)
  });
}`;
    default: {
      const params = endpoint?.parameters || {};
      const paramNames = Object.keys(params);
      const callArgs = paramNames.length > 0 ? paramNames.map((p) => `body.${p}`).join(", ") : "body";
      const validations = [];
      for (const [pName, pDef] of Object.entries(params)) {
        const required = typeof pDef === "string" ? pDef.includes("required") : pDef?.required;
        const typeStr = typeof pDef === "string" ? pDef.split(" ")[0] : pDef?.type || "String";
        if (required) {
          validations.push(`  if (body.${pName} === undefined || body.${pName} === null) errors.push({ field: '${pName}', message: '${pName} is required' });`);
        }
        if (typeStr === "UUID" || typeStr === "String" || typeStr === "Email") {
          validations.push(`  if (body.${pName} !== undefined && typeof body.${pName} !== 'string') errors.push({ field: '${pName}', message: '${pName} must be a string' });`);
        } else if (typeStr === "Integer" || typeStr === "Number" || typeStr === "Float") {
          validations.push(`  if (body.${pName} !== undefined && typeof body.${pName} !== 'number') errors.push({ field: '${pName}', message: '${pName} must be a number' });`);
        } else if (typeStr === "Boolean") {
          validations.push(`  if (body.${pName} !== undefined && typeof body.${pName} !== 'boolean') errors.push({ field: '${pName}', message: '${pName} must be a boolean' });`);
        }
      }
      const validationBlock = validations.length > 0 ? `  const errors: Array<{ field: string; message: string }> = [];
${validations.join("\n")}
  if (errors.length > 0) return reply.status(400).send({ error: 'Validation failed', details: errors });` : "";
      return `try {
  const body = (request.body || {}) as Record<string, any>;
${validationBlock}
  const result = await handler.${operation}(${callArgs});
  return reply.send(result || { success: true });
} catch (error) {
  return reply.status(400).send({
    error: 'Failed to execute ${operation}',
    message: error instanceof Error ? error.message : String(error)
  });
}`;
    }
  }
}
function inferOperationFromMethodAndPath(method, path) {
  if (!method || !path) return "unknown";
  const methodLower = method.toLowerCase();
  const hasIdParam = path.includes(":id");
  if (methodLower === "post" && !hasIdParam) return "create";
  if (methodLower === "get" && hasIdParam) return "retrieve";
  if (methodLower === "get" && !hasIdParam) return "list";
  if (methodLower === "put" && hasIdParam) return "update";
  if (methodLower === "patch" && hasIdParam) return "evolve";
  if (methodLower === "delete" && hasIdParam) return "delete";
  return "unknown";
}
function inferHttpMethod(operation) {
  return sharedInferHttpMethod(operation);
}
function inferPath(operation, endpoint) {
  if (endpoint?.path) {
    return endpoint.path;
  }
  return sharedInferPath(operation);
}
function curedToEndpoints(cured, _modelName) {
  return sharedCuredToEndpoints(cured);
}
export {
  generateFastifyRoutes as default
};
