import {
  DiscountsStore,
  IDiscount,
  IDiscountCondition,
} from "@/widget/shared/types/discounts";
import { computed } from "vue";
import { IFormulaField, IRepeaterField } from "@/widget/shared/types/fields";
import { useCurrency } from "@/widget/actions/fields/composable/useCurrency.ts";
import { useConditions } from "@/widget/actions/conditions/composable/useConditions.ts";
import { ComputedRef } from "vue-demi";
import { useFieldsStore } from "@/widget/app/providers/stores/fieldsStore.ts";
import { useTranslationsStore } from "@/widget/app/providers/stores/translationsStore.ts";
import { useDiscountsStore } from "@/widget/app/providers/stores/discountsStore.ts";

interface DiscountsResult {
  addDiscounts: (rawDiscounts: IDiscount[]) => void;
  applyDiscounts: (
    field: IFormulaField | IRepeaterField,
  ) => IFormulaField | IRepeaterField;
  promocodes: ComputedRef<string[]>;
  originalPromocodes: ComputedRef<string[]>;
  applyPromocode: (promocode: string) => void;
  removePromocode: (idx: number) => void;
  hasPromocodes: () => boolean;
}

function addDiscounts(rawDiscounts: IDiscount[]): void {
  const discountsStore = useDiscountsStore();
  const structuredDiscounts: DiscountsStore = {};

  rawDiscounts.forEach((discount) => {
    if (
      discount.isPromo &&
      discount.promocode &&
      !discountsStore.getOriginalPromocodes.includes(discount.promocode)
    ) {
      discountsStore.setOriginalPromocodes([
        ...discountsStore.getOriginalPromocodes,
        discount.promocode,
      ]);
    }

    discount.conditions.forEach((condition: IDiscountCondition) => {
      const fieldAliases = condition.fieldAlias.split(",");

      fieldAliases.forEach((fieldAlias: string): void => {
        if (!structuredDiscounts[fieldAlias]) {
          structuredDiscounts[fieldAlias] = [];
        }

        structuredDiscounts[fieldAlias].push({
          ...condition,
          isPromo: discount.isPromo,
          promocode: discount.promocode,
          discountId: +discount.discountId,
          discountConditionId: +condition.discountConditionId,
        });
      });
    });

    const originalDiscounts = discountsStore.getOriginalDiscounts;
    originalDiscounts[+discount.discountId] = discount;
    discountsStore.setOriginalDiscounts(originalDiscounts);
  });

  discountsStore.setDiscounts(structuredDiscounts);
}

function applyDiscounts(
  field: IFormulaField | IRepeaterField,
): IFormulaField | IRepeaterField {
  const discountsStore = useDiscountsStore();
  if (!discountsStore.getDiscounts[field?.alias]) return field;
  const conditions = JSON.parse(
    JSON.stringify(discountsStore.getDiscounts[field.alias]),
  )?.reverse();

  const withPromocodes = conditions.filter(
    (c: IDiscountCondition) => c.isPromo,
  );

  const notPromocodes = conditions.filter(
    (c: IDiscountCondition) => !c.isPromo,
  );

  const result = [...withPromocodes, ...notPromocodes];

  let applied = false;
  for (const condition of result) {
    const discount: IDiscount =
      discountsStore.getOriginalDiscounts[condition.discountId];
    if (
      discount &&
      isDiscountValid(discount) &&
      evaluateDiscountCondition(field, condition) &&
      checkPromocodeConditions(discount) &&
      !applied
    ) {
      const totalDiscount = calculateDiscount(field.value || 0, condition);
      field.value = (field.originalValue || 0) - totalDiscount;
      field.hasDiscount = true;

      field.discount = {
        discountType: condition.discountType,
        isPromo: condition.isPromo,
        promocode: condition.promocode,
        viewType: discount.viewType,
        discountName: discount.title,
        extraView: parseAppliedDiscount(
          totalDiscount,
          discount,
          condition,
          field,
        ),
      };

      applied = true;
    }
  }

  if (!applied) {
    field.discount = undefined;
    field.hasDiscount = false;
  }

  return field;
}

