import { openNotification } from 'client/Elements/Notification';
import valuesConstants from 'core/constants/values';
import { shiftRight } from 'core/tools/array';
import { ICalculationStore } from 'core/types/Calculation/Store';
import { isEqual, isNil } from 'lodash';
const { PERIODS_NUMBER } = valuesConstants;

function validateInsuranceTable(this: ICalculationStore) {
  const osagoRow = this.getTableRowValues(
    'tableInsurance',
    rows => rows.findIndex(x => x?.key === 'osago'),
    'value',
  );

  const kaskoRow = this.getTableRowValues(
    'tableInsurance',
    rows => rows.findIndex(x => x?.key === 'kasko'),
    'value',
  );

  /**
   * если в СК ОСАГО поле evo_osago_with_kasko=True И СК ОСАГО != СК КАСКО,
   *  то вывести и ошибку: "Невозможно страхование ОСАГО отдельно от КАСКО -
   * страховая компания должна быть одна!", иначе все ок
   */
  const osagoInsuranceCompanyOption =
    this.tables?.tableInsurance?.options?.insuranceCompany?.find(
      x => x.accountid === osagoRow.insuranceCompany,
    );

  const { insDecentral } = this.values;
  const invalid =
    !insDecentral &&
    osagoInsuranceCompanyOption?.evo_osago_with_kasko &&
    osagoRow.insuranceCompany !== kaskoRow.insuranceCompany;
  if (invalid) {
    openNotification({
      type: 'error',
      message: 'Ошибка',
      description:
        'Невозможно страхование ОСАГО отдельно от КАСКО - страховая компания должна быть одна!',
    });
    this.setTableRow('tableInsurance', rows =>
      rows.findIndex(x => x?.key === 'osago'),
    )({
      insuranceCompany: {
        validation: !invalid,
      },
    });
    this.setTableRow('tableInsurance', rows =>
      rows.findIndex(x => x?.key === 'kasko'),
    )({
      insuranceCompany: {
        validation: !invalid,
      },
    });
    return;
  }

  /**
   * Проверка на заполнение ОСАГО и КАСКО
   */
  this.setTableRow('tableInsurance', rows =>
    rows.findIndex(x => x?.key === 'osago'),
  )({
    insuranceCompany: {
      validation: !isNil(osagoRow.insuranceCompany),
    },
    insured: {
      validation: !isNil(osagoRow.insured),
    },
  });

  this.setTableRow('tableInsurance', rows =>
    rows.findIndex(x => x?.key === 'kasko'),
  )({
    insuranceCompany: {
      validation: !isNil(kaskoRow.insuranceCompany),
    },
    insured: {
      validation: !isNil(kaskoRow.insured),
    },
  });

  /**
   * Если в таблице страхования в строке КАСКО Плательщик = ЛД и в поле "Стоимость за первый период" значение меньше 1000, то выводить ошибку
   * Если в таблице страхования в строке ОСАГО Плательщик = ЛД и в поле "Стоимость за первый период" значение меньше 1000, то выводить ошибку
   */

  if (osagoRow.insured === 100_000_001 && osagoRow.insCost < 1000) {
    this.setTableRow('tableInsurance', rows =>
      rows.findIndex(x => x?.key === 'osago'),
    )({
      insCost: {
        validation: false,
      },
    });
  } else {
    this.setTableRow('tableInsurance', rows =>
      rows.findIndex(x => x?.key === 'osago'),
    )({
      insCost: {
        validation: undefined,
      },
    });
  }

  if (kaskoRow.insured === 100_000_001 && kaskoRow.insCost < 1000) {
    this.setTableRow('tableInsurance', rows =>
      rows.findIndex(x => x?.key === 'kasko'),
    )({
      insCost: {
        validation: false,
      },
    });
  } else {
    this.setTableRow('tableInsurance', rows =>
      rows.findIndex(x => x?.key === 'kasko'),
    )({
      insCost: {
        validation: undefined,
      },
    });
  }

  /**
   *  Самый откровенный костыль в истории калькулятора,
   *  потому что мне сейчас лень добавлять проверку текущего значения
   *  в отфильтрованном списке опций в таблице,
   *  да и это не имеет смысла
   * (связано с самой жуткой реакцией по страховке)
   *
   * TODO: Для нового калькулятора:
   * вместо костыля сбрасывать значение КАСКО на дефолтное, если текущего значения нет в списке опций
   *
   */
  const leasingWithoutKasko = this.getValue('leasingWithoutKasko');
  const otherInsuranceCompany =
    this.tables.tableInsurance.options?.insuranceCompany?.find(x =>
      x.name?.includes('ПРОЧИЕ'),
    );
  if (
    !leasingWithoutKasko &&
    kaskoRow.insuranceCompany === otherInsuranceCompany?.value
  ) {
    this.setTableRow('tableInsurance', rows =>
      rows.findIndex(x => x?.key === 'kasko'),
    )({
      insuranceCompany: {
        validation: false,
      },
    });

    openNotification({
      type: 'error',
      message: 'Ошибка',
      description: 'Укажите страховую компанию КАСКО из списка',
    });
  } else {
    this.setTableRow('tableInsurance', rows =>
      rows.findIndex(x => x?.key === 'kasko'),
    )({
      insuranceCompany: {
        validation: undefined,
      },
    });
  }
}

