<template>
  <div class="q-gutter-y-md">
    <q-slide-transition>
      <q-input
        v-show="!expanded"
        v-model="searchString"
        dense
        filled
        debounce="1000"
        :placeholder="$t('personalAccounts.searchBarPlaceholder')"
        @keydown.esc="resetSearch"
        @keydown.enter="$emit('update:table-model', model)"
      >
        <template #prepend>
          <q-icon name="search" />
        </template>
        <template #append>
          <q-btn dense flat icon="settings" round @click="toggleExpand" />
        </template>
      </q-input>
    </q-slide-transition>

    <q-slide-transition>
      <q-card bordered flat v-show="expanded">
        <q-card-section horizontal class="q-pa-md q-px-md q-gutter-x-md">
          <q-input
            :value="searchData.fullName"
            dense
            filled
            debounce="1000"
            :label="$t('personalAccounts.fullName')"
            style="flex: 4 1 0%"
            @input="setPersonFields($event, 'fullName')"
            @keydown.enter="$emit('update:table-model', model)"
          />
          <q-input
            :value="denormalizeDate(searchData.birthday)"
            dense
            filled
            debounce="1000"
            ref="birthday"
            :clearable="true"
            mask="##.##.####"
            :label="$t('personalAccounts.birthday')"
            style="flex: 2 0 0%"
            @input="setPersonFields(normalizeDate($event), 'birthday')"
            @keydown.enter="$emit('update:table-model', model)"
          >
            <template v-slot:prepend>
              <q-icon name="event" class="cursor-pointer">
                <q-popup-proxy
                  cover
                  transition-show="scale"
                  transition-hide="scale"
                >
                  <q-date
                    mask="YYYY-MM-DD"
                    :value="searchData.birthday"
                    @input="setPersonFields($event, 'birthday')"
                  >
                    <div class="row items-center justify-end">
                      <q-btn
                        v-close-popup
                        :label="$t('personalAccounts.close')"
                        color="primary"
                        flat
                      />
                    </div>
                  </q-date>
                </q-popup-proxy>
              </q-icon>
            </template>
          </q-input>
          <q-input
            class="q-pb-none"
            :value="searchData.inn"
            :rules="[innRules]"
            dense
            filled
            debounce="1000"
            :label="$t('personalAccounts.inn')"
            mask="############"
            style="flex: 2.2 0 0%"
            @input="setPersonFields($event, 'inn')"
            @keydown.enter="$emit('update:table-model', model)"
          />
          <q-input
            :value="searchData.snils"
            dense
            filled
            debounce="1000"
            :label="$t('personalAccounts.snils')"
            mask="###########"
            style="flex: 2 0 0%"
            @input="setPersonFields($event, 'snils')"
            @keydown.enter="$emit('update:table-model', model)"
          />
          <q-space style="flex: 4 0 0%" />
        </q-card-section>
        <q-card-section horizontal class="q-pt-md q-px-md q-gutter-x-md">
          <q-input
            :value="searchData.email"
            dense
            filled
            debounce="1000"
            :label="$t('personalAccounts.email')"
            style="flex: 1 0 0%"
            @input="setPersonFields($event, 'email')"
            @keydown.enter="$emit('update:table-model', model)"
          >
            <template v-slot:prepend>
              <q-icon name="email" />
            </template>
          </q-input>
          <q-input
            :value="searchData.phone"
            dense
            filled
            debounce="1000"
            :label="$t('personalAccounts.phone')"
            style="flex: 1 0 0%"
            @input="setPersonFields($event, 'phone')"
            @keydown.enter="$emit('update:table-model', model)"
          >
            <template v-slot:prepend>
              <q-icon name="phone" />
            </template>
          </q-input>
          <q-input
            :value="searchData.series"
            dense
            filled
            debounce="1000"
            :label="$t('personalAccounts.passportSerial')"
            mask="####"
            style="flex: 1 0 0%"
            @input="setPersonFields($event, 'series')"
            @keydown.enter="$emit('update:table-model', model)"
          />
          <q-input
            :value="searchData.number"
            dense
            filled
            debounce="1000"
            :label="$t('personalAccounts.passportNumber')"
            mask="######"
            style="flex: 1 0 0%"
            @input="setPersonFields($event, 'number')"
            @keydown.enter="$emit('update:table-model', model)"
          />
          <q-input
            :value="searchData.address"
            dense
            filled
            debounce="1000"
            :label="$t('personalAccounts.address')"
            style="flex: 2 0 0%"
            @input="setPersonFields($event, 'address')"
            @keydown.enter="$emit('update:table-model', model)"
          />
          <q-space style="flex: 4 0 0%" />
        </q-card-section>
        <q-card-section horizontal class="q-pa-md q-gutter-x-md">
          <q-input
            :value="applicationNum"
            dense
            filled
            debounce="1000"
            :label="$t('personalAccounts.statementNumber')"
            @input="setStatementNumber"
            @keydown.enter="$emit('update:table-model', model)"
          />
          <q-input
            :value="solutionNum"
            dense
            filled
            debounce="1000"
            :label="$t('personalAccounts.resolutionNumber')"
            @input="setResolutionNumber"
            @keydown.enter="$emit('update:table-model', model)"
          />
        </q-card-section>
        <q-btn
          dense
          flat
          class="absolute-top-right"
          color="grey-7"
          icon="close"
          size="10px"
          @click="closeExpand"
        />
      </q-card>
    </q-slide-transition>
  </div>
