import { isNothing, isSome } from "@jet/environment";
import * as models from "../../../api/models";
import * as serverData from "../../../foundation/json-parsing/server-data";
import * as mediaAttributes from "../../../foundation/media/attributes";
import * as mediaRelationships from "../../../foundation/media/relationships";
import { pageRouter } from "../../builders/routing";
import { hrefToRoutableUrl } from "../../builders/url-mapping";
import * as content from "../../content/content";
import { addClickEventToAction, addClickEventToSeeAllAction } from "../../metrics/helpers/clicks";
import { addImpressionFields } from "../../metrics/helpers/impressions";
import * as metricsHelpersLocation from "../../metrics/helpers/location";
import { addMetricsEventsToPageWithInformation, metricsPageInformationFromMediaApiResponse, } from "../../metrics/helpers/page";
import { createClickMetricsOptionsForChartOrCategory, createMetricsOptionsForChartOrCategory, } from "../../metrics/helpers/search/search-shelves";
import { combinedRecoMetricsDataFromMetricsData } from "../../metrics/helpers/util";
import * as onDevicePersonalization from "../../personalization/on-device-personalization";
import * as searchShelves from "./search-shelves";
import * as groupingShelfControllerCommon from "../../grouping/shelf-controllers/grouping-shelf-controller-common";
/**
 * Takes the raw page data and creates a charts and categories page
 * @param objectGraph The App Store Object Graph
 * @param resultData The data representing the charts and categories page
 * @returns A charts and categories page
 */
