import { getFieldName } from 'client/Containers/Calculation/Elements/tools';
import { InteractionElementsNames } from 'client/Containers/Calculation/types/elements';
import { TableNames } from 'client/Containers/Calculation/types/tables';
import { openNotification } from 'client/Elements/Notification';
import valuesConstants from 'core/constants/values';
import { pipe } from 'core/tools/func';
import { IReactionEffect } from 'core/types/Calculation/Store/effect';
import { Process } from 'core/types/Calculation/Store/process';
import { ValuesNames } from 'core/types/Calculation/Store/values';
import { ElementStatus } from 'types/elements';
import { getPrice } from './priceReactions/calculate';

const reactionEffects: IReactionEffect[] = [
  calculationStore => ({
    expression: () => {
      const {
        recalcWithRevision,
        supplierCurrency,
        supplierDiscountRub,
        supplierDiscountPerc,
        leaseObjectPrice,
        addEquipmentPrice,
      } = calculationStore.values;
      //@ts-ignore
      const importProgramSum = calculationStore.importProgramSum();
      return [
        recalcWithRevision,
        supplierCurrency,
        supplierDiscountRub,
        supplierDiscountPerc,
        leaseObjectPrice,
        importProgramSum,
        addEquipmentPrice,
      ];
    },
    effect: ([
      recalcWithRevision,
      supplierCurrencyId,
      supplierDiscountRub,
      supplierDiscountPerc,
      leaseObjectPrice,
      importProgramSum = 0,
      addEquipmentPrice = 0,
    ]) => {
      if (recalcWithRevision === true) {
        return;
      }
      const price = getPrice(
        supplierCurrencyId,
        leaseObjectPrice + addEquipmentPrice - importProgramSum,
        calculationStore,
      );

      const maxPriceChangeValue =
        price - supplierDiscountRub < 800000
          ? price - supplierDiscountRub + 50000
          : (price - supplierDiscountRub) * 1.05;
      calculationStore.setValue('maxPriceChange', maxPriceChangeValue);

      const minPriceChangeValue =
        price - supplierDiscountRub < 800000
          ? price - supplierDiscountRub - 50000
          : (price - supplierDiscountRub) * 0.95;
      calculationStore.setValue('minPriceChange', minPriceChangeValue);
    },
    options: {
      fireImmediately: true,
    },
  }),

  calculationStore => ({
    expression: () => {
      const { recalcWithRevision } = calculationStore.values;
      return recalcWithRevision;
    },
    effect: recalcWithRevision => {
      if (recalcWithRevision === true) {
        calculationStore.setFilter('selectQuote', quotes =>
          quotes.filter(
            quote =>
              quote.evo_recalc_limit &&
              quote.evo_recalc_limit > 0 &&
              quote.evo_statuscode &&
              quote.evo_statuscode.evo_id &&
              quote.evo_statuscode.evo_id === '2.3' &&
              !quote.evo_purchases_participation,
          ),
        );
        calculationStore.setValue('quote', null);
      } else {
        calculationStore.setFilter('selectQuote', undefined);
      }
    },
  }),

  calculationStore => ({
    expression: () => {
      const {
        supplierDiscountRub,
        leaseObjectPriceWthtVAT,
        recalcWithRevision,
        addEquipmentPrice,
      } = calculationStore.values;

      //@ts-ignore
      const price = calculationStore.plPriceRub();

      //@ts-ignore
      const importProgramSum = calculationStore.importProgramSum();

      const dealerPerson = calculationStore.getOption('selectDealerPerson');

      return [
        supplierDiscountRub,
        price,
        leaseObjectPriceWthtVAT,
        recalcWithRevision,
        addEquipmentPrice,
        importProgramSum,
        dealerPerson,
      ];
    },
    effect: ([
      supplierDiscountRub,
      price,
      leaseObjectPriceWthtVAT,
      recalcWithRevision,
      addEquipmentPrice,
      importProgramSum,
      dealerPerson,
    ]) => {
      if (!recalcWithRevision) {
        calculationStore.setValidation('tbxLeaseObjectPrice', undefined);
        return;
      }

      const product = calculationStore.getOption('selectProduct');

      const quote = calculationStore.getOption('selectQuote');

      const leaseObjectUsed = calculationStore.getValue('leaseObjectUsed');

      const maxCondition1 =
        leaseObjectUsed === false &&
        dealerPerson?.evo_supplier_type !== 100_000_001 &&
        quote?.evo_max_price_change &&
        !product?.evo_sale_without_nds &&
        price - supplierDiscountRub + addEquipmentPrice - importProgramSum >
          quote.evo_max_price_change;

      const maxCondition2 =
        leaseObjectUsed === false &&
        dealerPerson?.evo_supplier_type !== 100_000_001 &&
        quote?.evo_max_price_change &&
        product?.evo_sale_without_nds &&
        leaseObjectPriceWthtVAT >
          quote.evo_max_price_change -
            (quote.evo_nds_in_price_supplier_currency || 0);

      const maxCondition3 =
        (leaseObjectUsed === true ||
          dealerPerson?.evo_supplier_type === 100_000_001) &&
        quote?.evo_supplier_currency_price &&
        price - supplierDiscountRub + addEquipmentPrice - importProgramSum >
          quote.evo_supplier_currency_price -
            (quote.evo_discount_supplier_currency || 0) +
            (quote.evo_equip_price || 0) -
            (quote.evo_program_import_subsidy_sum || 0);

      const minCondition1 =
        quote?.evo_min_change_price &&
        !product?.evo_sale_without_nds &&
        price - supplierDiscountRub + addEquipmentPrice - importProgramSum <
          quote.evo_min_change_price;

      const minCondition2 =
        quote?.evo_min_change_price &&
        product?.evo_sale_without_nds &&
        leaseObjectPriceWthtVAT <
          quote.evo_min_change_price -
            (quote.evo_nds_in_price_supplier_currency || 0);

      if (maxCondition1 || maxCondition2 || maxCondition3) {
        calculationStore.setValidation('tbxLeaseObjectPrice', false);
        openNotification({
          type: 'error',
          message: 'Ошибка',
          description:
            'Указанная стоимость предмета лизинга больше возможного изменения стоимости предмета лизинга при пересчете без пересмотра. ' +
            'Уменьшите стоимость предмета лизинга',
        });
      } else if (minCondition1 || minCondition2) {
        calculationStore.setValidation('tbxLeaseObjectPrice', false);
        openNotification({
          type: 'error',
          message: 'Ошибка',
          description:
            'Указанная стоимость предмета лизинга меньше возможного изменения стоимости предмета лизинга при пересчете без пересмотра. ' +
            'Увеличьте стоимость предмета лизинга',
        });
      } else {
        calculationStore.setValidation('tbxLeaseObjectPrice', undefined);
      }
    },
  }),

  calculationStore => ({
    expression: () => {
      const { firstPaymentPerc, recalcWithRevision } = calculationStore.values;
      return { firstPaymentPerc, recalcWithRevision };
    },
    effect: ({ firstPaymentPerc, recalcWithRevision }) => {
      if (!recalcWithRevision) {
        calculationStore.setValidation('tbxFirstPaymentPerc', undefined);
        return;
      }

      const quote = calculationStore.getOption('selectQuote');
      if (quote && quote.evo_approved_first_payment) {
        if (firstPaymentPerc < quote.evo_approved_first_payment) {
          calculationStore.setValidation('tbxFirstPaymentPerc', false);
          openNotification({
            type: 'error',
            message: 'Ошибка',
            description:
              'Указанный первый платеж меньше одобренного. При пересчете без пересмотра изменение первого платежа возможно только в большую сторону от одобренного значения',
          });
        } else {
          calculationStore.setValidation('tbxFirstPaymentPerc', undefined);
        }
      }
    },
  }),

  calculationStore => ({
    expression: () => {
      const { leaseObjectCount, recalcWithRevision } = calculationStore.values;
      return { leaseObjectCount, recalcWithRevision };
    },
    effect: ({ leaseObjectCount, recalcWithRevision }) => {
      if (!recalcWithRevision) {
        calculationStore.setValidation('tbxLeaseObjectCount', undefined);
        return;
      }

      const quote = calculationStore.getOption('selectQuote');
      if (quote && quote.evo_recalc_limit) {
        if (leaseObjectCount > quote.evo_recalc_limit) {
          calculationStore.setValidation('tbxLeaseObjectCount', false);
          openNotification({
            type: 'error',
            message: 'Ошибка',
            description:
              'Количество ПЛ превышает лимит пересчета без пересмотра',
          });
        } else {
          calculationStore.setValidation('tbxLeaseObjectCount', undefined);
        }
      }
    },
  }),

  calculationStore => ({
    expression: () => {
      const { recalcWithRevision } = calculationStore.values;
      return recalcWithRevision;
    },
    effect: recalcWithRevision => {
      const quote = calculationStore.getOption('selectQuote');
      if (recalcWithRevision) {
        if (quote?.evo_recalc_limit) {
          calculationStore.setValue('leaseObjectCount', quote.evo_recalc_limit);
        }
      } else {
        if (quote?.evo_object_count) {
          calculationStore.setValue('leaseObjectCount', quote.evo_object_count);
        }
      }
    },
  }),

  calculationStore => ({
    expression: () => {
      const { maxMass, recalcWithRevision } = calculationStore.values;
      return { maxMass, recalcWithRevision };
    },
    effect: ({ maxMass, recalcWithRevision }) => {
      if (recalcWithRevision) {
        const quote = calculationStore.getOption('selectQuote');
        if (quote && quote.evo_max_mass)
          if (
            (maxMass < valuesConstants.MAX_VEHICLE_MASS &&
              quote.evo_max_mass < valuesConstants.MAX_VEHICLE_MASS) ||
            (maxMass >= valuesConstants.MAX_VEHICLE_MASS &&
              quote.evo_max_mass >= valuesConstants.MAX_VEHICLE_MASS)
          ) {
            calculationStore.setValidation('tbxMaxMass', undefined);
          } else {
            openNotification({
              type: 'error',
              message: 'Ошибка',
              description:
                'Указанная разрешенная макс. масса выходит из утвержденного диапазона. Для изменения параметра требуется пересмотр сделки',
            });
            calculationStore.setValidation('tbxMaxMass', false);
          }
      }
    },
  }),

  calculationStore => ({
    expression: () => {
      const { countSeats, leaseObjectCategory, recalcWithRevision } =
        calculationStore.values;
      return {
        countSeats,
        leaseObjectCategory,
        recalcWithRevision,
      };
    },
    effect: ({ countSeats, leaseObjectCategory, recalcWithRevision }) => {
      if (recalcWithRevision) {
        if (leaseObjectCategory === 100000003) {
          const quote = calculationStore.getOption('selectQuote');
          if (quote && quote?.evo_seats)
            if (
              (countSeats < valuesConstants.MAX_VEHICLE_SEATS &&
                quote.evo_seats < valuesConstants.MAX_VEHICLE_SEATS) ||
              (countSeats >= valuesConstants.MAX_VEHICLE_SEATS &&
                quote.evo_seats >= valuesConstants.MAX_VEHICLE_SEATS)
            ) {
              calculationStore.setValidation('tbxCountSeats', undefined);
            } else {
              openNotification({
                type: 'error',
                message: 'Ошибка',
                description:
                  'Указанное кол-во мест выходит из утвержденного диапазона. Для изменения параметра требуется пересмотр сделки',
              });
              calculationStore.setValidation('tbxCountSeats', false);
            }
        } else {
          calculationStore.setValidation('tbxCountSeats', undefined);
        }
      }
    },
  }),

  calculationStore => ({
    expression: () => {
      const { leaseObjectUsed, recalcWithRevision } = calculationStore.values;
      return { leaseObjectUsed, recalcWithRevision };
    },
    effect: ({ leaseObjectUsed, recalcWithRevision }) => {
      calculationStore.setStatus(
        'tbxLeaseObjectYear',
        recalcWithRevision && leaseObjectUsed
          ? ElementStatus.Disabled
          : ElementStatus.Default,
      );
    },
  }),

  calculationStore => ({
    expression: () => {
      const { leaseObjectYear, recalcWithRevision } = calculationStore.values;
      return { leaseObjectYear, recalcWithRevision };
    },
    effect: ({ leaseObjectYear, recalcWithRevision }) => {
      const { leaseObjectUsed } = calculationStore.values;
      if (recalcWithRevision && !leaseObjectUsed && leaseObjectYear) {
        const quote = calculationStore.getOption('selectQuote');
        if (quote && quote.evo_year)
          if (leaseObjectYear >= quote.evo_year) {
            calculationStore.setValidation('tbxLeaseObjectYear', undefined);
          } else {
            calculationStore.setValidation('tbxLeaseObjectYear', false);
          }
      }
    },
  }),

  (calculationStore, calculationProcess) => ({
    expression: () => {
      const { recalcWithRevision } = calculationStore.values;
      return recalcWithRevision;
    },
    effect: recalcWithRevision => {
      if (recalcWithRevision) {
        calculationProcess.setBypass({
          param: 'status',
          target: elementsToDisable,
          value: ElementStatus.Disabled,
        });
      } else {
        calculationProcess.clearBypass('status');
      }
    },
  }),

  (calculationStore, calculationProcess) => ({
    expression: () =>
      calculationStore.getValues(['firstPaymentPerc', 'recalcWithRevision']),
    effect: ({ firstPaymentPerc, recalcWithRevision }) => {
      if (firstPaymentPerc === 0 && recalcWithRevision === true) {
        calculationProcess.addToBypass({
          param: 'status',
          target: agentsElementsToDisable,
        });
      } else {
        calculationProcess.removeFromByPass({
          param: 'status',
          target: agentsElementsToDisable,
        });
      }
    },
  }),

  (calculationStore, calculationProcess) => ({
    expression: () => {
      return {
        recalcWithRevision: calculationStore.getValue('recalcWithRevision'),
        leaseObjectType: calculationStore.getOption('selectLeaseObjectType'),
      };
    },
    effect: ({ recalcWithRevision, leaseObjectType }) => {
      if (calculationProcess.hasProcess(Process.LoadKp)) {
        return;
      }
      if (!recalcWithRevision) {
        const allowedReqTelematicValues = [
          100000000, 100000001, 100000002, 100000003,
        ];
        calculationStore.setFilter('radioRequirementTelematic', options =>
          options.filter(
            x =>
              x.value &&
              typeof x.value === 'number' &&
              allowedReqTelematicValues.includes(x?.value),
          ),
        );
        if (leaseObjectType?.evo_id === '11') {
          calculationStore.setValue('requirementTelematic', 100000000);
          calculationStore.setStatus(
            'radioRequirementTelematic',
            ElementStatus.Disabled,
          );
        } else {
          calculationStore.setStatus(
            'radioRequirementTelematic',
            ElementStatus.Default,
          );
        }
      } else {
        calculationStore.setFilter('radioRequirementTelematic', undefined);
        calculationStore.setStatus(
          'radioRequirementTelematic',
          ElementStatus.Disabled,
        );
      }
    },
    options: {
      fireImmediately: true,
    },
  }),

  calculationStore => ({
    expression: () => {
      return calculationStore.getValue('recalcWithRevision');
    },
    effect: recalcWithRevision => {
      if (!recalcWithRevision) {
        const quote = calculationStore.getOption('selectQuote');
        if (quote) {
          calculationStore.setValue(
            'requirementTelematic',
            quote.evo_req_telematic,
          );
          let addProducts = Object.assign(
            {},
            ...Object.keys(map_add_product_types_to_values).map(valueName => {
              const target_add_product_type = quote?.evo_addproduct_types?.find(
                x =>
                  x.evo_product_type ===
                  map_add_product_types_to_values[valueName],
              );

              return {
                [valueName]: target_add_product_type?.evo_addproduct_typeid,
              };
            }),
          );
          calculationStore.setValues(addProducts);
        } else {
          calculationStore.setValue('requirementTelematic', 100000000);
          calculationStore.setValue('telematic', null);

          const addProducts = calculationStore.getStaticData(
            'evo_addproduct_type',
          );
          const tracker = addProducts.find(x =>
            x.evo_controls_program?.includes(100000000),
          );
          calculationStore.setValue('tracker', tracker?.evo_addproduct_typeid);
        }
      } else {
        calculationStore.setStatus(
          'radioRequirementTelematic',
          ElementStatus.Disabled,
        );
      }
    },
  }),

  (calculationStore, calculationProcess) => ({
    expression: () => {
      return calculationStore.getValues([
        'requirementTelematic',
        'recalcWithRevision',
      ]);
    },
    effect: ({ requirementTelematic, recalcWithRevision }) => {
      (['tracker', 'telematic'] as ValuesNames[]).forEach(valueName => {
        const elementName = getFieldName(valueName);

        calculationStore.setFilter(elementName, options =>
          options.filter(
            pipe(
              x => {
                if (x.evo_controls_program?.includes(requirementTelematic))
                  return x;
              },
              x => {
                if (recalcWithRevision) return x;
                if (x?.evo_visible_calc === true) return x;
              },
            ),
          ),
        );
      });
    },
    options: {
      fireImmediately: true,
    },
  }),

  calculationStore => ({
    expression: () => calculationStore.getValues(['lastPaymentPerc']),
    effect: ({ lastPaymentPerc }) => {
      if (!calculationStore.getValue('recalcWithRevision')) {
        calculationStore.setValidation('tbxLastPaymentPerc', undefined);
        return;
      }

      const quote = calculationStore.getOption('selectQuote');
      if (
        quote &&
        quote.evo_last_payment_perc &&
        lastPaymentPerc > 1 &&
        lastPaymentPerc > quote.evo_last_payment_perc
      ) {
        openNotification({
          type: 'error',
          message: 'Ошибка',
          description:
            'При пересчете без пересмотра последний платеж можно уменьшать или увеличивать до 1%',
        });
        calculationStore.setValidation('tbxLastPaymentPerc', false);
      } else {
        calculationStore.setValidation('tbxLastPaymentPerc', undefined);
      }
    },
  }),

  calculationStore => ({
    expression: () =>
      calculationStore.getValues([
        'lastPaymentPerc',
        'balanceHolder',
        'lastPaymentRule',
      ]),
    effect: ({ lastPaymentPerc, balanceHolder }) => {
      if (balanceHolder && balanceHolder === 100000001) {
        if (!lastPaymentPerc || parseFloat(lastPaymentPerc) < 1) {
          calculationStore.setValidation('tbxLastPaymentPerc', false);
          openNotification({
            type: 'error',
            message: 'Ошибка',
            description:
              'При балансе лизингодатель последний платеж не может быть меньше 1%! Увеличьте значение.',
          });
          return;
        }
      } else {
        if (parseFloat(lastPaymentPerc) === 0) {
          calculationStore.setValidation('tbxLastPaymentPerc', false);
          openNotification({
            type: 'error',
            message: 'Ошибка',
            description:
              'Последний платеж не может быть равен 0. Увеличьте значение',
          });
          return;
        }
      }
      if (!calculationStore.getValue('recalcWithRevision'))
        calculationStore.setValidation('tbxLastPaymentPerc', true);
    },
  }),
];

