export type AdjustmentSourceType =
    | 'voucher'
    | 'promotion'
    | 'custom_meta'
    | 'system_meta'
    | 'point'
    | 'extra_discount'
    | 'fee'
    | 'tax'
    | 'unique_code'
    | 'meta';

export const SYSTEM_META_KEYS = ['campaign_v_id', 'voucher_usage_applied'] as const;

export const SYSTEM_META_LABELS: Record<string, string> = {
    campaign_v_id: 'Campaign Visitor ID',
    voucher_usage_applied: 'Voucher Usage Applied',
};

export const isSystemMetaKey = (key: string) => (SYSTEM_META_KEYS as readonly string[]).includes(key);

export const formatSystemMetaDisplayValue = (key: string, rawValue: unknown): string => {
    if (key === 'voucher_usage_applied') {
        return rawValue === true || rawValue === 'true' ? 'Ya' : 'Tidak';
    }
    if (rawValue === null || rawValue === undefined || rawValue === '') {
        return '-';
    }
    return String(rawValue);
};

export interface UnifiedAdjustment {
    id: number;
    source_type: AdjustmentSourceType;
    coupon_name: string;
    amount: number;
    free_item: string;
    meta_key: string;
    custom_key: string;
    custom_value: string;
    promotion_name: string;
    promotion_case_type: string;
    promotion_id: string;
    promotion_case_id: number;
    promotion_case_value: number;
}

const emptyPromotionFields = {
    promotion_name: '',
    promotion_case_type: '',
    promotion_id: '',
    promotion_case_id: 0,
    promotion_case_value: 0,
};

const manualMetaSourceTypes: AdjustmentSourceType[] = ['point', 'extra_discount', 'fee', 'tax', 'unique_code'];

const isManualMetaSource = (sourceType: AdjustmentSourceType) => {
    return manualMetaSourceTypes.includes(sourceType);
};

const serializeSystemMetaValue = (rawValue: string): string | boolean => {
    if (rawValue === 'true') return true;
    if (rawValue === 'false') return false;
    return rawValue;
};

interface DiscountLike {
    id: number;
    coupon_name: string;
    amount: number;
    free_item?: string;
}

interface MetaLike {
    id: number;
    key: string;
    amount: number;
    value?: unknown;
    name?: string;
    type?: string;
}

const resolveMetaRawValue = (item: MetaLike) => {
    if (item.value !== undefined && item.value !== null && item.value !== '') {
        return item.value;
    }
    if (item.amount !== undefined && item.amount !== null && item.amount !== 0) {
        return item.amount;
    }
    return '';
};

const mapMetaItemToAdjustment = (item: MetaLike, id: number): UnifiedAdjustment => {
    const key = item.key || '';
    const amount = Number(item.amount) || 0;
    const promotionName = item.name || '';
    const itemType = (item.type || '').toLowerCase();

    if (isSystemMetaKey(key)) {
        const rawValue = resolveMetaRawValue(item);
        return {
            id,
            source_type: 'system_meta',
            coupon_name: '',
            amount: 0,
            free_item: '',
            meta_key: key,
            custom_key: key,
            custom_value: rawValue === true ? 'true' : rawValue === false ? 'false' : String(rawValue ?? ''),
            ...emptyPromotionFields,
        };
    }

    if (key === 'birthday_extra') {
        return {
            id,
            source_type: 'promotion',
            coupon_name: '',
            amount,
            free_item: '',
            meta_key: key,
            custom_key: '',
            custom_value: '',
            ...emptyPromotionFields,
            promotion_name: promotionName,
            promotion_case_type: key,
        };
    }

    if (key === 'extra_discount') {
        const isPromotionExtraDiscount = itemType === 'promotion' || promotionName !== '';

        if (isPromotionExtraDiscount) {
            return {
                id,
                source_type: 'promotion',
                coupon_name: '',
                amount,
                free_item: '',
                meta_key: key,
                custom_key: '',
                custom_value: '',
                ...emptyPromotionFields,
                promotion_name: promotionName,
                promotion_case_type: key,
            };
        }
    }

    if (manualMetaSourceTypes.includes(key as AdjustmentSourceType)) {
        return {
            id,
            source_type: key as AdjustmentSourceType,
            coupon_name: '',
            amount,
            free_item: '',
            meta_key: key,
            custom_key: '',
            custom_value: '',
            ...emptyPromotionFields,
        };
    }

    return {
        id,
        source_type: 'custom_meta',
        coupon_name: '',
        amount: 0,
        free_item: '',
        meta_key: '',
        custom_key: key,
        custom_value: String(amount),
        ...emptyPromotionFields,
    };
};

