"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getPropsFilterSlider = exports.getPropsFilterRange = exports.getPropsFilterList = exports.getPropsShared = exports.getPropsReact = exports.getPropsResults = exports.getPropsBase = exports.getPropsSensorSort = exports.getPropsSensorInventoryAvailable = exports.getPropsSensorPublished = exports.getPropsSensorCollection = exports.getPropsSensorCustom = exports.getPropsSensors = exports.getPropsFilterGroupOption = exports.getPropsFilterGroup = void 0;
const search_internals_1 = require("@usereactify/search-internals");
const components_1 = require("../components");
const curation_1 = require("./curation");
const sortOption_1 = require("./sortOption");
const filters_1 = require("./filters");
const hooks_1 = require("../hooks");
const package_json_1 = __importDefault(require("../../package.json"));
const getPropsFilterGroup = (options) => {
    var _a, _b;
    return [
        ...(_b = (_a = options.filterGroup) === null || _a === void 0 ? void 0 : _a.options.map((filterGroupOption) => (0, exports.getPropsFilterGroupOption)(options, filterGroupOption))) !== null && _b !== void 0 ? _b : [],
        ...(0, exports.getPropsSensors)(options),
        (0, exports.getPropsResults)(options),
    ];
};
exports.getPropsFilterGroup = getPropsFilterGroup;
const getPropsFilterGroupOption = (options, filterGroupOption) => {
    var _a;
    let filterProps = {};
    if (filterGroupOption.displayType === "slider") {
        const sliderFilterProps = (0, exports.getPropsFilterSlider)(filterGroupOption, (_a = options.provider.query) !== null && _a !== void 0 ? _a : {});
        filterProps = {
            defaultQuery: () => sliderFilterProps.defaultQuery,
            customQuery: () => sliderFilterProps.customQuery,
        };
    }
    if (filterGroupOption.displayType === "single" || filterGroupOption.displayType === "multi") {
        if (filterGroupOption.displayView === "range") {
            filterProps = (0, exports.getPropsFilterRange)(filterGroupOption);
        }
        else {
            filterProps = (0, exports.getPropsFilterList)(filterGroupOption);
        }
    }
    const sharedProps = (0, exports.getPropsShared)(options, filterGroupOption);
    return Object.assign(Object.assign({}, sharedProps), filterProps);
};
exports.getPropsFilterGroupOption = getPropsFilterGroupOption;
const getPropsSensors = (options) => {
    return [
        ...(0, exports.getPropsSensorCustom)(options),
        (0, exports.getPropsSensorCollection)(options),
        (0, exports.getPropsSensorPublished)(options),
        (0, exports.getPropsSensorInventoryAvailable)(options),
        (0, exports.getPropsSensorSort)(options),
    ].filter(Boolean);
};
exports.getPropsSensors = getPropsSensors;
const getPropsSensorCustom = (options) => {
    const sensors = options.provider.mode === "collection" ? options.config.sensors.collection : options.config.sensors.search;
    return sensors.map((sensor, index) => ({
        componentId: `SensorCustom_${index}`,
        customQuery: () => sensor,
        source: search_internals_1.ReactiveComponent,
    }));
};
exports.getPropsSensorCustom = getPropsSensorCustom;
const getPropsSensorCollection = (options) => {
    if (options.provider.mode !== "collection") {
        return null;
    }
    return {
        componentId: "SensorCollection",
        customQuery: () => {
            if (options.provider.mode !== "collection") {
                return null;
            }
            const conditions = [];
            if (options.provider.market) {
                conditions.push({
                    nested: {
                        path: "curations",
                        query: {
                            bool: {
                                should: [
                                    {
                                        nested: {
                                            path: "collections",
                                            query: {
                                                term: {
                                                    "collections.handle.keyword": options.provider.collectionHandle,
                                                },
                                            },
                                        },
                                    },
                                    {
                                        nested: {
                                            path: "curations",
                                            query: {
                                                term: {
                                                    "curations.collectionHandle.keyword": options.provider.collectionHandle,
                                                },
                                            },
                                        },
                                    },
                                ],
                                must: [{
                                        nested: {
                                            path: "curations",
                                            query: {
                                                term: {
                                                    "curations.markets.keyword": options.provider.market,
                                                },
                                            },
                                        },
                                    }]
                            },
                        },
                    },
                });
            }
            return {
                query: {
                    bool: {
                        should: [
                            {
                                nested: {
                                    path: "collections",
                                    query: {
                                        term: {
                                            "collections.handle.keyword": options.provider.collectionHandle,
                                        },
                                    },
                                },
                            },
                            {
                                nested: {
                                    path: "curations",
                                    query: {
                                        term: {
                                            "curations.collectionHandle.keyword": options.provider.collectionHandle,
                                        },
                                    },
                                },
                            },
                        ],
                    },
                },
            };
        },
        source: search_internals_1.ReactiveComponent,
    };
};
exports.getPropsSensorCollection = getPropsSensorCollection;
const getPropsSensorPublished = (options) => {
    return {
        componentId: "SensorPublished",
        customQuery: () => {
            if (options.provider.market) {
                return {
                    query: {
                        bool: {
                            must: [{
                                    match: {
                                        markets: options.provider.market,
                                    },
                                }, {
                                    match: {
                                        published: true,
                                    },
                                }]
                        },
                    },
                };
            }
            return {
                query: {
                    match: {
                        published: true,
                    },
                },
            };
        },
        source: search_internals_1.ReactiveComponent,
    };
};
exports.getPropsSensorPublished = getPropsSensorPublished;
const getPropsSensorInventoryAvailable = (options) => {
    const filterStack = (0, filters_1.getFilterStack)(options);
    if (!filterStack || "show_all" === filterStack.inventoryVisibility) {
        return null;
    }
    return {
        componentId: "SensorInventoryAvailable",
        customQuery: () => ({
            query: {
                bool: {
                    should: [
                        {
                            bool: {
                                must: [
                                    {
                                        term: {
                                            type: {
                                                value: "product",
                                            },
                                        },
                                    },
                                    {
                                        nested: {
                                            path: "variants",
                                            query: {
                                                match: { "variants.available": true },
                                            },
                                        },
                                    },
                                ],
                            },
                        },
                        ...(options.provider.mode === "instant-search"
                            ? []
                            : [
                                {
                                    term: {
                                        type: {
                                            value: "callout",
                                        },
                                    },
                                },
                            ]),
                    ],
                    minimum_should_match: "1",
                },
            },
        }),
        source: search_internals_1.ReactiveComponent,
    };
};
exports.getPropsSensorInventoryAvailable = getPropsSensorInventoryAvailable;
const getPropsSensorSort = (options) => {
    const curation = (0, curation_1.getCuration)(options);
    const sortOption = (0, sortOption_1.getSortOption)(options);
    const sort = (0, sortOption_1.generateSortSort)({
        provider: options.provider,
        config: options.config,
        curation: curation,
        sortOption: sortOption,
    });
    const query = (0, sortOption_1.generateSortQuery)({
        provider: options.provider,
        sortOption: sortOption,
        curation: curation,
    });
    return {
        componentId: "SensorSort",
        customQuery: () => ({
            sort,
            query,
        }),
        source: search_internals_1.ReactiveComponent,
    };
};
exports.getPropsSensorSort = getPropsSensorSort;
const getPropsBase = (options) => {
    var _a;
    const props = {
        app: options.config.index,
        url: options.config.endpoint,
        credentials: options.provider.credentials,
        theme: options.provider.theme,
        initialState: (_a = options.provider.preload) === null || _a === void 0 ? void 0 : _a.state,
        transformSort: () => {
            const sortSensor = (0, exports.getPropsSensorSort)(options);
            const customQuery = sortSensor.customQuery();
            return customQuery.sort;
        },
        transformRequest: (request) => {
            if (request.url.endsWith("?")) {
                request.url = request.url.substring(0, request.url.length - 1);
            }
            return request;
        },
        transformResponse: (response) => __awaiter(void 0, void 0, void 0, function* () {
            var _a, _b, _c, _d;
            // support filtering inside nested aggregations by moving the inner aggregation
            // up one level such that reactivesearch understands it
            //
            // see useReactiveFilterListProps > defaultQuery to see how a filter is being applied
            // to variant aggregations to ensure that only in stock sizes are displayed as filter
            // options, this involves a nested filter, which requires this fix
            //
            // https://github.com/appbaseio/reactivesearch/issues/1530
            if ((_b = (_a = response === null || response === void 0 ? void 0 : response.aggregations) === null || _a === void 0 ? void 0 : _a.reactivesearch_nested) === null || _b === void 0 ? void 0 : _b.reactify_nested_outer) {
                response.aggregations.reactivesearch_nested =
                    (0, hooks_1.replaceDocCountWithParent)((_d = (_c = response === null || response === void 0 ? void 0 : response.aggregations) === null || _c === void 0 ? void 0 : _c.reactivesearch_nested) === null || _d === void 0 ? void 0 : _d.reactify_nested_outer);
            }
            return response;
        }),
        headers: {
            "x-reactify-shop": options.provider.shopifyPermanentDomain,
            "x-reactify-mode": options.provider.mode,
            "x-reactify-client-id": options.provider.clientId,
            "x-reactify-client-version": package_json_1.default.version,
        },
    };
    return props;
};
exports.getPropsBase = getPropsBase;
const getPropsResults = (options) => {
    var _a, _b, _c, _d, _e;
    const includeFieldsProp = (() => {
        var _a;
        return [
            ...((_a = options.provider.includeFields) !== null && _a !== void 0 ? _a : []),
            "id",
            "title",
            "type",
            "handle",
            "image",
            "variants.id",
            "variants.presentment_prices",
            "callout",
        ];
    })();
    const excludeFieldsProp = (() => {
        var _a;
        return [...((_a = options.provider.excludeFields) !== null && _a !== void 0 ? _a : [])];
    })();
    return {
        size: (_c = (_a = options.pageSize) !== null && _a !== void 0 ? _a : (_b = options.filterGroup) === null || _b === void 0 ? void 0 : _b.pageSize) !== null && _c !== void 0 ? _c : 20,
        URLParams: options.provider.mode === "instant-search" ? false : true,
        showLoader: false,
        dataField: "title",
        showResultStats: false,
        react: (0, exports.getPropsReact)(options),
        includeFields: includeFieldsProp,
        excludeFields: excludeFieldsProp,
        scrollTarget: options.scrollTarget,
        componentId: "page", // this sets ?page= in the URL
        scrollOnChange: false, // @todo make this better, it's really janky when enabled
        pagination: ((_d = options.filterGroup) === null || _d === void 0 ? void 0 : _d.paginationType) !== "infinite_scroll",
        infiniteScroll: ((_e = options.filterGroup) === null || _e === void 0 ? void 0 : _e.paginationType) === "infinite_scroll",
        renderNoResults: () => null, // always use only render, otherwise both are shown
        source: search_internals_1.ReactiveList,
        // defaultQuery: () => ({
        //   sort: ["_score"],
        //   query: {
        //     match_all: {}
        //   }
        // })
    };
};
exports.getPropsResults = getPropsResults;
const getPropsReact = (options, filterGroupOption) => {
    const sensorIds = (0, components_1.SENSOR_IDS)(options.provider.mode, options.config);
    const reactProp = (() => {
        var _a, _b, _c;
        if (filterGroupOption === null || filterGroupOption === void 0 ? void 0 : filterGroupOption.settingsShowEmptyValues) {
            return {
                and: sensorIds,
            };
        }
        return {
            and: [
                ...sensorIds,
                ...((_a = options.provider.additionalComponentIds) !== null && _a !== void 0 ? _a : []),
                ...((_c = (_b = options.filterGroup) === null || _b === void 0 ? void 0 : _b.options.map((filter) => filter.handle)) !== null && _c !== void 0 ? _c : []),
            ].filter((handle) => handle !== (filterGroupOption === null || filterGroupOption === void 0 ? void 0 : filterGroupOption.handle)),
        };
    })();
    return reactProp;
};
exports.getPropsReact = getPropsReact;
const getPropsShared = (options, filterGroupOption) => {
    const reactProp = (0, exports.getPropsReact)(options, filterGroupOption);
    const nestedFieldProp = (() => {
        const nestedFields = ["variants"];
        const topField = filterGroupOption.field.split(".")[0];
        if (nestedFields.includes(topField)) {
            return topField;
        }
        return undefined;
    })();
    const customQueryProp = (() => {
        if (!filterGroupOption.settingsHideUnavailable ||
            !filterGroupOption.field.startsWith("variants."))
            return undefined;
        return (value) => {
            if (!value)
                return {};
            // reactivesearch sometimes returns string, sometimes string[]
            const valueArray = "string" === typeof value ? [value] : value;
            if (0 === valueArray.length)
                return {};
            return {
                query: {
                    nested: {
                        path: "variants",
                        query: {
                            bool: {
                                must: [
                                    {
                                        match: {
                                            "variants.available": "true",
                                        },
                                    },
                                    {
                                        terms: {
                                            [filterGroupOption.field]: valueArray,
                                        },
                                    },
                                ],
                            },
                        },
                    },
                },
            };
        };
    })();
    const defaultQueryProp = (() => {
        if (!filterGroupOption.field.startsWith("variants.")) {
            return undefined;
        }
        // override the aggregation query to filter the results by the variants.available attribute
        return () => {
            return {
                aggs: {
                    reactivesearch_nested: {
                        nested: { path: "variants" },
                        aggs: {
                            reactify_nested_outer: {
                                filter: {
                                    bool: {
                                        minimum_should_match: 1,
                                        should: [
                                            {
                                                match: {
                                                    "variants.available": "true",
                                                },
                                            },
                                            {
                                                match: {
                                                    "variants.available": filterGroupOption.settingsHideUnavailable
                                                        ? "true"
                                                        : "false",
                                                },
                                            },
                                        ],
                                    },
                                },
                                aggs: {
                                    [filterGroupOption.field]: {
                                        terms: {
                                            field: filterGroupOption.field,
                                            size: 100,
                                            order: { _count: "desc" },
                                        },
                                        aggs: {
                                            parent_docs: { reverse_nested: {} },
                                        },
                                    },
                                },
                            },
                        },
                    },
                },
            };
        };
    })();
    const sourceProp = (() => {
        if (filterGroupOption.displayType === "slider") {
            return search_internals_1.ReactiveComponent;
        }
        if (filterGroupOption.displayType === "single") {
            if (filterGroupOption.displayView === "range") {
                return search_internals_1.SingleRange;
            }
            return search_internals_1.SingleList;
        }
        if (filterGroupOption.displayType === "multi") {
            if (filterGroupOption.displayView === "range") {
                return search_internals_1.MultiRange;
            }
            return search_internals_1.MultiList;
        }
        return;
    })();
    return {
        URLParams: true,
        componentId: filterGroupOption.handle,
        dataField: filterGroupOption.field,
        filterLabel: filterGroupOption.name,
        nestedField: nestedFieldProp,
        customQuery: customQueryProp,
        defaultQuery: defaultQueryProp,
        source: sourceProp,
        react: reactProp,
    };
};
exports.getPropsShared = getPropsShared;
const getPropsFilterList = (filterGroupOption) => {
    var _a, _b, _c, _d;
    return {
        size: parseInt(filterGroupOption.displaySize) || undefined,
        queryFormat: (_a = filterGroupOption.settingsFilterLogic) !== null && _a !== void 0 ? _a : "or",
        showFilter: (_b = filterGroupOption.settingsShowFilter) !== null && _b !== void 0 ? _b : true,
        showLoadMore: (_c = filterGroupOption.settingsShowMore) !== null && _c !== void 0 ? _c : false,
        showSearch: (_d = filterGroupOption.settingsShowSearch) !== null && _d !== void 0 ? _d : false,
        showRadio: false,
        showCheckbox: false,
    };
};
exports.getPropsFilterList = getPropsFilterList;
const getPropsFilterRange = (filterGroupOption) => {
    var _a, _b, _c, _d;
    const data = (_b = (_a = filterGroupOption.displayRangeOptions) === null || _a === void 0 ? void 0 : _a.map((option) => {
        const [label, start, end] = option.split(":");
        return {
            label: label,
            start: start ? parseInt(start) : 0,
            end: end ? parseInt(end) : Number.MAX_SAFE_INTEGER,
        };
    })) !== null && _b !== void 0 ? _b : [];
    return {
        queryFormat: (_c = filterGroupOption.settingsFilterLogic) !== null && _c !== void 0 ? _c : "or",
        showFilter: (_d = filterGroupOption.settingsShowFilter) !== null && _d !== void 0 ? _d : true,
        showRadio: false,
        showCheckbox: false,
        data: data,
    };
};
exports.getPropsFilterRange = getPropsFilterRange;
const getPropsFilterSlider = (filterGroupOption, query, value) => {
    var _a;
    const filterValue = value !== null && value !== void 0 ? value : JSON.parse((_a = new URLSearchParams(typeof window === "undefined" ? query : window.location.search).get(filterGroupOption.handle)) !== null && _a !== void 0 ? _a : "[0,0]");
    const defaultQuery = {
        aggs: {
            min: {
                min: {
                    field: filterGroupOption.field,
                },
            },
            max: {
                max: {
                    field: filterGroupOption.field,
                },
            },
        },
    };
    const customQuery = (() => {
        if (filterValue[0] === 0 && filterValue[1] === 0) {
            return;
        }
        return {
            query: {
                bool: {
                    must: [
                        {
                            bool: {
                                must: [
                                    {
                                        match: {
                                            published: true,
                                        },
                                    },
                                    {
                                        range: {
                                            [filterGroupOption.field]: {
                                                gte: filterValue[0],
                                                lte: filterValue[1],
                                                boost: 2,
                                            },
                                        },
                                    },
                                ],
                            },
                        },
                    ],
                },
            }
        };
    })();
    return {
        defaultQuery,
        customQuery,
    };
};
exports.getPropsFilterSlider = getPropsFilterSlider;
//# sourceMappingURL=props.js.map