</template>

<script lang="ts">
import Vue from 'vue';
import { Component, PropSync, Ref, Watch } from 'vue-property-decorator';
import { isEmpty, isNil, omit } from 'lodash';

import type { PersonalAccountsTableModel, SearchData } from '@models/personal-accounts';
import { convertDateFormat, DateFormat } from '@/utils/format-date';
import { QInput } from 'quasar';

type SearchQueryMap = Record<keyof SearchData, (model: SearchData) => string>;

const fullNameMask = /((?:[А-ЯЁа-яё]+)(?:[\s-]+[А-ЯЁа-яё]+)*)/;
const passportNumberMask = /(?<!\.)(\b\d{2}[-\s]\d{2}|\d{4})[/\s](\d{2}(?:[-\s]?\d{2}){2}|\d{6})\b/;
const phoneMaskWeak = /\+[()-\s\d]+\b/;
const phoneMaskStict = /(\+(?:(?:9[679]|8[035789]|6[789]|5[90]|42|3[578]|2[1-689])|9[0-58]|8[1246]|6[0-6]|5[1-8]|4[013-9]|3[0-469]|2[70]|7|1)(?:[\s()-]*\d){0,13}\d\b)/;
const emailMaskStrict = /\b(\w+(?:[-.]\w+)*@\w+(?:[-.]\w+)+)\b/;
const emailMaskWeak = /\b[-.\w]+@[-.\w]+\b/;
const dateMaskStrict = /\b([0-9]{2})(?:\.([0-9]{2}))(?:\.([0-9]{2,4}))\b/;
const snilsMaskStrict = /\b(?<!\+)(\d{3}(?:[-\s]?\d{3}){2}(?:\s?\d{2}))\b/;
const innMaskStrict = /(\b\d{3}(?:[-\s]?\d{3})(?:(?:[-\s]?\d{2}){2}|(?:[-\s]?\d{3}){2}))\b/;

function stripNWC(str: string): string {
  return str.replaceAll(/\W/g, '');
}
function normolizeSpaces(str: string): string {
  return str.replaceAll(/\s+/g, ' ');
}

function clearNumber(str: string): string {
  return str.replaceAll(/\D+/g, '');
}

function transformDate(str: string): string {
  return str.replaceAll('.', '-');
}

@Component({})
export default class PersonalAccountsSearchBar extends Vue {
  @PropSync('tableModel', { type: Object }) model!: PersonalAccountsTableModel;

  @Ref('birthday') birthdayInput: QInput;

  expanded = false;

  searchString = '';
  fetchFrom = 'person';
  oldFetchFrom = 'person';

  searchData: SearchData = {
    applicationNum: '',

    solutionNum: '',

    email: '',
    phone: '',

    series: '',
    number: '',
    documentType: '',

    address: '',

    snils: '',
    inn: '',
    birthday: '',
    fullName: '',
  };

  birthdayProxy = '';

  extractors = {
    inn(searchData: SearchData, search: string): SearchData {
      const [, inn] = search.match(innMaskStrict) || [];
      searchData.inn = inn || '';
      return searchData;
    },

    snils(searchData: SearchData, search: string): SearchData {
      const [, snils] = search.match(snilsMaskStrict) || [];
      searchData.snils = snils || '';
      return searchData;
    },

    birthday(searchData: SearchData, search: string): SearchData {
      const [date] = search.match(dateMaskStrict) || [];
      searchData.birthday =
        convertDateFormat(date, DateFormat.date, DateFormat.invertedDate) || '';
      return searchData;
    },

    fullName(searchData: SearchData, search: string): SearchData {
      const [fullName] = search.match(fullNameMask) || [];
      searchData.fullName = fullName || '';
      return searchData;
    },

    phone(searchData: SearchData, search: string): SearchData {
      const [phone] = search.match(phoneMaskStict) || [];
      searchData.phone = phone || '';
      return searchData;
    },

    email(searchData: SearchData, search: string): SearchData {
      const [email] = search.match(emailMaskStrict) || [];
      searchData.email = email || '';
      return searchData;
    },

    passportNumber(searchData: SearchData, search: string): SearchData {
      const [, series, number] = search.match(passportNumberMask) || [];
      searchData.documentType = series || number ? 'PasportRF' : '';
      searchData.series = series || '';
      searchData.number = number || '';
      return searchData;
    },
  };

