import { isDereferenced } from "@scalar/openapi-types/helpers";
import { getResolvedRef } from "@scalar/workspace-store/helpers/get-resolved-ref";
import { isObjectSchema } from "@scalar/workspace-store/schemas/v3.1/strict/type-guards";
function resolveSchemaRef(ref) {
  return getResolvedRef(ref);
}
function formatProperty(key, obj) {
  let output = key;
  const isRequired = obj.required?.includes(key);
  output += isRequired ? " REQUIRED " : " optional ";
  const propRef = obj.properties[key];
  if (!propRef) return output;
  const property = resolveSchemaRef(propRef);
  if (property && typeof property === "object" && "type" in property) {
    output += property.type ?? "";
    if ("description" in property && typeof property.description === "string") {
      output += " " + property.description;
    }
  }
  return output;
}
function recursiveLogger(obj) {
  const results = ["Body"];
  const schema = getResolvedRef(obj?.schema);
  if (!schema || !isObjectSchema(schema) || !schema.properties) {
    return results;
  }
  const properties = schema.properties;
  const schemaWithProps = {
    properties,
    required: schema.required
  };
  Object.keys(properties).forEach((key) => {
    if (!obj.schema) {
      return;
    }
    results.push(formatProperty(key, schemaWithProps));
    const propRef = properties[key];
    if (!propRef) return;
    const property = resolveSchemaRef(propRef);
    if (property && isObjectSchema(property) && property.properties) {
      const nestedProperties = property.properties;
      Object.keys(nestedProperties).forEach((subKey) => {
        const ref = nestedProperties[subKey];
        if (!ref) return;
        const nested = resolveSchemaRef(ref);
        const typeStr = nested && typeof nested === "object" && "type" in nested ? nested.type ?? "" : "";
        results.push(`${subKey} ${typeStr}`);
      });
    }
  });
  return results;
}
function extractRequestBody(operation) {
  try {
    const media = getResolvedRef(operation?.requestBody)?.content?.["application/json"];
    if (!media) {
      throw new Error("Body not found");
    }
    return recursiveLogger(media);
  } catch (_error) {
    return false;
  }
}
function deepMerge(source, target) {
  for (const [key, val] of Object.entries(source)) {
    if (val !== null && typeof val === "object") {
      target[key] ??= new val.__proto__.constructor();
      deepMerge(val, target[key]);
    } else if (typeof val !== "undefined") {
      target[key] = val;
    }
  }
  return target;
}
function createEmptySpecification(partialSpecification) {
  return deepMerge(partialSpecification ?? {}, {
    info: {
      title: "",
      description: "",
      termsOfService: "",
      version: "",
      license: {
        name: "",
        url: ""
      },
      contact: {
        email: ""
      }
    },
    servers: [],
    tags: []
  });
}
function createParameterMap(operation) {
  const map = {
    path: [],
    query: [],
    header: [],
    cookie: [],
    body: [],
    formData: []
  };
  const parameters = operation.parameters ?? [];
  if (parameters) {
    parameters.forEach((parameter) => {
      if (!isDereferenced(parameter)) {
        return;
      }
      if (typeof parameter === "object" && parameter !== null && "$ref" in parameter) {
        return;
      }
      if (parameter.in === "path") {
        map.path.push(parameter);
      } else if (parameter.in === "query") {
        map.query.push(parameter);
      } else if (parameter.in === "header") {
        map.header.push(parameter);
      } else if (parameter.in === "cookie") {
        map.cookie.push(parameter);
      } else if (parameter.in === "body") {
        map.body.push(parameter);
      } else if (parameter.in === "formData") {
        map.formData.push(parameter);
      }
    });
  }
  return map;
}
export {
  createEmptySpecification,
  createParameterMap,
  deepMerge,
  extractRequestBody
};
