import { getValueName } from 'client/Containers/Calculation/Elements/tools';
import { ElementsNames } from 'client/Containers/Calculation/types/elements';
import { pipe } from 'core/tools/func';
import { ICalculationStore } from 'core/types/Calculation/Store';
import CONDITIONS from 'core/validation/conditions';
import {
  convertToValidationResult,
  getValue,
  showValidationMessages,
  validate,
  ValidationCondition,
} from 'core/validation/validate';
import { isNil } from 'lodash';

const customConditions: Partial<Record<ElementsNames, ValidationCondition>> = {
  selectLeaseObjectCategory: calculationStore => {
    const leaseObjectType = calculationStore.getOption('selectLeaseObjectType');
    const leaseObjectCategory = calculationStore.getValue(
      'leaseObjectCategory',
    );
    if (
      CONDITIONS.IS_NULL(leaseObjectCategory) &&
      !['6', '9', '10'].includes(leaseObjectType?.evo_id || '')
    ) {
      return {
        isValid: false,
      };
    }
    return { isValid: true };
  },
  selectQuote: calculationStore => {
    const quote = calculationStore.getValue('quote');
    if (
      calculationStore.getValue('recalcWithRevision') === true &&
      CONDITIONS.IS_NULL(quote)
    ) {
      return {
        isValid: false,
      };
    }
    return { isValid: true };
  },
  tbxVehicleTaxInYear: calculationStore => {
    const objectRegistration = calculationStore.getValue('objectRegistration');
    const vehicleTaxInYear = calculationStore.getValue('vehicleTaxInYear');
    if (
      objectRegistration === 100000001 &&
      CONDITIONS.LESS_OR_EQUALS_ZERO(vehicleTaxInYear)
    ) {
      return {
        isValid: false,
      };
    }
    return { isValid: true };
  },
  radioTypePTS: calculationStore => {
    const objectRegistration = calculationStore.getValue('objectRegistration');
    const typePTS = calculationStore.getValue('typePTS');
    if (objectRegistration === 100000001 && CONDITIONS.IS_NULL(typePTS)) {
      return {
        isValid: false,
      };
    }
    return { isValid: true };
  },
  selectObjectRegionRegistration: calculationStore => {
    const objectRegistration = calculationStore.getValue('objectRegistration');
    const objectRegionRegistration = calculationStore.getValue(
      'objectRegionRegistration',
    );
    if (
      objectRegistration === 100000001 &&
      CONDITIONS.IS_NULL(objectRegionRegistration)
    ) {
      return {
        isValid: false,
      };
    }
    return { isValid: true };
  },
  radioRequirementTelematic: calculationStore => {
    const { telematic, tracker, requirementTelematic } =
      calculationStore.getValues([
        'telematic',
        'tracker',
        'requirementTelematic',
      ]);

    if (requirementTelematic !== 100000004 && !telematic && !tracker) {
      return {
        isValid: false,
        message: 'Не указан Тип средства контроля: (Маяк или Телематика)',
      };
    }
    if (requirementTelematic === 100000004 && (telematic || tracker)) {
      return {
        isValid: false,
        message: 'Маяк и телематика не должны быть указаны',
      };
    }
    return { isValid: true };
  },
  selectTownRegistration: calculationStore => {
    const { townRegistration, objectRegistration } = calculationStore.getValues(
      ['townRegistration', 'objectRegistration'],
    );
    if (objectRegistration === 100000000 && !townRegistration) {
      return {
        isValid: false,
      };
    }
    return {
      isValid: true,
    };
  },
  tbxFirstPaymentRub: calculationStore => {
    const { firstPaymentRub, subsidySum } = calculationStore.values;
    return {
      isValid: firstPaymentRub - subsidySum >= 0,
      message:
        'Первый платеж с учетом субсидии получается отрицательный, увеличьте первый платеж',
    };
  },

  tbxLeasingPeriod: calculationStore => {
    const leasingPeriod = calculationStore.getValue('leasingPeriod');
    const tablePaymentsLength =
      calculationStore.tables.tablePayments.rows.length;
    return {
      isValid: leasingPeriod === tablePaymentsLength,
      message:
        'Срок лизинга не соответствует таблице платежей. Необходимо изменить срок лизинга',
    };
  },

  //TODO: перенести в process/agents/validation

  /**
   * @description
   * Валидация:
   * Если tbxDealerRewardSumm= 0 И в списке selectDealerRewardCondition есть запись,
   *  у которой evo_reward_condition.evo_agency_agreementid. Обязательная выплата АВ (evo_required_reward) = True,
   *  то поле tbxDealerRewardSumm обводить красной рамкой
   * и выводить ошибку "Согласно Агентскому договору с данным ЮЛ поставщика обязательна выплата АВ. Заложите АВ в расчет"
   */
  tbxDealerRewardSumm: calculationStore => {
    const dealerRewardConditionOptions = calculationStore.getOptions(
      'selectDealerRewardCondition',
    );
    const dealerRewardSumm = calculationStore.getValue('dealerRewardSumm');

    const isValid = !(
      dealerRewardSumm === 0 &&
      dealerRewardConditionOptions?.some(
        x => x.evo_agency_agreementidData?.evo_required_reward,
      )
    );

    return {
      isValid,
      message:
        'Согласно Агентскому договору с данным ЮЛ поставщика обязательна выплата АВ. Заложите АВ в расчет',
    };
  },
  /**
   * @description
   * Валидация
   * Если tbxDealerBrokerRewardSumm= 0 И в списке selectDealerBrokerRewardCondition есть запись,
   * у которой evo_reward_condition.evo_agency_agreementid. Обязательная выплата АВ (evo_required_reward) = True,
   * то поле tbxDealerBrokerRewardSumm обводить красной рамкой
   * и выводить ошибку "Согласно Агентскому договору с данным Брокером поставщика обязательна выплата АВ. Заложите АВ в расчет"
   */
  tbxDealerBrokerRewardSumm: calculationStore => {
    const dealerBrokerRewardConditionOptions = calculationStore.getOptions(
      'selectDealerBrokerRewardCondition',
    );
    const dealerBrokerRewardSumm = calculationStore.getValue(
      'dealerBrokerRewardSumm',
    );

    const isValid = !(
      dealerBrokerRewardSumm === 0 &&
      dealerBrokerRewardConditionOptions?.some(
        x => x.evo_agency_agreementidData?.evo_required_reward,
      )
    );

    return {
      isValid,
      message:
        'Согласно Агентскому договору с данным Брокером поставщика обязательна выплата АВ. Заложите АВ в расчет',
    };
  },

  /**
   * @description
   * Если tbxIndAgentRewardSumm= 0 И в списке selectIndAgentRewardCondition есть запись,
   * у которой evo_reward_condition.evo_agency_agreementid. Обязательная выплата АВ (evo_required_reward) = True,
   * то поле tbxIndAgentRewardSumm обводить красной рамкой
   * и выводить ошибку "Согласно Агентскому договору с данным Агентом ФЛ обязательна выплата АВ. Заложите АВ в расчет"
   */
  tbxIndAgentRewardSumm: calculationStore => {
    const indAgentRewardConditionOptions = calculationStore.getOptions(
      'selectIndAgentRewardCondition',
    );
    const indAgentRewardSumm = calculationStore.getValue('indAgentRewardSumm');

    const isValid = !(
      indAgentRewardSumm === 0 &&
      indAgentRewardConditionOptions?.some(
        x => x.evo_agency_agreementidData?.evo_required_reward,
      )
    );

    return {
      isValid,
      message:
        'Согласно Агентскому договору с данным Агентом ФЛ обязательна выплата АВ. Заложите АВ в расчет',
    };
  },

  /**
   * @description
   * Если tbxCalcDoubleAgentRewardSumm = 0 И в списке selectCalcDoubleAgentRewardCondition есть запись,
   * у которой evo_reward_condition.evo_agency_agreementid. Обязательная выплата АВ (evo_required_reward) = True,
   * то поле tbxCalcDoubleAgentRewardSumm обводить красной рамкой
   * и выводить ошибку "Согласно Агентскому договору с данным Двойным агентом обязательна выплата АВ. Заложите АВ в расчет"
   */
  tbxCalcDoubleAgentRewardSumm: calculationStore => {
    const calcDoubleAgentRewardConditionOptions = calculationStore.getOptions(
      'selectCalcDoubleAgentRewardCondition',
    );
    const calcDoubleAgentRewardSumm = calculationStore.getValue(
      'calcDoubleAgentRewardSumm',
    );

    const isValid = !(
      calcDoubleAgentRewardSumm === 0 &&
      calcDoubleAgentRewardConditionOptions?.some(
        x => x.evo_agency_agreementidData?.evo_required_reward,
      )
    );

    return {
      isValid,
      message:
        'Согласно Агентскому договору с данным Двойным агентом обязательна выплата АВ. Заложите АВ в расчет',
    };
  },

  /**
   * @description
   * Если tbxCalcBrokerRewardSum = 0 И в списке selectCalcBrokerRewardCondition есть запись,
   * у которой evo_reward_condition.evo_agency_agreementid. Обязательная выплата АВ (evo_required_reward) = True,
   * то поле tbxCalcBrokerRewardSum обводить красной рамкой
   * и выводить ошибку "Согласно Агентскому договору с данным Брокером обязательна выплата АВ. Заложите АВ в расчет"
   */
  tbxCalcBrokerRewardSum: calculationStore => {
    const calcBrokerRewardConditionOptions = calculationStore.getOptions(
      'selectCalcBrokerRewardCondition',
    );
    const calcBrokerRewardSum = calculationStore.getValue(
      'calcBrokerRewardSum',
    );

    const isValid = !(
      calcBrokerRewardSum === 0 &&
      calcBrokerRewardConditionOptions?.some(
        x => x.evo_agency_agreementidData?.evo_required_reward,
      )
    );

    return {
      isValid,
      message:
        'Согласно Агентскому договору с данным Брокером обязательна выплата АВ. Заложите АВ в расчет',
    };
  },

  /**
   * @description
   * Если tbxFinDepartmentRewardSumm = 0 И в списке selectFinDepartmentRewardCondtion есть запись,
   * у которой evo_reward_condition.evo_agency_agreementid. Обязательная выплата АВ (evo_required_reward) = True,
   * то поле tbxFinDepartmentRewardSumm обводить красной рамкой
   * и выводить ошибку "Согласно Агентскому договору с данным Финотделом обязательна выплата АВ. Заложите АВ в расчет"
   */
  tbxFinDepartmentRewardSumm: calculationStore => {
    const finDepartmentRewardCondtionOptions = calculationStore.getOptions(
      'selectFinDepartmentRewardCondtion',
    );
    const finDepartmentRewardSumm = calculationStore.getValue(
      'finDepartmentRewardSumm',
    );

    const isValid = !(
      finDepartmentRewardSumm === 0 &&
      finDepartmentRewardCondtionOptions?.some(
        x => x.evo_agency_agreementidData?.evo_required_reward,
      )
    );

    return {
      isValid,
      message:
        'Согласно Агентскому договору с данным Финотделом обязательна выплата АВ. Заложите АВ в расчет',
    };
  },
};

