import * as z from 'zod';

function extractPathParams(path) {
  const params = [];
  const segments = path.split("/");
  for (const segment of segments) {
    if (segment.startsWith(":")) {
      params.push(segment.slice(1));
    } else if (segment.startsWith("*:")) {
      params.push(segment.slice(2));
    } else if (segment === "*") {
      params.push("_");
    }
  }
  return params;
}
function getTypeFromZodType(zodType) {
  if (zodType instanceof z.ZodString) return "string";
  if (zodType instanceof z.ZodNumber) return "number";
  if (zodType instanceof z.ZodBoolean) return "boolean";
  if (zodType instanceof z.ZodArray) return "array";
  if (zodType instanceof z.ZodObject) return "object";
  if (zodType instanceof z.ZodEnum) return "enum";
  if (zodType instanceof z.ZodLiteral) return "literal";
  if (zodType instanceof z.ZodUnion) return "union";
  const type = zodType.type;
  if (type === "string") return "string";
  if (type === "number") return "number";
  if (type === "boolean") return "boolean";
  if (type === "array") return "array";
  if (type === "object") return "object";
  return "string";
}
function processZodType(zodType) {
  if (zodType instanceof z.ZodOptional) {
    const innerType = zodType._def?.innerType || zodType.unwrap?.();
    if (innerType) {
      return processZodType(innerType);
    }
  }
  if (zodType instanceof z.ZodNullable) {
    const innerType = zodType._def?.innerType || zodType.unwrap?.();
    if (innerType) {
      const innerSchema = processZodType(innerType);
      return {
        ...innerSchema,
        nullable: true
      };
    }
  }
  if (zodType instanceof z.ZodDefault) {
    const innerType = zodType._def?.innerType;
    const rawDefault = zodType._def?.defaultValue;
    const defaultValue = typeof rawDefault === "function" ? rawDefault() : rawDefault;
    if (innerType) {
      const innerSchema = processZodType(innerType);
      if (defaultValue !== void 0) {
        return {
          ...innerSchema,
          default: defaultValue
        };
      }
      return innerSchema;
    }
  }
  if (zodType instanceof z.ZodObject) {
    const shape = zodType.shape || zodType._def?.shape?.();
    if (shape) {
      const properties = {};
      const required = [];
      for (const [key, value] of Object.entries(shape)) {
        if (value instanceof z.ZodType) {
          properties[key] = processZodType(value);
          if (!(value instanceof z.ZodOptional)) {
            required.push(key);
          }
        }
      }
      return {
        type: "object",
        properties,
        ...required.length > 0 ? { required } : {}
      };
    }
  }
  if (zodType instanceof z.ZodArray) {
    const elementType = zodType._def?.type || zodType.element;
    return {
      type: "array",
      items: elementType ? processZodType(elementType) : { type: "string" }
    };
  }
  if (zodType instanceof z.ZodEnum) {
    const values = zodType._def?.values || zodType.options;
    return {
      type: "string",
      enum: values
    };
  }
  if (zodType instanceof z.ZodLiteral) {
    const value = zodType._def?.value || zodType.value;
    return {
      type: typeof value,
      const: value
    };
  }
  if (zodType instanceof z.ZodUnion) {
    const options = zodType._def?.options || zodType.options;
    if (options && Array.isArray(options)) {
      return {
        oneOf: options.map((opt) => processZodType(opt))
      };
    }
  }
  if (zodType._def?.coerce) {
    const innerType = zodType._def?.innerType;
    if (innerType) {
      return processZodType(innerType);
    }
  }
  return {
    type: getTypeFromZodType(zodType)
  };
}
function isStandardSchema(obj) {
  return obj && typeof obj === "object" && "~standard" in obj;
}
function extractQueryParams(querySchema) {
  const params = [];
  if (!querySchema) return params;
  if (querySchema instanceof z.ZodObject) {
    const shape = querySchema.shape || querySchema._def?.shape?.();
    if (shape) {
      for (const [key, value] of Object.entries(shape)) {
        if (value instanceof z.ZodType) {
          params.push({
            name: key,
            type: getTypeFromZodType(value),
            required: !(value instanceof z.ZodOptional),
            schema: processZodType(value)
          });
        }
      }
    }
  } else if (isStandardSchema(querySchema)) {
    const zodSchema = querySchema;
    if (zodSchema instanceof z.ZodObject) {
      return extractQueryParams(zodSchema);
    }
  }
  return params;
}
async function fetchAllSitemapEntries(context) {
  const allEntries = [];
  for (const [pluginKey, plugin] of Object.entries(context.plugins)) {
    if (pluginKey === "routeDocs" || plugin.name === "route-docs") {
      continue;
    }
    if (plugin.sitemap) {
      try {
        const entries = await plugin.sitemap();
        for (const entry of entries) {
          allEntries.push({
            ...entry,
            pluginKey
          });
        }
      } catch (error) {
        console.warn(`Failed to fetch sitemap for plugin ${pluginKey}:`, error);
      }
    }
  }
  return allEntries;
}
function generateRouteDocsSchema(context, sitemapEntries = []) {
  const documentedPlugins = [];
  const sitemapByPlugin = {};
  for (const entry of sitemapEntries) {
    if (!sitemapByPlugin[entry.pluginKey]) {
      sitemapByPlugin[entry.pluginKey] = [];
    }
    sitemapByPlugin[entry.pluginKey].push(entry);
  }
  for (const [pluginKey, plugin] of Object.entries(context.plugins)) {
    if (pluginKey === "routeDocs" || plugin.name === "route-docs") {
      continue;
    }
    const pluginRoutes = plugin.routes(context);
    const documentedRoutes = [];
    for (const [routeKey, route] of Object.entries(pluginRoutes)) {
      const r = route;
      const path = r.path;
      const routeOptions = r.options || {};
      const routeMeta = r.meta;
      if (!path) continue;
      const pathParamNames = extractPathParams(path);
      const pathParams = pathParamNames.map((name) => ({
        name,
        type: "string",
        // Path params are always strings
        required: true
      }));
      const queryParams = extractQueryParams(routeOptions.query);
      documentedRoutes.push({
        key: routeKey,
        path,
        pathParams,
        queryParams,
        meta: routeMeta
      });
    }
    if (documentedRoutes.length > 0) {
      documentedPlugins.push({
        key: pluginKey,
        name: plugin.name,
        routes: documentedRoutes,
        sitemapEntries: sitemapByPlugin[pluginKey] || []
      });
    }
  }
  return {
    plugins: documentedPlugins,
    generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
    allSitemapEntries: sitemapEntries
  };
}

export { fetchAllSitemapEntries, generateRouteDocsSchema };