export function searchChartsAndCategoriesPageFromData(objectGraph, resultData) {
    var _a, _b;
    /// Get the page's metadata
    const pageTitle = mediaAttributes.attributeAsString(resultData, "title");
    const selectedTabId = serverData.asString(resultData, "meta.autoSelectedTabId");
    const sourceShelfCanonicalId = serverData.asString(resultData, "meta.sourceShelfCanonicalId");
    const pageInformation = metricsPageInformationFromMediaApiResponse(objectGraph, "SearchLanding", sourceShelfCanonicalId, resultData);
    const onDevicePersonalizationMetricsData = onDevicePersonalization.metricsData(objectGraph);
    pageInformation.recoMetricsData = combinedRecoMetricsDataFromMetricsData(pageInformation.recoMetricsData, null, onDevicePersonalizationMetricsData);
    /// Generate a new SearchPageContext (mainly for making shelf contexts)
    const searchPageContext = {
        shelves: [],
        metricsLocationTracker: metricsHelpersLocation.newLocationTracker(),
        metricsPageInformation: pageInformation,
        adStitcher: null,
        adIncidentRecorder: null,
        pageType: searchShelves.SearchPageType.ChartsAndCategories,
    };
    /// Prep the shelves data, mappings, orderings, and page tabs list
    const shelvesData = serverData.asArrayOrEmpty(resultData, "data");
    const shelvesMapping = {};
    const shelfOrdering = [];
    const pageTabsCollector = [];
    const pageTabsLocationTracker = metricsHelpersLocation.newLocationTracker();
    for (const shelfData of shelvesData) {
        /// Generate the shelf attributes for the shelf
        const shelfAttributes = searchShelves.shelfAttributesFromData(objectGraph, shelfData, models.SearchLandingPageContentKind.CategoriesAndCharts, models.SearchPageKind.CategoriesAndCharts);
        /// Since the shelves act as their own page, we need to set a new location tracker for each shelf
        const shelfPageContext = {
            ...searchPageContext,
            metricsLocationTracker: metricsHelpersLocation.newLocationTracker(),
        };
        /// Generate the shelf context
        const shelfContext = searchShelves.baseShelfContext(objectGraph, shelfData, shelfAttributes, shelfPageContext);
        /// Push the shelf content location so each shelf has the correct parent and starting index
        metricsHelpersLocation.pushContentLocation(objectGraph, shelfContext.metricsOptions, shelfAttributes.title);
        /// Make the shelf
        const shelf = createChartsCategoryShelf(objectGraph, shelfData, true, shelfAttributes, shelfPageContext, shelfContext);
        metricsHelpersLocation.popLocation(shelfContext.metricsOptions.locationTracker);
        if (isNothing(shelf)) {
            continue;
        }
        /// Add the shelf to the shelves mapping for the shelf id
        shelvesMapping[shelf.id] = shelf;
        /// Add the shelf id to the shelf ordering (to maintain ordered shelves)
        shelfOrdering.push(shelf.id);
        /// Make a pageTab metadata model from the shelf and action
        const pageTab = new models.PageTab();
        const action = new models.PageTabChangeAction(shelfData.id, shelfAttributes.title);
        /// Generate the click actions
        const pageTabClickActionOptions = {
            id: shelfAttributes.title,
            canonicalId: (_a = serverData.asString(shelfData.meta, "canonicalId")) !== null && _a !== void 0 ? _a : undefined,
            actionType: "navigate",
            targetType: "button",
            pageInformation: searchPageContext.metricsPageInformation,
            locationTracker: pageTabsLocationTracker,
        };
        addClickEventToAction(objectGraph, action, pageTabClickActionOptions);
        pageTab.action = action;
        pageTab.id = shelf.id;
        pageTab.title = `${(_b = shelf.title) !== null && _b !== void 0 ? _b : ""}`; /// We need a deep copy of the string as we will remove the reference possibly later.
        pageTabsCollector.push(pageTab);
        metricsHelpersLocation.nextPosition(pageTabsLocationTracker);
    }
    /// Return an empty page if there are no real shelves to show
    if (!serverData.isDefinedNonNullNonEmpty(shelfOrdering)) {
        return new models.SearchChartsAndCategoriesPage();
    }
    /// Create the page tabs
    const pageTabs = new models.PageTabs();
    /// The id needs to be static but it isn't tied to the payload
    pageTabs.id = objectGraph.random.nextUUID();
    /// Add the pageTabs as its own shelf so it can be independent of the chart and category shelves
    /// as well as to control the segmented control for swapping between category shelf orderings (e.g. category containers)
    const pageTabsShelf = new models.Shelf("pageTabs");
    pageTabsShelf.items = [pageTabs];
    shelvesMapping[pageTabs.id] = pageTabsShelf;
    /// Make the page and add the shelf mappings (which includes our pageTabs shelf)
    const page = new models.SearchChartsAndCategoriesPage();
    page.shelfMapping = shelvesMapping;
    const shelfOrderings = {};
    /** Normally, we would have the shelf orderings be based on some identifier in the payload on a container which contains
        an array of shelves. E.g.
        {
            Container {
                containerId: string
                shelves: [
                    {
                        shelfId1: string,
                        ...
                    },
                    ...
                ]
            }
        }
        shelf orderings = { containerId: [shelfId1, ...]}

        However, the current protocol has no container, just a loose array of shelves.
        {
            shelves: [
                {
                    shelfId1: string,
                    ...
                },
                ...
            ]
        }

        Therefore, we have to fake our ordering by having the ordering be the shelves' own identifiers.

        shelf orderings = { shelfId1: [shelfId1], shelfId2: [shelfId2], ...}

        We also will append the pageTabs shelf if we have multiple shelves representing multiple tabs on the page.
    */
    for (const shelfOrderingElement of shelfOrdering) {
        if (pageTabsCollector.length > 1) {
            shelfOrderings[shelfOrderingElement] = [pageTabs.id, shelfOrderingElement];
        }
        else {
            shelfOrderings[shelfOrderingElement] = [shelfOrderingElement];
        }
    }
    for (const shelf of Object.values(shelvesMapping)) {
        shelf.title = undefined;
    }
    /// Set the data on the page
    page.title = pageTitle;
    page.pageTabs = pageTabs;
    page.columnCount = 2;
    page.shelfOrderings = shelfOrderings;
    /// If we don't have a reco selected default tab, just default to the first one
    page.defaultShelfOrdering = shelfOrdering.includes(selectedTabId) ? selectedTabId : shelfOrdering[0];
    /// Set the data on the page tabs
    pageTabs.tabs = pageTabsCollector;
    pageTabs.selectedTabId = page.defaultShelfOrdering;
    /// Add the page metrics
    addMetricsEventsToPageWithInformation(objectGraph, page, searchPageContext.metricsPageInformation);
    return page;
}
/**
 * Creates a charts and categories shelf from the shelf data
 * @param objectGraph The App Store Object Graph
 * @param data The shelf data object
 * @param isForSeeAllPage Whether or not this shelf will be displayed on the see-all page
 * @param shelfAttributes The shelf's attributes
 * @param searchPageContext The context for the page this shelf belongs to
 * @param searchShelfContext The shelf's context
 * @returns A charts and categories shelf
 */
