import {ExportImportTarget} from "./Exporters";
import {Testables} from "../testables";

export type PreloadedDynamicValues = { category: string; values: (string | number)[] };

export interface ComponentExporterImporter<DataIn, DataOut> {
    type: string,
    /**
     * @param data is immutable, you can mutate it if you want to, but data mutations inside this function will not change the original data object. You can return a new object or the same mutated object.
     */
    exportData?: (data: DataIn, target: ExportImportTarget) => DataOut,
    importData?: (data: DataIn, models: { testables: Testables }) => DataOut,
    /**
     * This is basically for specifying the ids that need were loaded dynamically for this component.
     * They are sent to the server so that its associated data can be preloaded on page load.
     * eg: InCategories may tag the following ids:
     * {
     *     category: 'categories',
     *     values: [10, 22] // these are the categories that are used by this component.
     * }
     */
    tagDynamicValues?: (data: DataIn, target: ExportImportTarget) => PreloadedDynamicValues | PreloadedDynamicValues[],
}


export class PreloadedDynamicData {
    constructor(public items: PreloadedDynamicValues[] = []) {}


    addPreloadedDynamicData(preloaded: PreloadedDynamicValues | PreloadedDynamicValues[]) {
        if (Array.isArray(preloaded)) {
            preloaded.forEach(item => this.addPreloadedDynamicData(item))
            return
        }

        const existingDynamicValues = this.items

        // Find existing entry with the same category
        const existingIndex = existingDynamicValues.findIndex((item: PreloadedDynamicValues) =>
            item.category === preloaded.category
        )

        if (existingIndex !== -1) {
            // Merge values with the existing entry, avoiding duplicates
            const existingItem = existingDynamicValues[existingIndex]
            // set for unique values
            const mergedValues = [...new Set([...existingItem.values, ...preloaded.values])]


            existingDynamicValues[existingIndex] = {
                ...existingItem,
                values: mergedValues
            }
        } else {
            // No existing category found, append the new item
            existingDynamicValues.push(preloaded)
        }
    }

    reset() {
        this.items = []
    }
}

/**
 * So uhm, I don't love that we are using a global here because of multiple reasons (mutability, bugs, execution limitations, etc.). One of them is that this only supports
 * exporting one at a time (synchronously).
 * ideally this would be an object passed as a dependency instead of a global object, but honestly, we don't have that use case at the moment, and we are NOT gaping to redesign the entire thing just for cleaner code. this works for our use case now, I got to be more pragmatic sometimes.
 */
export const currentPreloadedDynamicData: PreloadedDynamicData = new PreloadedDynamicData([])