  query: string[] = [];
  fullText: string[] = [];

  created() {
    this.searchData = this.model.searchData;
    this.expanded = Object.values(this.searchData).reduce((res: boolean, val) => {
      return res || !!val;
    }, false)
  }

  @Watch('searchString')
  onSearchStringChange(search: string, old: string): void {
    this.extractFields(normolizeSpaces(search));
  }

  @Watch('searchData')
  onSearchModelChange(searchData: SearchData): void {
    this.$emit('update:table-model', {
      ...this.model,
      searchData,
    });

    const paramsQuery: Record<string, string> = { ...searchData };
    const routeQuery = { ...this.$route.query };

    Object.keys(paramsQuery).forEach((keyQuery) => {
      if (isEmpty(paramsQuery[keyQuery])) {
        delete paramsQuery[keyQuery];
        delete routeQuery[keyQuery];
      }
    });

    this.$router.push({
      query: {
        ...routeQuery,
        ...paramsQuery,
      },
    });
  }

  setPersonFields(value: string, field: string): void {
    if (isNil(value)) {
      value = '';
    }
    this.setSearchModel({
      ...omit(this.searchData, ['applicationNum', 'solutionNum']),
      [field]: value,
    });
    console.log(value);
  }

  get solutionNum(): string {
    return this.searchData.solutionNum;
  }

  innRules(val: any): any {
    const str: any = val.toString();
    if (str && str > 0 && str.length === 12) {
      const strArr: any = Array.from(str);
      const arrTest: any = [7, 2, 4, 10, 3, 5, 9, 4, 6, 8];
      const arrTest2: any = [3, 7, 2, 4, 10, 3, 5, 9, 4, 6, 8];
      const result: any = arrTest.reduce(
        (sum: any, current: any, i: any) => sum + current * strArr[i],
        0
      );
      const result2: any = arrTest2.reduce(
        (sum: any, current: any, i: any) => sum + current * strArr[i],
        0
      );
      const one: any = result - parseInt((result / 11).toString()) * 11;
      const two: any = result2 - parseInt((result2 / 11).toString()) * 11;
      // console.log(one, Number(strArr[10]) === one)
      // console.log(two, Number(strArr[11]) === two)
      if (Number(strArr[10]) !== one || Number(strArr[11]) !== two) {
        return 'Неправильное контрольное число';
      }
    } else if (str !== '') {
      return 'ИНН может состоять только из 12 цифр';
    }
  }

  setResolutionNumber(value: string): void {
    this.setSearchModel({
      solutionNum: value,
    });
  }

  get applicationNum(): string {
    return this.searchData.applicationNum;
  }

  setStatementNumber(value: string): void {
    this.setSearchModel({
      applicationNum: clearNumber(value),
    });
  }

  extractFields(search: string): void {
    this.searchData = Object.values(this.extractors).reduce(
      (searchData, extractor) => {
        return extractor(searchData, search);
      },
      { ...this.searchData }
    );
  }

  toggleExpand(): void {
    this.expanded = !this.expanded;
  }

  closeExpand(): void {
    this.searchString = '';
    this.expanded = false;
    this.setSearchModel();
  }

  resetSearch(): void {
    this.searchString = '';
  }

  setSearchModel(newSearchModel: Partial<SearchData> = {}): void {
    const searchData: Partial<SearchData> = {};
    const keys = Object.keys(this.searchData) as Array<keyof SearchData>;
    keys.forEach((key) => {
      searchData[key] = newSearchModel[key] || '';
    });
    // TODO Найти другое решение
    if (newSearchModel.birthday === '') {
      this.birthdayInput.$data.innerValue = '';
    }
    // TODO Добавить селектор документа
    searchData.documentType =
      newSearchModel.series || newSearchModel.number ? 'PasportRF' : '';
    this.searchData = searchData as SearchData;
  }

  normalizeDate(date: string): string {
    if (!date) return '';
    const [day, month, year] = date.split('.');
    return [year, month, day].filter((i) => !!i).join('-');
  }

  denormalizeDate(date: string): string {
    if (!date) return '';
    const [year, month, day] = date.split('-');
    return [day, month, year].filter((i) => !!i).join('.');
  }
}
</script>
