// engine/api-spec-generator/openapi-parser.ts — Parse OpenAPI 3.x / Swagger 2.0 JSON (SPEC-286)
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
const HTTP_METHODS = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options'];
function resolveRef(ref, doc) {
    const parts = ref.replace(/^#\//, '').split('/');
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    let current = doc;
    for (const part of parts) {
        // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
        current = current?.[part];
        if (current === undefined || current === null) {
            return undefined;
        }
    }
    return current;
}
function extractFieldsFromSchema(schema, doc, requiredFields = []) {
    const resolvedSchema = schema.$ref !== undefined ? (resolveRef(schema.$ref, doc) ?? schema) : schema;
    const schemaRequired = resolvedSchema.required ?? [];
    const allRequired = [...new Set([...requiredFields, ...schemaRequired])];
    const fields = [];
    const properties = resolvedSchema.properties ?? {};
    for (const [name, prop] of Object.entries(properties)) {
        const resolved = prop.$ref !== undefined ? (resolveRef(prop.$ref, doc) ?? prop) : prop;
        fields.push({
            name,
            type: resolved.type ?? 'string',
            required: allRequired.includes(name),
            format: resolved.format,
            description: resolved.description,
            enumValues: resolved.enum,
        });
    }
    return fields;
}
function extractParameterFields(params, doc) {
    return params.map((p) => {
        const schema = p.schema ?? {};
        const resolved = schema.$ref !== undefined ? (resolveRef(schema.$ref, doc) ?? schema) : schema;
        return {
            name: p.name ?? 'unknown',
            type: resolved.type ?? 'string',
            required: p.required === true,
            format: resolved.format,
            description: p.description ?? resolved.description,
            enumValues: resolved.enum,
        };
    });
}
function extractRequestBodyFields(body, doc) {
    const jsonContent = body.content?.['application/json'];
    if (jsonContent === undefined) {
        return [];
    }
    const schema = jsonContent.schema;
    if (schema === undefined) {
        return [];
    }
    return extractFieldsFromSchema(schema, doc);
}
function extractResponses(responses) {
    return Object.entries(responses).map(([code, resp]) => ({
        statusCode: parseInt(code, 10),
        description: resp.description ?? '',
    }));
}
function deriveResourceGroup(path, tags) {
    if (tags.length > 0) {
        return tags[0] ?? 'General';
    }
    const segments = path.split('/').filter((s) => s.length > 0 && !s.startsWith('{'));
    const skip = new Set(['api', 'v1', 'v2', 'v3', 'rest']);
    const meaningful = segments.find((s) => !skip.has(s.toLowerCase()));
    if (meaningful === undefined) {
        return 'General';
    }
    return meaningful.charAt(0).toUpperCase() + meaningful.slice(1);
}
function buildTitle(method, path, summary) {
    if (summary !== undefined && summary.trim().length > 0) {
        return summary.trim();
    }
    const methodLabel = {
        get: 'Get',
        post: 'Create',
        put: 'Update',
        patch: 'Patch',
        delete: 'Delete',
        head: 'Head',
        options: 'Options',
    };
    const segments = path.split('/').filter((s) => s.length > 0 && !s.startsWith('{'));
    const skip = new Set(['api', 'v1', 'v2', 'v3', 'rest']);
    const resource = segments
        .filter((s) => !skip.has(s.toLowerCase()))
        .map((s) => s.charAt(0).toUpperCase() + s.slice(1))
        .join(' ');
    return `${methodLabel[method.toLowerCase()] ?? method.toUpperCase()} ${resource}`.trim();
}
// ---------------------------------------------------------------------------
// Main parser helpers
// ---------------------------------------------------------------------------
function extractPathItemOperations(path, pathItem, doc) {
    const ops = [];
    for (const method of HTTP_METHODS) {
        const op = pathItem[method];
        if (op === undefined) {
            continue;
        }
        const tags = op.tags ?? [];
        const fields = [
            ...extractParameterFields(op.parameters ?? [], doc),
            ...(op.requestBody !== undefined ? extractRequestBodyFields(op.requestBody, doc) : []),
        ];
        const responses = op.responses !== undefined ? extractResponses(op.responses) : [];
        const externalId = op.operationId !== undefined && op.operationId.length > 0
            ? op.operationId
            : `${method.toUpperCase()} ${path}`;
        ops.push({
            externalId,
            title: buildTitle(method, path, op.summary),
            description: op.description ?? op.summary ?? '',
            method: method.toUpperCase(),
            path,
            tags,
            fields,
            responses,
            resourceGroup: deriveResourceGroup(path, tags),
        });
    }
    return ops;
}
// ---------------------------------------------------------------------------
// Main parser
// ---------------------------------------------------------------------------
export function parseOpenApi(jsonContent) {
    let doc;
    try {
        doc = JSON.parse(jsonContent);
    }
    catch {
        throw new Error('Invalid OpenAPI JSON: failed to parse document');
    }
    const source = doc.swagger !== undefined ? 'swagger' : 'openapi';
    const title = doc.info?.title ?? 'Untitled API';
    const version = doc.info?.version ?? '1.0.0';
    const description = doc.info?.description ?? '';
    const paths = doc.paths ?? {};
    const operations = [];
    for (const [path, rawPathItem] of Object.entries(paths)) {
        if (rawPathItem === null || rawPathItem === undefined || typeof rawPathItem !== 'object') {
            continue;
        }
        const pathItem = rawPathItem;
        operations.push(...extractPathItemOperations(path, pathItem, doc));
    }
    return { source, title, version, description, operations };
}
//# sourceMappingURL=openapi-parser.js.map