import { CartData, Discount, PrivilegeCartData, Tariff, TariffCartData, findPrivilegeDiscount, findDiscountFactor, applyLoyaltyDiscount} from "@frontend/kitui";

function applyPrivilegeDiscounts(
    cartData: CartData,
    discounts: Discount[],
) {
          const privMap = new Map()
          
          cartData.services.forEach(service => service.tariffs.forEach(tariff => tariff.privileges.forEach(p => {
            privMap.set(p.privilegeId, p.amount + (privMap.get(p.privilegeId)||0))
          })))
    cartData.services.forEach(service => {
          
        service.tariffs.forEach(tariff => {

            tariff.privileges.forEach(privilege => {
                const privilegeDiscount = findPrivilegeDiscount(privilege.privilegeId, privMap.get(privilege.privilegeId)||0, discounts);
                if (!privilegeDiscount) return;

                const discountAmount = privilege.price * (1 - findDiscountFactor(privilegeDiscount));
                privilege.price -= discountAmount;
                cartData.allAppliedDiscounts.push(privilegeDiscount);
                privilege.appliedPrivilegeDiscount = privilegeDiscount;

                tariff.price -= discountAmount;
                service.price -= discountAmount;
                cartData.priceAfterDiscounts -= discountAmount;
            });
        });
    });
}
function findServiceDiscount(
    serviceKey: string,
    currentPrice: number,
    discounts: Discount[],
): Discount | null {
    const applicableDiscounts = discounts.filter(discount => {
        return (
            discount.Layer === 2 &&
            discount.Condition.Group === serviceKey &&
            currentPrice >= Number(discount.Condition.PriceFrom)
        );
    });

    if (!applicableDiscounts.length) return null;

    const maxValueDiscount = applicableDiscounts.reduce((prev, current) => {
        return Number(current.Condition.PriceFrom) > Number(prev.Condition.PriceFrom) ? current : prev;
    });

    return maxValueDiscount;
}

function findCartDiscount(
    cartPurchasesAmount: number,
    discounts: Discount[],
): Discount | null {
    const applicableDiscounts = discounts.filter(discount => {
        return (
            discount.Layer === 3 &&
            cartPurchasesAmount >= Number(discount.Condition.CartPurchasesAmount)
        );
    });

    if (!applicableDiscounts.length) return null;

    const maxValueDiscount = applicableDiscounts.reduce((prev, current) => {
        return Number(current.Condition.CartPurchasesAmount) > Number(prev.Condition.CartPurchasesAmount) ? current : prev;
    });

    return maxValueDiscount;
}

function applyCartDiscount(
    cartData: CartData,
    discounts: Discount[],
) {
    const cartDiscount = findCartDiscount(cartData.priceAfterDiscounts, discounts);
    if (!cartDiscount) return;

    cartData.priceAfterDiscounts *= findDiscountFactor(cartDiscount);
    cartData.allAppliedDiscounts.push(cartDiscount);
    cartData.appliedCartPurchasesDiscount = cartDiscount;
}


function applyServiceDiscounts(
    cartData: CartData,
    discounts: Discount[],
) {
          const privMap = new Map()
          cartData.services.forEach(service => {

          service.tariffs.forEach(tariff => tariff.privileges.forEach(p => {
            privMap.set(p.serviceKey, p.price + (privMap.get(p.serviceKey)||0))
          }))
          })

    cartData.services.forEach(service => {
        service.tariffs.map(tariff => {
            tariff.privileges.forEach(privilege => {
                const privilegeDiscount = findServiceDiscount(privilege.serviceKey, privMap.get(privilege.serviceKey), discounts);
                if (!privilegeDiscount) return;

                const discountAmount = privilege.price * (1 - findDiscountFactor(privilegeDiscount));
                privilege.price -= discountAmount;
                cartData.allAppliedDiscounts.push(privilegeDiscount);
                service.appliedServiceDiscount = privilegeDiscount;

                tariff.price -= discountAmount;
                service.price -= discountAmount;
                cartData.priceAfterDiscounts -= discountAmount;
            });
        });
    });
}

export function calcCart(tariffs: Tariff[], discounts: Discount[], purchasesAmount: number, isUserNko?: boolean): CartData {
    const cartData: CartData = {
        services: [],
        priceBeforeDiscounts: 0,
        priceAfterDiscounts: 0,
        itemCount: 0,
        appliedCartPurchasesDiscount: null,
        appliedLoyaltyDiscount: null,
        allAppliedDiscounts: [],
    }

    tariffs.forEach(tariff => {
      if (tariff.privileges === undefined) return
        if (
            (tariff.price || 0) > 0
            && tariff.privileges.length !== 1
        ) throw new Error("Price is defined for tariff with several")

        let serviceData =cartData.services.find(service => (service.serviceKey === "custom" && tariff.isCustom))         
        if (!serviceData && !tariff.isCustom) serviceData =  cartData.services.find(service => service.serviceKey === tariff.privileges[0]?.serviceKey)

        if (!serviceData) {
            serviceData = {
                serviceKey: tariff.isCustom ?"custom" :tariff.privileges[0]?.serviceKey,
                tariffs: [],
                price: 0,
                appliedServiceDiscount: null,
            }
            cartData.services.push(serviceData)
        }

        const tariffCartData: TariffCartData = {
            price: tariff.price ?? 0,
            isCustom: tariff.isCustom,
            privileges: [],
            id: tariff._id,
            name: tariff.name,
        }
        serviceData.tariffs.push(tariffCartData)

        tariff.privileges.forEach(privilege => {
            let privilegePrice = privilege.amount * privilege.price
            if (!tariff.price) tariffCartData.price += privilegePrice
            else privilegePrice = tariff.price

            const privilegeCartData: PrivilegeCartData = {
                serviceKey: privilege.serviceKey,
                privilegeId: privilege.privilegeId,
                description: privilege.description,
                price: privilegePrice,
                amount: privilege.amount,
                appliedPrivilegeDiscount: null,
            }

            tariffCartData.privileges.push(privilegeCartData)
            cartData.priceAfterDiscounts += privilegePrice
            cartData.itemCount++
        })

        cartData.priceBeforeDiscounts += tariffCartData.price
        serviceData.price += tariffCartData.price
    })

    const nkoDiscount = findNkoDiscount(discounts)
    if (isUserNko && nkoDiscount) {
        applyNkoDiscount(cartData, nkoDiscount)
    } else {
        applyPrivilegeDiscounts(cartData, discounts)
        applyServiceDiscounts(cartData, discounts)
        applyCartDiscount(cartData, discounts)
        applyLoyaltyDiscount(cartData, discounts, purchasesAmount)
    }

    cartData.allAppliedDiscounts = Array.from(new Set(cartData.allAppliedDiscounts))

    console.log('CD', cartData)
    return cartData
}

function applyNkoDiscount(cartData: CartData, discount: Discount) {
    cartData.priceAfterDiscounts *= discount.Target.Factor
    cartData.allAppliedDiscounts.push(discount)
}

export function findNkoDiscount(discounts: Discount[]): Discount | null {
    const applicableDiscounts = discounts.filter(discount => discount.Condition.UserType === "nko")

    if (!applicableDiscounts.length) return null

    const maxValueDiscount = applicableDiscounts.reduce((prev, current) => {
        return current.Condition.CartPurchasesAmount > prev.Condition.CartPurchasesAmount ? current : prev
    })

    return maxValueDiscount
}