function validatePaymentsTable(this: ICalculationStore) {
  const { graphType } = this.values;
  const payments = this.tables.tablePayments.rows.map(
    x => x.paymentRelation?.value,
  );
  const rows = this.tables.tablePayments.rows;
  const isValidRows = () =>
    !rows.some(x => x.paymentRelation?.validation === false);

  switch (graphType) {
    case 100000001: {
      {
        const areMiddleRowsEqual =
          new Set(payments.slice(1, payments.length - 1)).size === 1;

        this.setTableRows(
          'tablePayments',
          1,
        )(
          Array.from({ length: payments.length - 2 }, () => ({
            paymentRelation: {
              validation: areMiddleRowsEqual ? false : true,
            },
          })),
        );
      }

      if (isValidRows()) {
        const target_payments = payments.slice(1, 4);
        const min = Math.min(...target_payments);
        const max = Math.max(...target_payments);
        const areInvalidRows = max - min > 10;

        this.setTableRows(
          'tablePayments',
          1,
        )(
          Array.from({ length: 3 }, () => ({
            paymentRelation: {
              validation: areInvalidRows ? false : true,
            },
          })),
        );
      }

      if (isValidRows()) {
        const target_payments = payments.slice(1, payments.length - 1);
        let pairs_number = 0;
        new Set(target_payments).forEach(set_v => {
          let setValueCount = 0;
          target_payments.forEach(target_v => {
            if (target_v === set_v) {
              setValueCount++;
            }
          });
          if (setValueCount > 1) {
            pairs_number++;
          }
        });

        this.setTableRows(
          'tablePayments',
          2,
        )(
          Array.from({ length: payments.length - 3 }, () => ({
            paymentRelation: {
              validation: pairs_number >= 2 ? true : false,
            },
          })),
        );
      }

      if (isValidRows()) {
        payments.forEach((x, i) => {
          if (i > 1 && i < rows.length - 1) {
            const isInvalidValue = x > payments[i - 1] || x < 3;
            this.setTableRow(
              'tablePayments',
              i,
            )({
              paymentRelation: {
                validation: !isInvalidValue,
              },
            });
          }
        });
      }

      break;
    }

    case 100000003: {
      const { highSeasonStart: highSeasonStartId } = this.values;
      if (!highSeasonStartId) {
        return;
      }
      const highSeasonStart = parseInt(
        this.getOption('selectHighSeasonStart')?.name || '2',
      );
      const shiftNumber = highSeasonStart - 2;
      const middleRows = payments.slice(1, PERIODS_NUMBER + 1);
      const unshiftedMiddleRows = shiftRight(middleRows, shiftNumber);

      const seasonTypeOptions = this.getOption('selectSeasonType');
      if (!seasonTypeOptions) {
        return;
      }
      const startPositions =
        seasonTypeOptions && seasonTypeOptions.startPositions;

      const stepsValues: any[] = [];
      for (let i = 0; i < startPositions.length; i++) {
        const targetIndex = startPositions[i];
        stepsValues.push(unshiftedMiddleRows[targetIndex]);
      }

      const areCorrectSeasonPayments = isEqual(
        stepsValues,
        [...stepsValues].sort((a, b) => b - a),
      );
      this.setTableRows(
        'tablePayments',
        1,
      )(
        Array.from({ length: PERIODS_NUMBER }, () => ({
          paymentRelation: {
            validation: areCorrectSeasonPayments,
          },
        })),
      );
      break;
    }

    case 100000004: {
      const targetRows = payments.slice(1, 4);
      const areEqual3MiddleRows = new Set(targetRows).size === 1;
      this.setTableRows(
        'tablePayments',
        1,
      )(
        Array.from({ length: 3 }, () => ({
          paymentRelation: {
            validation: !areEqual3MiddleRows,
          },
        })),
      );

      if (isValidRows()) {
        const areCorrect3MiddleRows = isEqual(
          targetRows.slice(0).sort((a, b) => a - b),
          targetRows,
        );
        this.setTableRows(
          'tablePayments',
          1,
        )(
          Array.from({ length: 3 }, () => ({
            paymentRelation: {
              validation: areCorrect3MiddleRows,
            },
          })),
        );
      }
      break;
    }
  }
}

export default function (this: ICalculationStore) {
  validateInsuranceTable.call(this);
  validatePaymentsTable.call(this);
}
