import { Table } from 'client/Containers/Calculation/types/tables';
import { openNotification } from 'client/Elements/Notification';
import {
  insuranceKaskoDefaultFilter,
  insuranceOsagoDefaultFilter,
  singleValueFilter,
} from 'core/constants/stores/Calculation/filters';
import valuesConstants from 'core/constants/values';
import { shift, shiftRight } from 'core/tools/array';
import { IReactionEffect } from 'core/types/Calculation/Store/effect';
import { Process } from 'core/types/Calculation/Store/process';
import { toJS } from 'mobx';
import { ElementStatus } from 'types/elements';

const { PERIODS_NUMBER } = valuesConstants;

export default [
  (calculationStore, calculationProcess) => ({
    expression: () => {
      const kaskoValues = calculationStore.getTableRowValues(
        'tableInsurance',
        rows => rows.findIndex(x => x?.key === 'kasko'),
        'value',
      );

      return {
        ...kaskoValues,
      };
    },
    effect: ({ insuranceCompany, insTerm, insured }) => {
      if (calculationProcess.hasProcess(Process.LoadKp)) {
        return;
      }
      if (insTerm) {
        const { rows: tableRows } = calculationStore.tables.tableInsurance;
        const dgoRowIndex = tableRows.findIndex(x => x?.key === 'dgo');
        if (dgoRowIndex && dgoRowIndex >= 0)
          calculationStore.setTableRows(
            'tableInsurance',
            dgoRowIndex,
          )([
            {
              insuranceCompany: {
                value: insuranceCompany,
              },
              insTerm: {
                value: insTerm,
              },
              insured: {
                value: insured,
              },
            },
            {
              insuranceCompany: {
                value: insuranceCompany,
              },
              insTerm: {
                value: insTerm,
              },
              insured: {
                value: insured,
              },
            },
          ]);
      }
    },
  }),

  // (calculationStore, calculationProcess) => ({
  //   expression: () => {
  //     const { leasingPeriod } = calculationStore.values;

  //     const insTermValue = calculationStore.getTableRowValue(
  //       'tableInsurance',
  //       rows => rows.findIndex(x => x?.key === 'kasko'),
  //       'insTerm',
  //       'value',
  //     );

  //     return {
  //       insTerm: insTermValue,
  //       leasingPeriod,
  //     };
  //   },
  //   effect: ({ insTerm, leasingPeriod }) => {
  //     if (calculationProcess.hasProcess(Process.LoadKp)) {
  //       return;
  //     }
  //     if (insTerm === 100000001 && leasingPeriod > 15) {
  //       calculationStore.setTableRow('tableInsurance', rows =>
  //         rows.findIndex(x => x?.key === 'kasko'),
  //       )({
  //         insured: { value: 100000001, status: ElementStatus.Disabled },
  //       });
  //     } else {
  //       calculationStore.setTableRow('tableInsurance', rows =>
  //         rows.findIndex(x => x?.key === 'kasko'),
  //       )({
  //         insured: { status: ElementStatus.Default },
  //       });
  //     }
  //   },
  // }),

  calculationStore => ({
    expression: () => {
      const { leasingPeriod } = calculationStore.values;

      const insTermValue = calculationStore.getTableRowValue(
        'tableInsurance',
        rows => rows.findIndex(x => x?.key === 'kasko'),
        'insTerm',
        'value',
      );

      return {
        insTerm: insTermValue,
        leasingPeriod,
      };
    },
    effect: ({ insTerm, leasingPeriod }) => {
      const quote = calculationStore.getOption('selectQuote');
      const recalcWithRevision =
        calculationStore.getValue('recalcWithRevision');
      if (
        recalcWithRevision &&
        quote?.evo_one_year_insurance &&
        leasingPeriod > 15 &&
        insTerm === 100000001
      ) {
        setTimeout(() => {
          calculationStore.setTableRow(
            'tableInsurance',
            rows => rows.findIndex(x => x?.key === 'kasko'),
            false,
          )({
            insTerm: { value: 100000000, status: ElementStatus.Disabled },
          });
        });
        openNotification({
          type: 'info',
          message: 'Внимание!',
          description:
            'Срок страхования КАСКО изменен на 12 месяцев, т.к. оформляется Однолетний полис',
        });
      }
    },
  }),

  // самая жуткая реакция по страховке
  (calculationStore, calculationProcess) => ({
    expression: () => {
      const { leasingPeriod, leasingWithoutKasko } = calculationStore.values;
      return { leasingPeriod, leasingWithoutKasko };
    },
    effect: ({ leasingPeriod, leasingWithoutKasko }) => {
      if (leasingWithoutKasko) {
        const otherInsuranceCompany =
          calculationStore.tables.tableInsurance.options?.insuranceCompany?.find(
            x => x.name?.includes('ПРОЧИЕ'),
          );
        const insuranceOtherFilter = singleValueFilter(
          otherInsuranceCompany?.value,
        );
        calculationStore.setTableRow('tableInsurance', rows =>
          rows.findIndex(x => x?.key === 'kasko'),
        )({
          insuranceCompany: {
            value: otherInsuranceCompany?.value,
            status: ElementStatus.Disabled,
            filter: insuranceOtherFilter,
          },
          insCost: {
            value: 0,
            status: ElementStatus.Disabled,
          },
          insTerm: {
            value: 100_000_000,
            status: ElementStatus.Disabled,
          },
          insured: {
            value: 100_000_000,
            status: ElementStatus.Disabled,
          },
        });

        calculationStore.setTableRow('tableInsurance', rows =>
          rows.findIndex(x => x?.key === 'dgo'),
        )({
          insuranceCompany: {
            value: otherInsuranceCompany?.value,
            status: ElementStatus.Disabled,
            filter: insuranceOtherFilter,
          },
          insCost: {
            value: 0,
            status: ElementStatus.Disabled,
          },
          insTerm: {
            value: 100_000_000,
            status: ElementStatus.Disabled,
          },
          insured: {
            value: 100_000_000,
            status: ElementStatus.Disabled,
          },
        });

        calculationStore.setTableRow('tableInsurance', rows =>
          rows.findIndex(x => x?.key === 'ns'),
        )({
          insuranceCompany: {
            value: otherInsuranceCompany?.value,
            status: ElementStatus.Disabled,
            filter: insuranceOtherFilter,
          },
          insCost: {
            value: 0,
            status: ElementStatus.Disabled,
          },
          insTerm: {
            value: 100_000_000,
            status: ElementStatus.Disabled,
          },
          insured: {
            value: 100_000_000,
            status: ElementStatus.Disabled,
          },
        });
      } else if (leasingPeriod) {
        calculationStore.setTableRow('tableInsurance', rows =>
          rows.findIndex(x => x?.key === 'kasko'),
        )({
          insuranceCompany: {
            filter: insuranceKaskoDefaultFilter,
            status: ElementStatus.Default,
          },
          insCost: { status: ElementStatus.Default },
        });

        calculationStore.setTableRow('tableInsurance', rows =>
          rows.findIndex(x => x?.key === 'dgo'),
        )({
          insuranceCompany: { filter: insuranceKaskoDefaultFilter },
        });

        calculationStore.setTableRow('tableInsurance', rows =>
          rows.findIndex(x => x?.key === 'ns'),
        )({
          insuranceCompany: { filter: insuranceKaskoDefaultFilter },
        });

        if (leasingPeriod < 12) {
          calculationStore.setTableRow('tableInsurance', rows =>
            rows.findIndex(x => x?.key === 'osago'),
          )({
            insured: { value: 100000000, status: ElementStatus.Disabled },
          });
          calculationStore.setTableRow('tableInsurance', rows =>
            rows.findIndex(x => x?.key === 'kasko'),
          )({
            insured: { value: 100000000, status: ElementStatus.Disabled },
            insTerm: { value: 100000000, status: ElementStatus.Disabled },
          });
        } else if (leasingPeriod === 12) {
          calculationStore.setTableRow('tableInsurance', rows =>
            rows.findIndex(x => x?.key === 'osago'),
          )({
            insured: { status: ElementStatus.Default },
          });
          calculationStore.setTableRow('tableInsurance', rows =>
            rows.findIndex(x => x?.key === 'kasko'),
          )({
            insured: { status: ElementStatus.Default },
            insTerm: { value: 100000000, status: ElementStatus.Disabled },
          });
        } else if (leasingPeriod > 12 && leasingPeriod < 16) {
          calculationStore.setTableRow('tableInsurance', rows =>
            rows.findIndex(x => x?.key === 'osago'),
          )({
            insured: { status: ElementStatus.Default },
          });
          calculationStore.setTableRow('tableInsurance', rows =>
            rows.findIndex(x => x?.key === 'kasko'),
          )({
            insured: { status: ElementStatus.Default },
            insTerm: { value: 100000001, status: ElementStatus.Disabled },
          });
        } else if (
          leasingPeriod > 16
          //  &&
          // calculationStore.getTableRowValue(
          //   'tableInsurance',
          //   rows => rows.findIndex(x => x?.key === 'kasko'),
          //   'insTerm',
          //   'value',
          // ) === 100000001
        ) {
          calculationStore.setTableRow('tableInsurance', rows =>
            rows.findIndex(x => x?.key === 'osago'),
          )({
            insured: { status: ElementStatus.Default },
          });
          calculationStore.setTableRow('tableInsurance', rows =>
            rows.findIndex(x => x?.key === 'kasko'),
          )({
            insured: { status: ElementStatus.Default },
            insTerm: { value: 100000000, status: ElementStatus.Disabled },
          });
        } else {
          calculationStore.setTableRow('tableInsurance', rows =>
            rows.findIndex(x => x?.key === 'osago'),
          )({
            insured: { status: ElementStatus.Default },
          });
          calculationStore.setTableRow('tableInsurance', rows =>
            rows.findIndex(x => x?.key === 'kasko'),
          )({
            insured: { status: ElementStatus.Default },
            insTerm: { status: ElementStatus.Disabled },
          });
        }
      }
    },
    options: {
      fireImmediately: true,
    },
  }),

  (calculationStore, calculationProcess) => ({
    expression: () => {
      const kaskoValues = calculationStore.getTableRowValues(
        'tableInsurance',
        rows => rows.findIndex(x => x?.key === 'kasko'),
        'value',
      );
      const dgoValues = calculationStore.getTableRowValues(
        'tableInsurance',
        rows => rows.findIndex(x => x?.key === 'dgo'),
        'value',
      );
      const nsValues = calculationStore.getTableRowValues(
        'tableInsurance',
        rows => rows.findIndex(x => x?.key === 'ns'),
        'value',
      );

      return {
        kaskoRow: kaskoValues,
        dgoRow: dgoValues,
        nsRow: nsValues,
      };
    },
    effect: ({ kaskoRow, dgoRow, nsRow }) => {
      if (calculationProcess.hasProcess(Process.LoadKp)) {
        return;
      }

      if (
        kaskoRow &&
        kaskoRow.insCost === 0 &&
        ((dgoRow && dgoRow.insCost > 0) || (nsRow && nsRow.insCost > 0))
      ) {
        calculationStore.setTableRow('tableInsurance', rows =>
          rows.findIndex(x => x?.key === 'kasko'),
        )({
          insCost: {
            validation: false,
          },
        });

        openNotification({
          type: 'error',
          message: 'Ошибка во время расчета графика',
          description: 'Укажите стоимость КАСКО',
        });
      } else {
        calculationStore.setTableRow('tableInsurance', rows =>
          rows.findIndex(x => x?.key === 'kasko'),
        )({
          insCost: {
            validation: true,
          },
        });
      }
    },
  }),

  (calculationStore, calculationProcess) => ({
    expression: () => {
      const kaskoValues = calculationStore.getTableRowValues(
        'tableInsurance',
        rows => rows.findIndex(x => x?.key === 'kasko'),
        'value',
      );
      return {
        kaskoRow: kaskoValues,
      };
    },
    effect: ({ kaskoRow }) => {
      if (calculationProcess.hasProcess(Process.LoadKp)) {
        return;
      }

      if (
        kaskoRow &&
        kaskoRow.insured === 100000001 &&
        kaskoRow.insCost === 0
      ) {
        calculationStore.setTableRow('tableInsurance', rows =>
          rows.findIndex(x => x?.key === 'kasko'),
        )({
          insCost: {
            validation: false,
          },
        });
        openNotification({
          type: 'error',
          message: 'Ошибка во время расчета графика',
          description: 'Укажите стоимость КАСКО, включаемую в график',
        });
      } else {
        calculationStore.setTableRow('tableInsurance', rows =>
          rows.findIndex(x => x?.key === 'kasko'),
        )({
          insCost: {
            validation: true,
          },
        });
      }
    },
  }),

  (calculationStore, calculationProcess) => ({
    expression: () => {
      const { rows: tableRows } = calculationStore.tables.tableInsurance;
      const osagoRowIndex = tableRows.findIndex(x => x?.key === 'osago');
      const osagoValues = calculationStore.getTableRowValues(
        'tableInsurance',
        osagoRowIndex,
        'value',
      );
      return {
        osagoRow: osagoValues,
      };
    },
    effect: ({ osagoRow }) => {
      if (calculationProcess.hasProcess(Process.LoadKp)) {
        return;
      }

      if (
        osagoRow &&
        osagoRow.insured === 100000001 &&
        osagoRow.insCost === 0
      ) {
        calculationStore.setTableRow('tableInsurance', rows =>
          rows.findIndex(x => x?.key === 'osago'),
        )({
          insCost: {
            validation: false,
          },
        });
        openNotification({
          type: 'error',
          message: 'Ошибка во время расчета графика',
          description: 'Укажите стоимость ОСАГО, включаемую в график',
        });
      } else {
        calculationStore.setTableRow('tableInsurance', rows =>
          rows.findIndex(x => x?.key === 'osago'),
        )({
          insCost: {
            validation: true,
          },
        });
      }
    },
  }),

  calculationStore => ({
    expression: () => {
      const { firstPaymentPerc } = calculationStore.values;
      return firstPaymentPerc;
    },
    effect: firstPaymentPerc => {
      calculationStore.setTableRow(
        'tablePayments',
        0,
      )({
        paymentRelation: {
          value: firstPaymentPerc,
        },
      });
    },
  }),

  (calculationStore, calculationProcess) => ({
    expression: () => {
      const { leasingPeriod, graphType, parmentsDecreasePercent, seasonType } =
        calculationStore.values;

      const highSeasonStart = calculationStore.getOption(
        'selectHighSeasonStart',
      );

      return {
        leasingPeriod,
        graphType,
        parmentsDecreasePercent,
        seasonType,
        highSeasonStart: parseInt(highSeasonStart?.name || '2'),
      };
    },
    effect: async (nextParams, prevParams) => {
      if (calculationProcess.hasProcess(Process.LoadKp)) {
        return;
      }

      const { firstPaymentPerc, lastPaymentPerc } = calculationStore.values;
      const {
        leasingPeriod,
        graphType,
        parmentsDecreasePercent,
        seasonType,
        highSeasonStart,
      } = nextParams;

      const prevValues = toJS(calculationStore.tables.tablePayments.rows).map(
        x => x.paymentRelation?.value,
      );
      let payments: Table['rows'] = [
        {
          paymentRelation: {
            value: firstPaymentPerc,
            status: ElementStatus.Disabled,
          },
        },
      ];

      calculationStore.cleanTable('tablePayments');

      switch (graphType) {
        case 100000000: {
          const middleRows = Array.from({ length: leasingPeriod - 2 }, () => ({
            paymentRelation: {
              value: 100,
              status: ElementStatus.Disabled,
            },
          }));
          payments = [...payments, ...middleRows];

          break;
        }

        case 100000001: {
          switch (seasonType) {
            default: {
              const paymentsInStep = Math.ceil((leasingPeriod - 2) / 3);
              const targetSeasonType = calculationStore.getOption(
                'selectSeasonType',
                {
                  value: seasonType,
                },
              );
              const stepsValues: number[] =
                targetSeasonType && targetSeasonType.stepsValues;

              const middleRows = Array.from(
                { length: leasingPeriod - 2 },
                (_v, i) => {
                  let value = stepsValues[2];

                  if (i <= paymentsInStep * 2 - 1) {
                    value = stepsValues[1];
                  }

                  if (i <= paymentsInStep - 1) {
                    value = stepsValues[0];
                  }

                  return {
                    paymentRelation: {
                      value,
                      status: ElementStatus.Disabled,
                    },
                  };
                },
              );
              payments = [...payments, ...middleRows];
              break;
            }
            case 100_000_007: {
              const middleRows = Array.from(
                { length: leasingPeriod - 3 },
                () => ({
                  paymentRelation: {
                    value: 100,
                    status: ElementStatus.Default,
                  },
                }),
              );
              payments = [
                ...payments,
                {
                  paymentRelation: {
                    value: 100,
                    status: ElementStatus.Disabled,
                  },
                },
                ...middleRows,
              ];
              break;
            }
            case null: {
              break;
            }
          }

          break;
        }

        case 100000002: {
          const middleRows = Array.from(
            { length: leasingPeriod - 3 },
            (v, i) => ({
              paymentRelation: {
                value: 100,
                status: ElementStatus.Disabled,
              },
            }),
          );
          for (const i in middleRows) {
            const currRow = middleRows[parseInt(i)];
            const prevRow = middleRows[parseInt(i) - 1];
            currRow.paymentRelation.value = parseFloat(
              (
                ((prevRow ? prevRow.paymentRelation.value : 100) *
                  parmentsDecreasePercent) /
                100
              ).toFixed(2),
            );
          }
          payments = [
            ...payments,
            {
              paymentRelation: {
                value: 100,
                status: ElementStatus.Disabled,
              },
            },
            ...middleRows,
          ];

          break;
        }

        case 100000003: {
          if (!seasonType) {
            return;
          }

          const next_seasonType_option = calculationStore.getOption(
            'selectSeasonType',
            {
              value: seasonType,
            },
          );

          const {
            //@ts-ignore
            startPositions: nextStartPositions,
            //@ts-ignore
            paymentsInStep: nextPaymentsInStep,
            //@ts-ignore
            stepsValues: nextStepsValues,
          } = next_seasonType_option;

          let stepsValues: number[] = nextStepsValues;

          const {
            seasonType: prevSeasonType,
            highSeasonStart: prevHighSeasonStart,
          } = prevParams;
          if (
            prevParams.graphType === nextParams.graphType &&
            prevSeasonType === seasonType &&
            prevHighSeasonStart !== highSeasonStart
          ) {
            /**
             * FIND PREV HIGH, MIDDLE, LOW
             */

            //TODO: change 2 to variable from options selectHighSeasonStart
            const prevShiftNumber = prevHighSeasonStart - 2;

            let middleRows = prevValues.slice(1, PERIODS_NUMBER + 1);

            // prevent unnecessary running shiftRight
            if (prevShiftNumber > 0)
              middleRows = shiftRight(middleRows, prevShiftNumber);

            const prev_seasonType_option = calculationStore.getOption(
              'selectSeasonType',
              {
                value: prevSeasonType,
              },
            );
            const prevStartPositions =
              prev_seasonType_option && prev_seasonType_option.startPositions;

            stepsValues = prevStartPositions.map(
              startPosition => middleRows[startPosition],
            );
            /** */
          }

          /**
           * GENERATE PERIODS
           */

          const nextShiftNumber = highSeasonStart - 2;

          let nextPeriods: number[] = [];

          nextStartPositions.forEach((startPosition, i) => {
            for (
              let j = startPosition;
              j < startPosition + nextPaymentsInStep[i];
              j++
            ) {
              nextPeriods[j] = stepsValues[i];
            }
          });

          if (nextShiftNumber > 0) {
            nextPeriods = shift(nextPeriods, nextShiftNumber);
          }
          nextPeriods.length = PERIODS_NUMBER;

          const middleRows = Array.from(
            { length: leasingPeriod - 2 },
            (v, i) => {
              return {
                paymentRelation: {
                  value:
                    i < PERIODS_NUMBER &&
                    // i - PERIODS_NUMBER * Math.floor(i / PERIODS_NUMBER)
                    nextPeriods[i],
                  status:
                    i < PERIODS_NUMBER
                      ? ElementStatus.Default
                      : ElementStatus.Disabled,
                },
              };
            },
          );

          payments = [...payments, ...middleRows];

          break;
        }

        case 100000004: {
          const middleRows = Array.from({ length: leasingPeriod - 5 }, () => ({
            paymentRelation: {
              value: 100,
              status: ElementStatus.Disabled,
            },
          }));

          payments = [
            ...payments,
            {
              paymentRelation: {
                value: 25,
                status: ElementStatus.Default,
              },
            },
            {
              paymentRelation: {
                value: 50,
                status: ElementStatus.Default,
              },
            },
            {
              paymentRelation: {
                value: 75,
                status: ElementStatus.Default,
              },
            },
            ...middleRows,
          ];
          break;
        }

        default: {
          break;
        }
      }

      calculationStore.replaceTableRows('tablePayments')([
        ...payments,
        {
          paymentRelation: {
            value: lastPaymentPerc,
            status: ElementStatus.Disabled,
          },
        },
      ]);
    },
    options: {
      fireImmediately: true,
    },
  }),

  calculationStore => ({
    expression: () => {
      const { lastPaymentPerc, leasingPeriod } = calculationStore.values;
      return { lastPaymentPerc, leasingPeriod };
    },
    effect: ({ lastPaymentPerc }) => {
      calculationStore.setTableRow(
        'tablePayments',
        calculationStore.tables.tablePayments.rows.length - 1,
      )({
        paymentRelation: {
          value: lastPaymentPerc,
          status: ElementStatus.Disabled,
        },
      });
    },
    options: {
      fireImmediately: true,
    },
  }),

  (calculationStore, calculationProcess) => ({
    expression: () => {
      const { leaseObjectCategory } = calculationStore.values;
      return leaseObjectCategory;
    },
    effect: leaseObjectCategory => {
      if (calculationProcess.hasProcess(Process.LoadKp)) {
        return;
      }
      const isTrailer = leaseObjectCategory === 100000004;

      if (isTrailer) {
        const otherInsuranceCompany =
          calculationStore.tables.tableInsurance.options?.insuranceCompany?.find(
            x => x.name?.includes('ПРОЧИЕ'),
          );
        if (otherInsuranceCompany) {
          const insuranceOtherFilter = singleValueFilter(
            otherInsuranceCompany.value,
          );
          calculationStore.setTableRow(
            'tableInsurance',
            rows => rows.findIndex(x => x?.key === 'osago'),
            true,
          )({
            insuranceCompany: {
              filter: insuranceOtherFilter,
              value: otherInsuranceCompany.value,
              status: ElementStatus.Disabled,
            },
            insCost: {
              value: 0,
              status: ElementStatus.Disabled,
            },
          });
        }
      } else {
        calculationStore.setTableRow(
          'tableInsurance',
          rows => rows.findIndex(x => x?.key === 'osago'),
          true,
        )({
          insuranceCompany: {
            filter: insuranceOsagoDefaultFilter,
            value: isTrailer ? null : undefined,
            status: ElementStatus.Default,
          },
          insCost: {
            status: ElementStatus.Default,
          },
        });
      }
    },
  }),
  (calculationStore, calculationProcess) => ({
    expression: () => calculationStore.getOption('selectBrand'),
    effect: brand => {
      if (calculationProcess.hasProcess(Process.LoadKp)) {
        return;
      }
      if (brand?.evo_id === 'BRAND49') {
        const { tableInsurance } = calculationStore.tables;
        // ПАО "ГРУППА РЕНЕССАНС СТРАХОВАНИЕ"
        const targetInsuranceCompany =
          tableInsurance.options?.insuranceCompany?.find(
            x => x.evo_inn === '7725497022',
          );
        if (targetInsuranceCompany) {
          const targetInsuranceFilter = singleValueFilter(
            targetInsuranceCompany.value,
          );
          calculationStore.setTableRow('tableInsurance', rows =>
            rows.findIndex(x => x?.key === 'kasko'),
          )({
            insuranceCompany: {
              filter: targetInsuranceFilter,
              value: targetInsuranceCompany.value,
              status: ElementStatus.Disabled,
            },
          });
        }
      } else {
        calculationStore.setTableRow('tableInsurance', rows =>
          rows.findIndex(x => x?.key === 'kasko'),
        )({
          insuranceCompany: {
            filter: insuranceKaskoDefaultFilter,
            status: ElementStatus.Default,
            value: null,
          },
        });
      }
    },
  }),
] as IReactionEffect[];