const normalizeAdjustment = (row: UnifiedAdjustment): UnifiedAdjustment => {
    if (row.source_type === 'system_meta') {
        return row;
    }

    if (row.source_type !== 'meta') return row;

    const key = row.meta_key || '';
    const amount = Number(row.amount) || 0;
    const promotionType = (row.promotion_case_type || '').toLowerCase();
    const hasPromotionIdentity = row.promotion_name !== '' || promotionType === 'promotion';

    if (isSystemMetaKey(key)) {
        return {
            ...row,
            source_type: 'system_meta',
            meta_key: key,
            custom_key: key,
            custom_value: row.custom_value || String(amount),
        };
    }

    if (key === 'birthday_extra') {
        return {
            ...row,
            source_type: 'promotion',
            promotion_case_type: key,
            meta_key: key,
        };
    }

    if (key === 'extra_discount' && hasPromotionIdentity) {
        return {
            ...row,
            source_type: 'promotion',
            promotion_case_type: key,
            meta_key: key,
        };
    }

    if (manualMetaSourceTypes.includes(key as AdjustmentSourceType)) {
        return {
            ...row,
            source_type: key as AdjustmentSourceType,
            meta_key: key,
        };
    }

    return {
        ...row,
        source_type: 'custom_meta',
        amount: 0,
        meta_key: '',
        custom_key: key,
        custom_value: String(amount),
    };
};

interface CustomMetaLike {
    id: number;
    key: string;
    value: string;
}

export const emptyAdjustment = (id: number): UnifiedAdjustment => ({
    id,
    source_type: 'voucher',
    coupon_name: '',
    amount: 0,
    free_item: '',
    meta_key: '',
    custom_key: '',
    custom_value: '',
    ...emptyPromotionFields,
});

export const mapAdjustmentsToLegacy = (adjustments: UnifiedAdjustment[]) => {
    const discounts = adjustments
        .filter((row) => row.source_type === 'voucher')
        .map((row) => ({
            id: row.id,
            coupon_name: row.coupon_name,
            amount: Number(row.amount) || 0,
            free_item: row.free_item || '',
        }));

    const normalizedMetaMap = adjustments
        .filter((row) => row.source_type === 'meta' || row.source_type === 'promotion' || isManualMetaSource(row.source_type))
        .reduce((acc: Record<string, { id: number; key: string; amount: number; name?: string; type?: string }>, row) => {
            const key = row.source_type === 'promotion' ? row.meta_key || row.promotion_case_type : row.source_type === 'meta' ? row.meta_key : row.source_type;

            if (!key) return acc;

            const rowAmount = Number(row.amount) || 0;
            const rowName = row.source_type === 'promotion' ? row.promotion_name : row.promotion_name || '';
            const rowType = row.source_type === 'promotion' ? 'promotion' : '';
            const mapKey =
                row.source_type === 'promotion'
                    ? `promotion:${key}:${row.promotion_name || ''}:${row.promotion_case_type || key}`
                    : row.source_type === 'meta'
                      ? `legacy:${key}`
                      : `manual:${row.source_type}`;

            if (!acc[mapKey]) {
                acc[mapKey] = {
                    id: row.id,
                    key,
                    amount: rowAmount,
                    ...(rowName ? { name: rowName } : {}),
                    ...(rowType ? { type: rowType } : {}),
                };
            } else {
                acc[mapKey].amount += rowAmount;
                if (!acc[mapKey].name && rowName) acc[mapKey].name = rowName;
                if (!acc[mapKey].type && rowType) acc[mapKey].type = rowType;
            }

            return acc;
        }, {});

    const systemMetaRows = adjustments
        .filter((row) => row.source_type === 'system_meta')
        .map((row) => ({
            id: row.id,
            key: row.meta_key || row.custom_key,
            value: serializeSystemMetaValue(row.custom_value),
        }));

    const meta = [...Object.values(normalizedMetaMap), ...systemMetaRows];

    const customMeta = adjustments
        .filter((row) => row.source_type === 'custom_meta')
        .map((row) => ({
            id: row.id,
            key: row.custom_key,
            value: row.custom_value,
        }));

    return { discounts, meta, customMeta };
};

export const mapLegacyToAdjustments = (discounts: DiscountLike[] = [], meta: MetaLike[] = [], customMeta: CustomMetaLike[] = []) => {
    const voucherRows: UnifiedAdjustment[] = discounts.map((item, index) => ({
        id: index + 1,
        source_type: 'voucher',
        coupon_name: item.coupon_name || '',
        amount: Number(item.amount) || 0,
        free_item: item.free_item || '',
        meta_key: '',
        custom_key: '',
        custom_value: '',
        ...emptyPromotionFields,
    }));

    const metaRows: UnifiedAdjustment[] = meta.map((item, index) => mapMetaItemToAdjustment(item, voucherRows.length + index + 1));

    const customRows: UnifiedAdjustment[] = customMeta.map((item, index) => ({
        id: voucherRows.length + metaRows.length + index + 1,
        source_type: 'custom_meta',
        coupon_name: '',
        amount: 0,
        free_item: '',
        meta_key: '',
        custom_key: item.key || '',
        custom_value: item.value || '',
        ...emptyPromotionFields,
    }));

    return [...voucherRows, ...metaRows, ...customRows].map(normalizeAdjustment);
};