const map_add_product_types_to_values = {
  tracker: 100000003,
  telematics: 100000004,
};

const elementsToDisable: (InteractionElementsNames | TableNames)[] = [
  'tablePayments',
  'selectLead',
  'selectOpportunity',
  'selectClientRisk',
  'selectClientType',
  'tbxLeasingPeriod',
  // 'tbxLastPaymentPerc',
  // 'tbxLastPaymentRub',
  // 'radioLastPaymentRule',
  'radioGraphType',
  'tbxParmentsDecreasePercent',
  'selectSeasonType',
  'selectHighSeasonStart',
  'selectLeaseObjectType',
  'cbxLeaseObjectUsed',
  'selectBrand',
  'selectModel',
  'selectConfiguration',
  'selectLeaseObjectCategory',
  'selectDealer',
  'selectDealerPerson',
  'selectIndAgent',
  'selectCalcBroker',
  'selectCalcFinDepartment',
  'selectTarif',
  'tbxCreditRate',
  'selectRate',
  'tbxMaxPriceChange',
  'tbxImporterRewardPerc',
  'tbxImporterRewardRub',
  'radioRequirementTelematic',
  'selectTelematic',
  'selectTracker',
  'tbxMileage',
  'selectSubsidy',
  'tbxEngineHours',
  'selectImportProgram',
  'tbxAddEquipmentPrice',
  'tbxVIN',
];

// Для recalc = true и первого платежа = 0
const agentsElementsToDisable: InteractionElementsNames[] = [
  'selectDealerRewardCondition',
  'tbxDealerRewardSumm',
  'selectDealerBroker',
  'selectDealerBrokerRewardCondition',
  'tbxDealerBrokerRewardSumm',
  'selectIndAgentRewardCondition',
  'tbxIndAgentRewardSumm',
  'selectCalcDoubleAgentRewardCondition',
  'tbxCalcDoubleAgentRewardSumm',
  'selectCalcBrokerRewardCondition',
  'tbxCalcBrokerRewardSum',
  'selectFinDepartmentRewardCondtion',
  'tbxFinDepartmentRewardSumm',
];

export default reactionEffects;
