# Source: CmsDataFetching.js

    // NOTE This entire functionality seems non-crutial and maintainanece burden for no benefit

    /** @typedef {import("./CmsMakeupEngine").ProductUsagePattern} ProductUsagePattern */

    /**
     * @typedef {Object} CmsApiConfiguration
     *
     * @property {string} url - base url of api
     * @property {string} accessToken
     * @property {string} languageCode
     */

    export class FetchError extends Error {
        /**
         * @param {unknown} cause
         * @param {string} message
         */
        constructor(cause, message = "Fetch failed") {
            super(message);
            this.name = "FetchError";
            this.cause = cause;
        }
    }

    export class NotFoundError extends Error {
        /**
         * @param {string} entity
         * @param {string | number} id
         */
        constructor(entity, id) {
            super(`${entity} with id ${id} was not found.`);
            this.name = "NotFoundError";
            this.entity = entity;
            this.id = id;
        }
    }

    /**
     *
     * @param {string} url
     * @returns {Promise<unknown>}
     */
    async function fetch_wrap(url) {
        const json = await fetch(url, {
            method: "GET",
            headers: {
                Accept: "application/json",
            },
        });

        return (await json.json()).data;
    }

    /**
     * @param {CmsApiConfiguration} conf
     * @returns {Promise<unknown>}
     */
    async function finishesMany(conf) {
        return fetch_wrap(
            `${conf.url}/finishes?access_token=${conf.accessToken}&language_code=${conf.languageCode}`,
        );
    }
    /**
     * @param {CmsApiConfiguration} conf
     * @param {number} pup_id
     * @returns {Promise<unknown>}
     */
    async function productUsagePatternsSingle(conf, pup_id) {
        return fetch_wrap(
            `${conf.url}/product_usage_patterns/${pup_id}?access_token=${conf.accessToken}&language_code=${conf.languageCode}`,
        );
    }
    /**
     * @param {CmsApiConfiguration} conf
     * @param {number} product_id
     * @returns {Promise<unknown>}
     */
    async function shadeColorsMany(conf, product_id) {
        return fetch_wrap(
            `${conf.url}/products/${product_id}/shade_colors?access_token=${conf.accessToken}&language_code=${conf.languageCode}`,
        );
    }
    /**
     * @param {CmsApiConfiguration} conf
     * @param {number} pup_id
     * @returns {Promise<unknown>}
     */
    async function usagePatternAreasMany(conf, pup_id) {
        return fetch_wrap(
            `${conf.url}/product_usage_patterns/${pup_id}/usage_pattern_areas?access_token=${conf.accessToken}&language_code=${conf.languageCode}`,
        );
    }

    /**
     * @async
     * @param {Omit<CmsApiConfiguration, "languageCode">} conf
     * @param {number} shade_color_id
     * @returns {Promise<number | undefined>}
     */
    export async function tryToFetchshadeColorProductId(conf, shade_color_id) {
        const shadeColors = await fetch_wrap(
            `${conf.url}/shade_colors/${shade_color_id}?access_token=${conf.accessToken}`,
        );

        if (shadeColors instanceof Error) throw shadeColors;

        const shadeColor = /** @type {Array<{product: number | undefined}>} */(shadeColors).at(0);
        if (!shadeColor) throw new NotFoundError("ShadeColors", shade_color_id);

        return shadeColor.product;
    }

    /**
     * @async
     * @param {CmsApiConfiguration} conf
     * @param {number} pupId
     * @returns {Promise<ProductUsagePattern>}
     */
    export async function expandProductUsagePatternFetch(conf, pupId) {
        // prettier-ignore
        const finishProm = finishesMany(conf)
            .catch((reason) => new FetchError(reason, "Couldn't fetch finishes."));
        // prettier-ignore
        const pupProm = productUsagePatternsSingle(conf, pupId)
            .catch((reason) => new FetchError(reason, `Couldn't fetch product usage pattern ${pupId}.`));
        // prettier-ignore
        const upasProm = usagePatternAreasMany(conf, pupId)
            .catch((reason) => new FetchError(reason, `Couldn't fetch usage pattern arreas for product usage pattern ${pupId}.`));

        const [finishes, pups, upas] = await Promise.all([
            finishProm,
            pupProm,
            upasProm,
        ]);
        if (finishes instanceof Error) throw finishes; //TODO Appropriate error message and documented
        if (pups instanceof Error) throw pups; //TODO Appropriate error message and documented
        if (upas instanceof Error) throw upas; //TODO Appropriate error message and documented

        const pup = pups.at(0);
        if (!pup) throw new NotFoundError("ProductUsagePattern", pupId);

        // prettier-ignore
        const shadeProm = shadeColorsMany(conf, pup.product)
            .catch(
                (reason) => new FetchError(reason, `Couldn't fetch shadecolors for product ${pup.product}.`)
            );

        const [shades] = await Promise.all([shadeProm]);
        if (shades instanceof Error) throw shades; //TODO Appropriate error message and documented

        return {
            id: pup.id,
            product: pup.product,
            usagePatternAreas: upas.map((upa) => {
                const shadeColor = shades.find((s) => s.id === upa.shadeColor);
                if (!shadeColor)
                    throw new NotFoundError("ShadeColor", upa.shadeColor);

                const finish = finishes.find((f) => f.id === shadeColor.finish);
                if (!finish) throw new NotFoundError("Finish", shadeColor.finish);

                return {
                    applicationArea: upa.applicationArea,
                    shadeColor: {
                        id: shadeColor.id,
                        colorOpacity: shadeColor.colorOpacity,
                        finishOpacity: shadeColor.finishOpacity,
                        rendering: shadeColor.rendering,
                        finish: {
                            name: finish.name,
                        },
                    },
                };
            }),
        };
    }