export function createChartsCategoryShelf(objectGraph, data, isForSeeAllPage, shelfAttributes, searchPageContext, searchShelfContext) {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
    const items = [];
    const chartsAndCategoriesData = mediaRelationships.relationshipCollection(data, "contents");
    const shelf = new models.Shelf("searchChartsAndCategories");
    shelf.isHorizontal = false;
    shelf.id = data.id;
    shelf.title = shelfAttributes.title;
    shelf.presentationHints = { isWidthConstrained: true };
    if (serverData.isNumber((_a = shelfAttributes.displayStyle) === null || _a === void 0 ? void 0 : _a.layoutSize)) {
        shelf.contentsMetadata = {
            type: "searchLandingChartsAndCategoriesSection",
            numberOfColumns: shelfAttributes.displayStyle.layoutSize,
        };
    }
    if (shelfAttributes.hasSeeAll) {
        const action = new models.FlowAction("searchChartsAndCategories");
        action.pageUrl = shelfAttributes.seeAllLink;
        action.title = objectGraph.loc.string("ACTION_SEE_ALL");
        const seeAllMetricsOptions = {
            ...searchShelfContext.metricsOptions,
            targetType: "button",
        };
        addClickEventToSeeAllAction(objectGraph, action, action.pageUrl, seeAllMetricsOptions);
        shelf.seeAllAction = action;
    }
    addImpressionFields(objectGraph, shelf, searchShelfContext.metricsOptions);
    const brickUseCase = isForSeeAllPage
        ? content.SearchChartOrCategoryBrickUseCase.seeAllPage
        : content.SearchChartOrCategoryBrickUseCase.other;
    for (const chartOrCategory of chartsAndCategoriesData) {
        let name = null;
        let badge = null;
        if (chartOrCategory.type === "tags") {
            const brickName = (_b = mediaAttributes.attributeAsString(chartOrCategory, "name")) !== null && _b !== void 0 ? _b : "tagbrick";
            name = brickName;
        }
        else {
            const editorialNotes = mediaAttributes.attributeAsDictionary(chartOrCategory, "editorialNotes");
            if (serverData.isDefinedNonNullNonEmpty(editorialNotes)) {
                name = serverData.asString(editorialNotes, "name");
                badge = serverData.asString(editorialNotes, "badge");
            }
        }
        const artwork = content.searchChartOrCategoryArtworkFromData(objectGraph, chartOrCategory, brickUseCase, (_c = shelfAttributes === null || shelfAttributes === void 0 ? void 0 : shelfAttributes.displayStyle) === null || _c === void 0 ? void 0 : _c.layoutDensity);
        const kind = mediaAttributes.attributeAsString(chartOrCategory, "kind");
        const linkData = mediaAttributes.attributeAsDictionary(chartOrCategory, "link");
        const linkUrl = serverData.asString(linkData, "url");
        const dataCollection = mediaRelationships.relationshipCollection(chartOrCategory, "primary-content");
        let isTitleRequired = true;
        let action = null;
        if (chartOrCategory.type === "tags") {
            const href = serverData.asString(chartOrCategory, "href");
            const url = hrefToRoutableUrl(objectGraph, href);
            const flowPage = objectGraph.required(pageRouter).fetchFlowPage(url);
            const flowAction = new models.FlowAction(flowPage);
            flowAction.pageUrl = url;
            flowAction.title = name;
            action = flowAction;
        }
        else if (isSome(linkUrl)) {
            switch (kind) {
                case "CategoryChart":
                    const topChartAction = new models.FlowAction("topCharts");
                    topChartAction.pageUrl = linkUrl;
                    topChartAction.title = name;
                    action = topChartAction;
                    break;
                case "External":
                    // For external links, we don't require a title we can just show an image
                    isTitleRequired = false;
                    const target = serverData.asString(linkData, "target");
                    if (target === "external") {
                        action = new models.ExternalUrlAction(linkUrl);
                        action.title = name !== null && name !== void 0 ? name : "";
                    }
                    else {
                        const flowPage = objectGraph.required(pageRouter).fetchFlowPage(linkUrl);
                        const linkAction = new models.FlowAction(flowPage);
                        linkAction.pageUrl = linkUrl;
                        linkAction.title = name !== null && name !== void 0 ? name : "";
                        action = linkAction;
                    }
                    break;
                default:
                    break;
            }
        }
        else if (serverData.isDefinedNonNullNonEmpty(dataCollection)) {
            const chartMetadata = dataCollection[0];
            const chartHref = chartMetadata.href;
            const url = hrefToRoutableUrl(objectGraph, chartHref);
            if ((url === null || url === void 0 ? void 0 : url.length) > 0) {
                const flowAction = new models.FlowAction("page");
                flowAction.pageUrl = url;
                flowAction.title = name;
                action = flowAction;
            }
            else {
                continue;
            }
        }
        else {
            continue;
        }
        const chartClickOptions = createClickMetricsOptionsForChartOrCategory(objectGraph, (_d = shelfAttributes === null || shelfAttributes === void 0 ? void 0 : shelfAttributes.displayStyle) === null || _d === void 0 ? void 0 : _d.layoutDensity, chartOrCategory, searchShelfContext);
        addClickEventToAction(objectGraph, action, chartClickOptions);
        if (isTitleRequired && serverData.isNullOrEmpty(name)) {
            continue;
        }
        let chartOrCategoryModel = new models.SearchChartOrCategory(name, artwork, null, null, badge, action, (_e = shelfAttributes === null || shelfAttributes === void 0 ? void 0 : shelfAttributes.displayStyle) === null || _e === void 0 ? void 0 : _e.layoutDensity, artworkSafeArea((_f = shelfAttributes === null || shelfAttributes === void 0 ? void 0 : shelfAttributes.displayStyle) === null || _f === void 0 ? void 0 : _f.layoutDensity), textSafeArea((_g = shelfAttributes === null || shelfAttributes === void 0 ? void 0 : shelfAttributes.displayStyle) === null || _g === void 0 ? void 0 : _g.layoutDensity));
        let chartModelMetricsOptions = createMetricsOptionsForChartOrCategory(objectGraph, chartOrCategoryModel, chartOrCategory, searchShelfContext);
        const artworkOptions = {
            useCase: 18 /* content.ArtworkUseCase.GroupingBrick */,
        };
        const collectionIcons = groupingShelfControllerCommon.artworkForTags(objectGraph, chartOrCategory, 1060, 520, artworkOptions, chartModelMetricsOptions);
        if (isSome(collectionIcons) && collectionIcons.length > 0) {
            const collectionIconBackgroundColor = collectionIcons[0].backgroundColor;
            if (isSome(collectionIconBackgroundColor) && (collectionIconBackgroundColor === null || collectionIconBackgroundColor === void 0 ? void 0 : collectionIconBackgroundColor.type) === "rgb") {
                chartOrCategoryModel = new models.SearchChartOrCategory(name, null, collectionIcons, (_h = content.closestTagBackgroundColorForIcon(collectionIconBackgroundColor)) !== null && _h !== void 0 ? _h : undefined, badge, action, (_j = shelfAttributes === null || shelfAttributes === void 0 ? void 0 : shelfAttributes.displayStyle) === null || _j === void 0 ? void 0 : _j.layoutDensity, artworkSafeArea((_k = shelfAttributes === null || shelfAttributes === void 0 ? void 0 : shelfAttributes.displayStyle) === null || _k === void 0 ? void 0 : _k.layoutDensity), textSafeArea((_l = shelfAttributes === null || shelfAttributes === void 0 ? void 0 : shelfAttributes.displayStyle) === null || _l === void 0 ? void 0 : _l.layoutDensity));
                chartModelMetricsOptions = createMetricsOptionsForChartOrCategory(objectGraph, chartOrCategoryModel, chartOrCategory, searchShelfContext);
            }
        }
        addImpressionFields(objectGraph, chartOrCategoryModel, chartModelMetricsOptions);
        items.push(chartOrCategoryModel);
        metricsHelpersLocation.nextPosition(searchShelfContext.metricsOptions.locationTracker);
    }
    if (serverData.isNullOrEmpty(items)) {
        return null;
    }
    shelf.items = items;
    return shelf;
}
function artworkSafeArea(density) {
    switch (density) {
        // Tile
        case models.GenericSearchPageShelfDisplayStyleDensity.Density1:
            return models.ChartOrCategorySafeArea.defaultTileArtworkSafeArea;
        // Pill
        case models.GenericSearchPageShelfDisplayStyleDensity.Density2:
            return models.ChartOrCategorySafeArea.defaultPillArtworkSafeArea;
        // Round
        case models.GenericSearchPageShelfDisplayStyleDensity.Density3:
            return undefined;
        default:
            return undefined;
    }
}
function textSafeArea(density) {
    switch (density) {
        // Tile
        case models.GenericSearchPageShelfDisplayStyleDensity.Density1:
            return models.ChartOrCategorySafeArea.defaultTileTextSafeArea;
        // Pill
        case models.GenericSearchPageShelfDisplayStyleDensity.Density2:
            return models.ChartOrCategorySafeArea.defaultPillTextSafeArea;
        default:
            return undefined;
    }
}
//# sourceMappingURL=search-categories.js.map