import {ComponentExporterImporter, PreloadedDynamicValues} from "../ComponentExporterImporter";
import {OfferData} from "../../store";
import {AdvancedData, BuyXGetYOptions, ProductData} from "../../cards/BuyXGetY";
import {ExportImportTarget} from "../Exporters";
import {getLazyTestables} from "../../hooks";
import {Testable} from "../../Testable";
import {TestableFormat, Testables} from "../../testables";
import {DiscountOptions} from "../../cards/Discount";
import {ProductDiscountOptions, qtyType} from "../../cards/BuyXGetX";

export class BuyXGetYExporterImporter implements ComponentExporterImporter<OfferData<BuyXGetYOptions>, OfferData<BuyXGetYOptions>> {
    type = 'BuyXGetY'
    exportData(data: OfferData<BuyXGetYOptions>, target: ExportImportTarget): OfferData<BuyXGetYOptions> {
        const {options} = data
        const testables = getLazyTestables()
        if (options.mode === 'advanced') {
            // replace the contexts with the actual testable data, call export() on each testable type
            options.data.source = (options.data as AdvancedData).source.map(id => {
                const testable = new Testable(testables, id)
                if (!testable.exists()) {
                    return undefined
                }

                return testable.export(target)
            }).filter(t => t !== undefined)
        }

        return data
    }

    importData(data: OfferData<BuyXGetYOptions>, {testables}: { testables: Testables }): OfferData<BuyXGetYOptions> {
        let {options} = data

        if (options.mode === 'advanced') {
            (options.data as AdvancedData).source = options.data.source.map((testableData) => {
                if (!testableData || !('type' in testableData)) {
                    return undefined
                }
                // we need to add this testable to the store first
                const contextId = testables.addTestables([testableData], TestableFormat.Nested, false)[0]

                return contextId
            }) //
        }

        options = {
            ...options,
            ...getLocalData(options)
        } as BuyXGetYOptions

        return {
            ...data,
            options
        }
    }

    tagDynamicValues(data: OfferData<BuyXGetYOptions>, target: ExportImportTarget): PreloadedDynamicValues | PreloadedDynamicValues[] {
        const {options: {mode, data: selectedData}} = data

        if (mode === 'products') {
            const selectedProducts = selectedData as ProductData
            return {
                category: 'products',
                values: selectedProducts.map(p => p.id)
            }
        }

        const selectedContextIDs = (selectedData as AdvancedData).source
        const selectedTestables = selectedContextIDs.map(id => new Testable(getLazyTestables(), id)).filter(t => t.exists())

        const allDynamicValues: PreloadedDynamicValues[] = []

        selectedTestables.forEach(context => {
            const dynamicValues = context.getDynamicValues()
            if (dynamicValues?.length) {
                allDynamicValues.push(...(Array.isArray(dynamicValues) ? dynamicValues : [dynamicValues]))
            }
        })

        return allDynamicValues
    }
}

export const resolveData = (mode: BuyXGetYOptions['mode'], options: BuyXGetYOptions): AdvancedData | ProductData => {
    if (mode === 'advanced') {
        if (!Array.isArray(options.data)) {
            return options.data as AdvancedData
        } else if (options.__local?.data_advanced && !Array.isArray(options.__local?.data_advanced)) {
            return options.__local.data_advanced
        } else {
            return getDefaultAdvancedData()
        }
    } else {
        // mode === 'products'
        if (Array.isArray(options.data)) {
            return options.data as ProductData
        } else if (options.__local?.data_products && Array.isArray(options.__local?.data_products)) {
            return options.__local.data_products
        } else {
            return getDefaultProductData()
        }
    }
};
export const getLocalData = (options: BuyXGetYOptions): Pick<BuyXGetYOptions, '__local'> => {
    return {
        __local: {
            data_advanced: resolveData('advanced', options) as AdvancedData,
            data_products: resolveData('products', options) as ProductData,
        }
    }
};

export const getDefaultProductData = (): ProductData => []
export const getDefaultAdvancedData = (): AdvancedData => ({
    source: [],
    // @ts-ignore
    discountOptions:  {
        qtyType: 'simple',
        qty: {
            "type": "any", // currently only 'any' is supported
            "amount": 1 // this is a placeholder for future advanced types
        },
        quantity: 1,
        discount: {
            type: 'free',
            amount: 1
        },
        missingItemsInCart: {
            mode: 'manual-add' // advanced mode only supports manual-add.
        }
    } as ProductDiscountOptions,
} as AdvancedData)
