"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LogsGraphQLClient = exports.MissingMetadataError = exports.MissingInvocationError = exports.MissingAppLogLinesError = exports.MissingAppLogsError = void 0;
const sanitizeLogLine = (line) => ({
    timestamp: line.timestamp,
    level: line.level || undefined,
    message: line.message || undefined,
    other: line.other
});
class MissingAppLogsError extends Error {
}
exports.MissingAppLogsError = MissingAppLogsError;
class MissingAppLogLinesError extends Error {
}
exports.MissingAppLogLinesError = MissingAppLogLinesError;
class MissingInvocationError extends Error {
}
exports.MissingInvocationError = MissingInvocationError;
class MissingMetadataError extends Error {
}
exports.MissingMetadataError = MissingMetadataError;
class LogsGraphQLClient {
    graphqlClient;
    constructor(graphqlClient) {
        this.graphqlClient = graphqlClient;
    }
    async viewInvocationLogs(details) {
        const result = await this.getInvocationLogs(details);
        if (!result.lines.length) {
            throw new MissingInvocationError();
        }
        return {
            ...this.extractInvocationInfo(result.metadata),
            logs: result.lines.map(sanitizeLogLine)
        };
    }
    async viewAppLogsV2(details, invocationMap, logLinesWithInvocation, totalRecieved) {
        const query = `
      query forge_cli_getApplicationLogsV2(
        $appId: String!,
        $environmentId: String!,
        $dateSearchInput: DateSearchInput,
        $offset: Int!,
        $limit: Int!,
        $queryStartTime: String!,
        $runtime: String
      ) {
        appLogsWithMetaData(
          appId: $appId
          environmentId: $environmentId
          limit: $limit
          offset: $offset
          queryStartTime: $queryStartTime
          query: {
            dates: $dateSearchInput
            runtime: $runtime
          }
        ) {
          appLogs {
            appId
            appVersion
            message
            environmentId
            invocationId
            functionKey
            lvl
            error
            other
            ts
          }
          hasNextPage
          totalLogs
          __typename
        }
      }
    `;
        const result = await this.graphqlClient.query(query, details);
        if (!result || !result.appLogsWithMetaData || !result.appLogsWithMetaData.appLogs) {
            throw new MissingAppLogsError();
        }
        for (const logLine of result.appLogsWithMetaData.appLogs) {
            if (details.grouped) {
                let logsMetadata = invocationMap.get(logLine.invocationId);
                if (!logsMetadata) {
                    logsMetadata = {
                        id: logLine.invocationId,
                        appVersion: logLine.appVersion,
                        function: logLine.functionKey || undefined,
                        trigger: undefined,
                        logs: []
                    };
                }
                logsMetadata.logs.push({
                    message: logLine.message || undefined,
                    other: logLine.other ? JSON.parse(logLine.other) : [],
                    level: logLine.lvl || undefined,
                    timestamp: logLine.ts
                });
                invocationMap.set(logLine.invocationId, logsMetadata);
            }
            logLinesWithInvocation.push({
                id: logLine.invocationId,
                appVersion: logLine.appVersion,
                function: logLine.functionKey || undefined,
                logs: [
                    {
                        message: logLine.message || undefined,
                        other: logLine.other ? JSON.parse(logLine.other) : [],
                        level: logLine.lvl || undefined,
                        timestamp: logLine.ts
                    }
                ]
            });
        }
        const serverSideMaxLimit = result.appLogsWithMetaData.appLogs.length;
        totalRecieved += serverSideMaxLimit;
        if (result.appLogsWithMetaData.hasNextPage && details.maxLimit > totalRecieved) {
            details.offset = details.offset + serverSideMaxLimit;
            details.limit = details.limit - serverSideMaxLimit;
            return this.viewAppLogsV2(details, invocationMap, logLinesWithInvocation, totalRecieved);
        }
        logLinesWithInvocation.forEach((l) => {
            l.logs.sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp));
            return l;
        });
        logLinesWithInvocation.sort((a, b) => {
            if (a.logs.length && b.logs.length) {
                return Date.parse(a.logs[0].timestamp) - Date.parse(b.logs[0].timestamp);
            }
            return 0;
        });
        const invocations = [...invocationMap.values()];
        return details.grouped ? invocations : logLinesWithInvocation;
    }
    async viewAppLogs(details) {
        const query = `
      query forge_cli_getApplicationLogs($appId: ID!, $environmentId: [ID!]!, $limit: Int!, $contextAri: [ID!], $startTime: String) {
        appLogs(
          appId: $appId,
          environmentId: $environmentId,
          last: $limit,
          query: {
            installationContexts: $contextAri,
            dates: {
              earliestStart: $startTime
            }
          }
        ) {
          nodes {
            id
            function {
              key
            }
            appVersion
            trigger {
              type
            }
            appLogLines {
              edges {
                node {
                  timestamp
                  level
                  message
                  other
                }
                cursor
              }
              pageInfo {
                hasNextPage
              }
            }
          }
        }
      }
    `;
        const result = await this.graphqlClient.query(query, details);
        if (!result.appLogs || !result.appLogs.nodes) {
            throw new MissingAppLogsError();
        }
        const invocations = [];
        for (const node of result.appLogs.nodes) {
            if (node) {
                const invocation = this.extractInvocationInfo(node);
                if (node.appLogLines != null) {
                    const { cursor, lines } = this.extractLogLines(node.appLogLines);
                    const firstLogs = lines.map(sanitizeLogLine);
                    if (!node.appLogLines.pageInfo.hasNextPage) {
                        invocation.logs = firstLogs;
                    }
                    else {
                        const nextLines = await this.getInvocationLogs({ invocationId: invocation.id, after: cursor });
                        invocation.logs = [...firstLogs, ...nextLines.lines.map(sanitizeLogLine)];
                    }
                }
                invocations.push(invocation);
            }
        }
        return invocations;
    }
    extractInvocationInfo(metadata) {
        return {
            id: metadata.id,
            appVersion: metadata.appVersion,
            function: (metadata.function && metadata.function.key) || undefined,
            trigger: (metadata.trigger && metadata.trigger.type) || undefined,
            logs: []
        };
    }
    extractLogLines(connection) {
        const lines = [];
        let cursor;
        for (const edge of connection.edges || []) {
            if (edge) {
                cursor = edge.cursor;
                lines.push(edge.node);
            }
        }
        return { cursor, lines };
    }
    async getInvocationLogs(filter) {
        const query = `
      query forge_cli_getInvocationLogs($invocationId: ID!, $after: String) {
        appLogLines(
          after: $after,
          invocation: $invocationId
        ) {
          metadata {
            id
            function {
              key
            }
            appVersion
            trigger {
              type
            }
          }
          edges {
            node {
              timestamp
              level
              message
              other
            }
            cursor
          }
          pageInfo {
            hasNextPage
          }
        }
      }
    `;
        const result = await this.graphqlClient.query(query, filter);
        if (!result.appLogLines) {
            throw new MissingAppLogLinesError();
        }
        const { cursor, lines } = this.extractLogLines(result.appLogLines);
        if (result.appLogLines.pageInfo.hasNextPage) {
            const nextLines = await this.getInvocationLogs({
                ...filter,
                after: cursor
            });
            lines.push(...nextLines.lines);
        }
        return {
            lines,
            metadata: result.appLogLines.metadata
        };
    }
}
exports.LogsGraphQLClient = LogsGraphQLClient;