const elementsValidations: Partial<
  Record<ElementsNames, (value?: any) => boolean>
> = {
  selectLead: CONDITIONS.IS_NULL,
  selectProduct: CONDITIONS.IS_NULL,
  selectSupplierCurrency: CONDITIONS.IS_NULL,
  selectLeaseObjectType: CONDITIONS.IS_NULL,
  selectBrand: CONDITIONS.IS_NULL,
  selectModel: CONDITIONS.IS_NULL,
  selectLeaseObjectUseFor: CONDITIONS.IS_NULL,
  selectDealer: CONDITIONS.IS_NULL,
  // selectDealerPerson: CONDITIONS.IS_NULL,
  selectRegionRegistration: CONDITIONS.IS_NULL,
  selectTarif: CONDITIONS.IS_NULL,
  // selectRate: VALIDATIONS.IS_NULL,
  selectRegistration: CONDITIONS.IS_NULL,
  // tbxLeaseObjectPrice: CONDITIONS.LESS_OR_EQUALS_ZERO,
  tbxLeaseObjectPriceWthtVAT: CONDITIONS.LESS_OR_EQUALS_ZERO,
  // tbxVATInLeaseObjectPrice: CONDITIONS.LESS_OR_EQUALS_ZERO,
  // tbxLastPaymentPerc: VALIDATIONS.IS_NULL,
  // tbxLastPaymentRub: VALIDATIONS.IS_NULL,
  // tbxFirstPaymentPerc: VALIDATIONS.IS_NULL,
  // tbxFirstPaymentRub: VALIDATIONS.IS_NULL,
  tbxLeaseObjectCount: CONDITIONS.LESS_OR_EQUALS_ZERO,
};

