const lowerCaseString = (str: string) => String(str || '').toLowerCase();

const normalizeArray = (arr: string[] | undefined) => (arr || []).map((item) => lowerCaseString(item));

export interface PromotionRules {
    promotion_type?: string;
    promotion_included_products?: string[];
    promotion_excluded_products?: string[];
    promotion_include_categories?: string[];
    promotion_exclude_categories?: string[];
}

export interface PromoCartLine {
    product: string;
    id?: string;
    product_categories: string[];
    qty: number;
    price: number;
    product_title?: string;
    is_free_item?: boolean;
    is_gift_card?: boolean;
}

export interface CaseEligibility {
    caseId: number;
    eligible: boolean;
    metric: number;
    required: number;
    metricLabel: string;
}

export interface OrderItemForPromo {
    id?: number;
    item_id?: string;
    product?: string;
    product_categories?: string[];
    quantity?: number;
    amount?: number;
    price?: number;
    product_title?: string;
    is_free_item?: boolean;
    is_gift_card?: boolean;
}

function isGiftCardItem(item: OrderItemForPromo): boolean {
    if (item.is_gift_card) return true;
    const title = (item.product_title || '').toLowerCase();
    return title.includes('gift card') || title.includes('greeting card');
}

export function parseProductIdFromItemId(itemId: string | undefined): string {
    if (!itemId) return '';
    const part = String(itemId).split(' | ')[0]?.trim();
    return part || '';
}

export function mapOrderItemsToPromoLines(items: OrderItemForPromo[]): PromoCartLine[] {
    if (!Array.isArray(items)) return [];

    return items
        .filter((item) => {
            if (!item.item_id && !item.product) return false;
            if (item.is_free_item) return false;
            if (isGiftCardItem(item)) return false;
            return true;
        })
        .map((item) => {
            const productId = item.product || parseProductIdFromItemId(item.item_id);
            const qty = Number(item.quantity) || 0;
            const price = Number(item.amount ?? item.price ?? 0);

            return {
                product: productId,
                id: productId,
                product_categories: Array.isArray(item.product_categories) ? item.product_categories : [],
                qty,
                price,
                product_title: item.product_title,
                is_free_item: item.is_free_item,
                is_gift_card: item.is_gift_card,
            };
        })
        .filter((line) => line.product && line.qty > 0);
}

export function isProductAccepted(product: PromoCartLine, rules: PromotionRules): boolean {
    const productId = lowerCaseString(product.product || product.id || '');
    const productCategories = normalizeArray(product.product_categories);

    const excludeProducts = normalizeArray(rules.promotion_excluded_products);
    const includeProducts = normalizeArray(rules.promotion_included_products);
    const excludeCategories = normalizeArray(rules.promotion_exclude_categories);
    const includeCategories = normalizeArray(rules.promotion_include_categories);

    const hasIncludeRules = includeProducts.length > 0 || includeCategories.length > 0;

    if (excludeProducts.includes(productId)) return false;

    if (excludeCategories.length > 0) {
        const hasExcludedCategory = productCategories.some((cat) => excludeCategories.includes(cat));
        if (hasExcludedCategory) {
            return includeProducts.includes(productId);
        }
    }

    if (includeProducts.includes(productId)) return true;

    if (includeCategories.length > 0) {
        return productCategories.some((cat) => includeCategories.includes(cat));
    }

    return !hasIncludeRules;
}

export function filterAcceptedProd(products: PromoCartLine[], rules: PromotionRules): PromoCartLine[] {
    return products.filter((product) => isProductAccepted(product, rules));
}

export function getAcceptedProdQty(products: PromoCartLine[], rules: PromotionRules): number {
    return filterAcceptedProd(products, rules).reduce((total, product) => total + (product.qty || 0), 0);
}

export function getAcceptedProdSubtotal(products: PromoCartLine[], rules: PromotionRules): number {
    return filterAcceptedProd(products, rules).reduce((total, product) => {
        const price = product.price || 0;
        const qty = product.qty || 0;
        return total + price * qty;
    }, 0);
}

function resolveBirthdayMinValue(value: number | string | null | undefined): number {
    const n = Number(value);
    return n > 0 ? n : 1;
}

function formatMetricLabel(promotionType: string, metric: number): string {
    if (promotionType === 'subtotal_of_cart' || promotionType === 'birthday') {
        return `Rp ${metric.toLocaleString('id-ID')}`;
    }
    return `${metric} qty`;
}

/** Highlight tier yang memenuhi minimum requirement cart (>=). */
function isTierEligible(promotionType: string, metric: number, required: number): boolean {
    if (required <= 0) return false;
    if (promotionType === 'qty_of_cart') {
        return metric >= required;
    }
    if (promotionType === 'subtotal_of_cart' || promotionType === 'birthday') {
        return metric >= required;
    }
    return false;
}

export function evaluatePromotionCases(
    promotion: PromotionRules & {
        promotion_case?: Array<{ id: number; value: number; case_type: string }>;
        promotion_merge_free_items?: boolean;
    },
    items: OrderItemForPromo[]
): CaseEligibility[] {
    const promotionType = promotion.promotion_type || '';
    const cases = promotion.promotion_case || [];

    const lines = mapOrderItemsToPromoLines(items);
    if (!lines.length) {
        return cases.map((c) => ({
            caseId: c.id,
            eligible: false,
            metric: 0,
            required:
                promotionType === 'birthday' ? resolveBirthdayMinValue(c.value) : Number(c.value) || 0,
            metricLabel: formatMetricLabel(promotionType, 0),
        }));
    }

    let metric = 0;
    if (promotionType === 'qty_of_cart') {
        metric = getAcceptedProdQty(lines, promotion);
    } else if (promotionType === 'subtotal_of_cart' || promotionType === 'birthday') {
        metric = getAcceptedProdSubtotal(lines, promotion);
    } else {
        return [];
    }

    const metricLabel = formatMetricLabel(promotionType, metric);

    if (promotionType === 'birthday') {
        const mergeFreeItems = promotion.promotion_merge_free_items ?? true;
        let maxEligibleRequired = -1;
        cases.forEach((c) => {
            const required = resolveBirthdayMinValue(c.value);
            if (metric >= required && required > maxEligibleRequired) {
                maxEligibleRequired = required;
            }
        });

        return cases.map((c) => {
            const required = resolveBirthdayMinValue(c.value);
            const meetsMin = metric >= required;
            const eligible =
                c.case_type === 'free_item' && mergeFreeItems
                    ? meetsMin
                    : meetsMin && required === maxEligibleRequired;

            return {
                caseId: c.id,
                eligible,
                metric,
                required,
                metricLabel,
            };
        });
    }

    // Temukan nilai minimum requirement terbesar yang memenuhi metric saat ini
    let maxEligibleRequired = -1;
    cases.forEach((c) => {
        const required = Number(c.value) || 0;
        if (isTierEligible(promotionType, metric, required)) {
            if (required > maxEligibleRequired) {
                maxEligibleRequired = required;
            }
        }
    });

    return cases.map((c) => {
        const required = Number(c.value) || 0;
        const eligible = required === maxEligibleRequired;

        return {
            caseId: c.id,
            eligible,
            metric,
            required,
            metricLabel,
        };
    });
}

export function promotionHasEligibleCase(eligibility: CaseEligibility[]): boolean {
    return eligibility.some((e) => e.eligible);
}
