/**
 * Global BigInt JSON serialization support.
 * algosdk v3 returns BigInt for numeric fields; JSON.stringify cannot handle them natively.
 * This patch ensures all JSON.stringify calls throughout the codebase work with BigInt values.
 */
BigInt.prototype.toJSON = function () {
    return Number(this);
};
const DEFAULT_ITEMS_PER_PAGE = 10;
export class ResponseProcessor {
    static generateNextPageToken(page) {
        return btoa(`page_${page}`);
    }
    static decodePageToken(token) {
        try {
            const decoded = atob(token);
            const page = parseInt(decoded.replace('page_', ''));
            return isNaN(page) ? 1 : page;
        }
        catch {
            return 1;
        }
    }
    static shouldPaginateArray(array, itemsPerPage) {
        return array.length > itemsPerPage;
    }
    static shouldPaginateObject(obj, itemsPerPage) {
        return Object.keys(obj).length > itemsPerPage;
    }
    static paginateObject(obj, itemsPerPage, pageToken) {
        const entries = Object.entries(obj);
        const totalItems = entries.length;
        const totalPages = Math.ceil(totalItems / itemsPerPage);
        const currentPage = pageToken ? this.decodePageToken(pageToken) : 1;
        const startIndex = (currentPage - 1) * itemsPerPage;
        const endIndex = startIndex + itemsPerPage;
        const hasNextPage = endIndex < totalItems;
        const paginatedEntries = entries.slice(startIndex, endIndex);
        const paginatedObject = Object.fromEntries(paginatedEntries);
        return {
            items: paginatedObject,
            metadata: {
                totalItems,
                itemsPerPage,
                currentPage,
                totalPages,
                hasNextPage,
                ...(hasNextPage && {
                    pageToken: this.generateNextPageToken(currentPage + 1),
                }),
            }
        };
    }
    static paginateArray(array, itemsPerPage, pageToken) {
        const totalItems = array.length;
        const totalPages = Math.ceil(totalItems / itemsPerPage);
        const currentPage = pageToken ? this.decodePageToken(pageToken) : 1;
        const startIndex = (currentPage - 1) * itemsPerPage;
        const endIndex = startIndex + itemsPerPage;
        const hasNextPage = endIndex < totalItems;
        const paginatedItems = array.slice(startIndex, endIndex);
        return {
            items: paginatedItems,
            metadata: {
                totalItems,
                itemsPerPage,
                currentPage,
                totalPages,
                hasNextPage,
                ...(hasNextPage && {
                    pageToken: this.generateNextPageToken(currentPage + 1),
                }),
            }
        };
    }
    static processResponse(response, pageToken, itemsPerPage) {
        const perPage = itemsPerPage || DEFAULT_ITEMS_PER_PAGE;
        // Handle array responses
        if (Array.isArray(response)) {
            const { items, metadata } = this.paginateArray(response, perPage, pageToken);
            return {
                content: [{
                        type: 'text',
                        text: JSON.stringify({ data: items, metadata }, null, 2)
                    }]
            };
        }
        // Handle object responses with array values
        if (typeof response === 'object' && response !== null) {
            const processed = JSON.parse(JSON.stringify(response));
            let paginatedField;
            let paginationMetadata;
            for (const key in processed) {
                if (Array.isArray(processed[key])) {
                    if (this.shouldPaginateArray(processed[key], perPage)) {
                        const result = this.paginateArray(processed[key], perPage, pageToken);
                        processed[key] = result.items;
                        if (result.metadata) {
                            paginatedField = key;
                            paginationMetadata = result.metadata;
                        }
                    }
                }
                else if (typeof processed[key] === 'object' && processed[key] !== null) {
                    if (this.shouldPaginateObject(processed[key], perPage)) {
                        const result = this.paginateObject(processed[key], perPage, pageToken);
                        processed[key] = result.items;
                        if (result.metadata) {
                            paginatedField = key;
                            paginationMetadata = result.metadata;
                        }
                    }
                    const nestedResult = this.processResponse(processed[key], pageToken, perPage);
                    if (nestedResult.content?.[0]?.text) {
                        try {
                            processed[key] = JSON.parse(nestedResult.content[0].text);
                        }
                        catch {
                            processed[key] = nestedResult.content[0].text;
                        }
                    }
                }
            }
            if (paginationMetadata) {
                return {
                    content: [{
                            type: 'text',
                            text: JSON.stringify({
                                data: processed,
                                metadata: { ...paginationMetadata, arrayField: paginatedField }
                            }, null, 2)
                        }]
                };
            }
            return {
                content: [{
                        type: 'text',
                        text: JSON.stringify({ data: processed }, null, 2)
                    }]
            };
        }
        return {
            content: [{
                    type: 'text',
                    text: JSON.stringify({ data: response }, null, 2)
                }]
        };
    }
    static wrapResourceHandler(handler) {
        return ((...args) => handler(...args));
    }
}
