/**
 * OpenAPI Auth Extractors
 * 
 * Ported from Hoppscotch's openapi/index.ts
 * Handles authentication scheme parsing for v2 and v3
 */ /* eslint-disable @typescript-eslint/no-explicit-any */ import { isOpenAPIV3Operation } from './index';
/**
 * Resolves OpenAPI v3 security scheme object to Brainfish auth
 */ function resolveOpenAPIV3SecurityObj(scheme, _schemeData// Used for OAuth to pass params
) {
    if (scheme.type === 'http') {
        if (scheme.scheme === 'basic') {
            return {
                authType: 'basic',
                authActive: true,
                username: '',
                password: ''
            };
        } else if (scheme.scheme === 'bearer') {
            return {
                authType: 'bearer',
                authActive: true,
                token: ''
            };
        }
        return {
            authType: 'none',
            authActive: true
        };
    } else if (scheme.type === 'apiKey') {
        if (scheme.in === 'header') {
            return {
                authType: 'api-key',
                authActive: true,
                addTo: 'HEADERS',
                key: scheme.name,
                value: ''
            };
        } else if (scheme.in === 'query') {
            return {
                authType: 'api-key',
                authActive: true,
                addTo: 'QUERY_PARAMS',
                key: scheme.name,
                value: ''
            };
        }
    } else if (scheme.type === 'oauth2') {
        // Select flow on first come basis: authorizationCode > implicit > password > clientCredentials
        if (scheme.flows?.authorizationCode) {
            return {
                authType: 'oauth-2',
                authActive: true,
                grantTypeInfo: {
                    grantType: 'AUTHORIZATION_CODE',
                    authEndpoint: scheme.flows.authorizationCode.authorizationUrl ?? '',
                    clientID: '',
                    scopes: _schemeData.join(' '),
                    token: '',
                    isPKCE: false,
                    tokenEndpoint: scheme.flows.authorizationCode.tokenUrl ?? '',
                    clientSecret: '',
                    authRequestParams: [],
                    refreshRequestParams: [],
                    tokenRequestParams: []
                },
                addTo: 'HEADERS'
            };
        } else if (scheme.flows?.implicit) {
            return {
                authType: 'oauth-2',
                authActive: true,
                grantTypeInfo: {
                    grantType: 'IMPLICIT',
                    authEndpoint: scheme.flows.implicit.authorizationUrl ?? '',
                    clientID: '',
                    token: '',
                    scopes: _schemeData.join(' '),
                    authRequestParams: [],
                    refreshRequestParams: []
                },
                addTo: 'HEADERS'
            };
        } else if (scheme.flows?.password) {
            return {
                authType: 'oauth-2',
                authActive: true,
                grantTypeInfo: {
                    grantType: 'PASSWORD',
                    clientID: '',
                    authEndpoint: scheme.flows.password.tokenUrl ?? '',
                    clientSecret: '',
                    password: '',
                    username: '',
                    token: '',
                    scopes: _schemeData.join(' '),
                    refreshRequestParams: [],
                    tokenRequestParams: []
                },
                addTo: 'HEADERS'
            };
        } else if (scheme.flows?.clientCredentials) {
            return {
                authType: 'oauth-2',
                authActive: true,
                grantTypeInfo: {
                    grantType: 'CLIENT_CREDENTIALS',
                    authEndpoint: scheme.flows.clientCredentials.tokenUrl ?? '',
                    clientID: '',
                    clientSecret: '',
                    scopes: _schemeData.join(' '),
                    token: '',
                    clientAuthentication: 'IN_BODY',
                    refreshRequestParams: [],
                    tokenRequestParams: []
                },
                addTo: 'HEADERS'
            };
        }
        // Default OAuth2
        return {
            authType: 'oauth-2',
            authActive: true,
            grantTypeInfo: {
                grantType: 'AUTHORIZATION_CODE',
                authEndpoint: '',
                clientID: '',
                scopes: _schemeData.join(' '),
                token: '',
                isPKCE: false,
                tokenEndpoint: '',
                clientSecret: '',
                authRequestParams: [],
                refreshRequestParams: [],
                tokenRequestParams: []
            },
            addTo: 'HEADERS'
        };
    } else if (scheme.type === 'openIdConnect') {
        return {
            authType: 'oauth-2',
            authActive: true,
            grantTypeInfo: {
                grantType: 'AUTHORIZATION_CODE',
                authEndpoint: '',
                clientID: '',
                scopes: _schemeData.join(' '),
                token: '',
                isPKCE: false,
                tokenEndpoint: '',
                clientSecret: '',
                authRequestParams: [],
                refreshRequestParams: [],
                tokenRequestParams: []
            },
            addTo: 'HEADERS'
        };
    }
    return {
        authType: 'none',
        authActive: true
    };
}
/**
 * Resolves OpenAPI v3 security scheme
 */ function resolveOpenAPIV3SecurityScheme(doc, schemeName, schemeData) {
    const scheme = doc.components?.securitySchemes?.[schemeName];
    if (!scheme) return {
        authType: 'none',
        authActive: true
    };
    return resolveOpenAPIV3SecurityObj(scheme, schemeData);
}
/**
 * Resolves OpenAPI v3 security requirements
 */ function resolveOpenAPIV3Security(doc, security) {
    // Only consider the first security requirement
    const sec = security[0];
    if (!sec) return {
        authType: 'none',
        authActive: true
    };
    // Only consider the first security condition within the first condition
    const [schemeName, schemeData] = Object.entries(sec)[0] ?? [
        undefined,
        undefined
    ];
    if (!schemeName || !schemeData) return {
        authType: 'none',
        authActive: true
    };
    return resolveOpenAPIV3SecurityScheme(doc, schemeName, schemeData);
}
/**
 * Parses OpenAPI v3 authentication
 */ export function parseOpenAPIV3Auth(doc, op) {
    const rootAuth = doc.security ? resolveOpenAPIV3Security(doc, doc.security) : undefined;
    const opAuth = op.security ? resolveOpenAPIV3Security(doc, op.security) : undefined;
    return opAuth ?? rootAuth ?? {
        authType: 'none',
        authActive: true
    };
}
/**
 * Resolves OpenAPI v2 security scheme
 */ function resolveOpenAPIV2SecurityScheme(scheme, _schemeData) {
    if (scheme.type === 'basic') {
        return {
            authType: 'basic',
            authActive: true,
            username: '',
            password: ''
        };
    } else if (scheme.type === 'apiKey') {
        // V2 only supports in: header and in: query
        return {
            authType: 'api-key',
            addTo: scheme.in === 'header' ? 'HEADERS' : 'QUERY_PARAMS',
            authActive: true,
            key: scheme.name,
            value: ''
        };
    } else if (scheme.type === 'oauth2') {
        // Select flow: accessCode > implicit > password > application
        if (scheme.flow === 'accessCode') {
            return {
                authType: 'oauth-2',
                authActive: true,
                grantTypeInfo: {
                    authEndpoint: scheme.authorizationUrl ?? '',
                    clientID: '',
                    clientSecret: '',
                    grantType: 'AUTHORIZATION_CODE',
                    scopes: _schemeData.join(' '),
                    token: '',
                    isPKCE: false,
                    tokenEndpoint: scheme.tokenUrl ?? '',
                    authRequestParams: [],
                    refreshRequestParams: [],
                    tokenRequestParams: []
                },
                addTo: 'HEADERS'
            };
        } else if (scheme.flow === 'implicit') {
            return {
                authType: 'oauth-2',
                authActive: true,
                grantTypeInfo: {
                    authEndpoint: scheme.authorizationUrl ?? '',
                    clientID: '',
                    grantType: 'IMPLICIT',
                    scopes: _schemeData.join(' '),
                    token: '',
                    authRequestParams: [],
                    refreshRequestParams: []
                },
                addTo: 'HEADERS'
            };
        } else if (scheme.flow === 'application') {
            return {
                authType: 'oauth-2',
                authActive: true,
                grantTypeInfo: {
                    authEndpoint: scheme.tokenUrl ?? '',
                    clientID: '',
                    clientSecret: '',
                    grantType: 'CLIENT_CREDENTIALS',
                    scopes: _schemeData.join(' '),
                    token: '',
                    clientAuthentication: 'IN_BODY',
                    refreshRequestParams: [],
                    tokenRequestParams: []
                },
                addTo: 'HEADERS'
            };
        } else if (scheme.flow === 'password') {
            return {
                authType: 'oauth-2',
                authActive: true,
                grantTypeInfo: {
                    grantType: 'PASSWORD',
                    authEndpoint: scheme.tokenUrl ?? '',
                    clientID: '',
                    clientSecret: '',
                    password: '',
                    scopes: _schemeData.join(' '),
                    token: '',
                    username: '',
                    refreshRequestParams: [],
                    tokenRequestParams: []
                },
                addTo: 'HEADERS'
            };
        }
        // Default OAuth2
        return {
            authType: 'oauth-2',
            authActive: true,
            grantTypeInfo: {
                authEndpoint: '',
                clientID: '',
                clientSecret: '',
                grantType: 'AUTHORIZATION_CODE',
                scopes: _schemeData.join(' '),
                token: '',
                isPKCE: false,
                tokenEndpoint: '',
                authRequestParams: [],
                refreshRequestParams: [],
                tokenRequestParams: []
            },
            addTo: 'HEADERS'
        };
    }
    return {
        authType: 'none',
        authActive: true
    };
}
/**
 * Resolves OpenAPI v2 security definition
 */ function resolveOpenAPIV2SecurityDef(doc, schemeName, schemeData) {
    const scheme = Object.entries(doc.securityDefinitions ?? {}).find(([name])=>schemeName === name);
    if (!scheme) return {
        authType: 'none',
        authActive: true
    };
    const schemeObj = scheme[1];
    return resolveOpenAPIV2SecurityScheme(schemeObj, schemeData);
}
/**
 * Resolves OpenAPI v2 security requirements
 */ function resolveOpenAPIV2Security(doc, security) {
    // Only consider the first security requirement
    const sec = security[0];
    if (!sec) return {
        authType: 'none',
        authActive: true
    };
    // Only consider the first security condition within the first condition
    const [schemeName, schemeData] = Object.entries(sec)[0] ?? [
        undefined,
        undefined
    ];
    if (!schemeName || !schemeData) return {
        authType: 'none',
        authActive: true
    };
    return resolveOpenAPIV2SecurityDef(doc, schemeName, schemeData);
}
/**
 * Parses OpenAPI v2 authentication
 */ export function parseOpenAPIV2Auth(doc, op) {
    const rootAuth = doc.security ? resolveOpenAPIV2Security(doc, doc.security) : undefined;
    const opAuth = op.security ? resolveOpenAPIV2Security(doc, op.security) : undefined;
    return opAuth ?? rootAuth ?? {
        authType: 'none',
        authActive: true
    };
}
/**
 * Parses OpenAPI authentication (v2 or v3)
 */ export function parseOpenAPIAuth(doc, op// OpenAPIOperationType
) {
    return isOpenAPIV3Operation(doc, op) ? parseOpenAPIV3Auth(doc, op) : parseOpenAPIV2Auth(doc, op);
}
export function extractSecuritySchemes(doc) {
    const schemes = [];
    // Check if it's v3
    const v3Doc = doc;
    if (v3Doc.components?.securitySchemes) {
        for (const [name, schemeRef] of Object.entries(v3Doc.components.securitySchemes)){
            // Skip references for now
            if ('$ref' in schemeRef) continue;
            const scheme = schemeRef;
            const auth = resolveOpenAPIV3SecurityObj(scheme, []);
            let type = 'none';
            let description = scheme.description;
            if (scheme.type === 'http') {
                if (scheme.scheme === 'basic') type = 'basic';
                else if (scheme.scheme === 'bearer') type = 'bearer';
            } else if (scheme.type === 'apiKey') {
                type = 'api-key';
                description = description || `API Key in ${scheme.in}: ${scheme.name}`;
            } else if (scheme.type === 'oauth2') {
                type = 'oauth2';
            }
            if (type !== 'none') {
                schemes.push({
                    name,
                    type,
                    auth,
                    description
                });
            }
        }
    }
    // Check if it's v2
    const v2Doc = doc;
    if (v2Doc.securityDefinitions) {
        for (const [name, scheme] of Object.entries(v2Doc.securityDefinitions)){
            const auth = resolveOpenAPIV2SecurityScheme(scheme, []);
            let type = 'none';
            let description = scheme.description;
            if (scheme.type === 'basic') {
                type = 'basic';
            } else if (scheme.type === 'apiKey') {
                type = 'api-key';
                description = description || `API Key in ${scheme.in}: ${scheme.name}`;
            } else if (scheme.type === 'oauth2') {
                type = 'oauth2';
            }
            if (type !== 'none') {
                schemes.push({
                    name,
                    type,
                    auth,
                    description
                });
            }
        }
    }
    return schemes;
}
/**
 * Get the default/recommended auth from the spec
 * Based on the global security requirement
 */ export function getDefaultAuth(doc) {
    // Check v3 global security
    const v3Doc = doc;
    if (v3Doc.security && v3Doc.security.length > 0) {
        return resolveOpenAPIV3Security(v3Doc, v3Doc.security);
    }
    // Check v2 global security
    const v2Doc = doc;
    if (v2Doc.security && v2Doc.security.length > 0) {
        return resolveOpenAPIV2Security(v2Doc, v2Doc.security);
    }
    // If no global security, return the first scheme found
    const schemes = extractSecuritySchemes(doc);
    if (schemes.length > 0) {
        return schemes[0].auth;
    }
    return null;
}
/**
 * Extract additional security headers required by an endpoint
 * These are API key headers that are NOT the primary auth (handled by global auth)
 * 
 * For example, if an endpoint requires both `access-token` and `agent-key`,
 * the primary auth handles `access-token`, and this returns `agent-key` as additional header
 */ export function extractSecurityHeaders(doc, op, primaryAuthKey// The key handled by global auth (e.g., 'access-token')
) {
    const headers = [];
    try {
        const v3Doc = doc;
        const v3Op = op;
        // Get security requirements (operation-level or global)
        const security = v3Op.security ?? v3Doc.security ?? [];
        if (security.length === 0) return [];
        // Process the first security requirement (they are OR'd, we use first)
        const secReq = security[0];
        if (!secReq) return [];
        // Get all required scheme names
        const schemeNames = Object.keys(secReq);
        for (const schemeName of schemeNames){
            const scheme = v3Doc.components?.securitySchemes?.[schemeName];
            if (!scheme) continue;
            // Only handle API keys in headers
            if (scheme.type === 'apiKey' && scheme.in === 'header') {
                // Skip if this is the primary auth key
                if (primaryAuthKey && scheme.name === primaryAuthKey) continue;
                headers.push({
                    key: scheme.name,
                    value: '',
                    description: scheme.description || `Required: ${schemeName}`,
                    active: true,
                    required: true
                });
            }
        }
    } catch  {
    // Return empty on error
    }
    return headers;
}