const elementsConditions = (
  Object.keys(elementsValidations) as ElementsNames[]
).reduce(
  (ac: Partial<Record<ElementsNames, ValidationCondition>>, elementName) => {
    const validator = elementsValidations[elementName];
    if (validator)
      ac[elementName] = pipe(getValue, validator, convertToValidationResult);
    return ac;
  },
  {},
);

const entityElementsConditions = (
  [
    'selectIndAgentRewardCondition',
    'selectCalcBrokerRewardCondition',
    'selectFinDepartmentRewardCondtion',
  ] as ElementsNames[]
).reduce(
  (ac: Partial<Record<ElementsNames, ValidationCondition>>, elementName) => {
    const valueName = getValueName(elementName);
    ac[elementName] = (calculationStore, elementName) => {
      if (isNil(calculationStore.getValue(valueName))) {
        return { isValid: true };
      }
      return {
        isValid: calculationStore.getOption(elementName) !== undefined,
      };
    };
    return ac;
  },
  {},
);

const conditions = Object.assign(
  {},
  customConditions,
  elementsConditions,
  entityElementsConditions,
);

export default function (this: ICalculationStore) {
  const validationResult = validate(this, conditions);
  (Object.keys(validationResult) as ElementsNames[]).forEach(elementName => {
    const isValid = validationResult[elementName]?.isValid;
    if (isValid !== undefined) this.setValidation(elementName, isValid);
  });
  showValidationMessages(validationResult, 'Ошибка во время расчета графика');
}