function isDiscountValid(discount: IDiscount): boolean {
  const today = new Date().toISOString().split("T")[0];

  if (discount.period === "single_day" && discount.singleDate !== today) {
    return false;
  }

  if (
    discount.period === "period" &&
    (today < discount.periodStartDate! || today > discount.periodEndDate!)
  ) {
    return false;
  }

  return discount.discountStatus === "active";
}

function checkPromocodeConditions(discount: IDiscount) {
  const discountsStore = useDiscountsStore();
  return discount.isPromo
    ? discountsStore.getPromocodes.length &&
        discount.isPromo &&
        !!discountsStore.getPromocodes.includes(discount?.promocode || "")
    : true;
}

function toFixedTruncate(num: number, decimals: number): number {
  const factor = Math.pow(10, decimals);
  return Math.floor(num * factor) / factor;
}

function evaluateDiscountCondition(
  field: IFormulaField | IRepeaterField,
  condition: IDiscountCondition,
): boolean {
  let value = field.value || 0;

  const decimals =
    field.fieldCurrency && field.fieldCurrencySettings
      ? field.fieldCurrencySettings.numAfterInteger
      : 0;

  value = toFixedTruncate(Number(value), decimals);

  switch (condition.conditionSymbol) {
    case "<":
      return value !== 0 && value < +condition.overPrice;
    case ">":
      return value !== 0 && value > +condition.overPrice;
    case "=":
      return value === +condition.overPrice;
    default:
      return false;
  }
}

function calculateDiscount(
  value: number,
  condition: IDiscountCondition,
): number {
  if (condition.discountType === "percent_of_amount") {
    return (value * +condition.discountAmount) / 100;
  }
  return +condition.discountAmount;
}

function parseAppliedDiscount(
  discountValue: number,
  discount: IDiscount,
  condition: IDiscountCondition,
  field: IFormulaField,
): string {
  const currencyFormatter = useCurrency();
  const value = currencyFormatter.formatCurrency(
    discountValue,
    currencyFormatter.getCurrencyOptions(field),
  );

  if (discount.viewType === "show_with_title") {
    return `-${value}`;
  }

  const translations = useTranslationsStore();

  if (condition.discountType === "percent_of_amount") {
    return `${Number(condition.discountAmount)}% ${translations.getTranslations.off}`;
  }

  return `-${value} ${translations.getTranslations.off}`;
}

function applyPromocode(promocode: string): void {
  const discountsStore = useDiscountsStore();
  const fieldStore = useFieldsStore();
  const { triggerCondition } = useConditions();

  if (!discountsStore.getPromocodes.includes(promocode)) {
    discountsStore.setPromocodes([...discountsStore.getPromocodes, promocode]);
    fieldStore.recalculateTotals();
    triggerCondition();
    fieldStore.recalculateTotals();
  }
}

function removePromocode(idx: number): void {
  const discountsStore = useDiscountsStore();
  const fieldStore = useFieldsStore();
  const { triggerCondition } = useConditions();
  discountsStore.setPromocodes(
    discountsStore.getPromocodes.filter((_, i: number) => i !== idx),
  );

  fieldStore.recalculateTotals();
  triggerCondition();
  fieldStore.recalculateTotals();
}

function hasPromocodes(): boolean {
  const discountsStore = useDiscountsStore();
  return discountsStore.getOriginalPromocodes.length > 0;
}

export function useDiscounts(): DiscountsResult {
  const discountsStore = useDiscountsStore();
  return {
    addDiscounts,
    applyDiscounts,
    applyPromocode,
    removePromocode,
    hasPromocodes,
    promocodes: computed(() => discountsStore.getPromocodes),
    originalPromocodes: computed(() => discountsStore.getOriginalPromocodes),
  };
}
