<template>
  <div class="q-gutter-y-md">
    <q-input
      v-model="filter.search"
      dense
      filled
      debounce="1000"
      :placeholder="$t('signedApplications.nameService')"
      @keydown.esc="filter.search = ''"
      @keydown.enter="startSearch()"
    >
      <template #prepend>
        <q-icon name="search" />
      </template>
      <template #append>
        <q-btn dense flat icon="settings" round @click="toggleFilter">
          <q-badge floating rounded color="red" v-if="!filter.visible && !!filledFields">{{ filledFields }}</q-badge>
        </q-btn>
      </template>
    </q-input>

    <q-slide-transition>
      <q-card bordered flat v-show="filter.visible">
        <q-card-section>
          <div class="row-md q-gutter-x-md">
            <div class="q-mt-sm col">
              <div>
                <BaseAutocompleteSelect
                  :model.sync="services"
                  :async-getter="getService"
                  :is-multiple="false"
                  :field-label="$t('signedApplications.labelService')"
                  label-value="shortName"
                  @value="handleServicesValues"
                />
              </div>
            </div>
            <div class="q-mt-sm col">
              <div>
                <q-select
                  v-model="filter.goals"
                  :options="goalsList"
                  filled
                  stretch
                  flat
                  :disable="!services.selected"
                  borderless
                  multiple
                  :label="$t('signedApplications.goalService')"
                  style="min-width: 20em"
                  emit-value
                  map-options
                >
                </q-select>
              </div>
            </div>
            <div class="q-mt-sm col">
              <div>
                <q-select
                  v-model="decisionCode.selected"
                  :options="starusData"
                  filled
                  stretch
                  flat
                  borderless
                  :label="$t('signedApplications.solutionType')"
                  style="min-width: 20em"
                  map-options
                  @input="handelDecisionCodeChange"
                >
                </q-select>
              </div>
            </div>
          </div>
          <div class="row-md q-gutter-x-md justify-end">
            <!-- Фильтр Дата принятия решения убрать временно  -->
            <!-- <div class="q-mt-sm col q-mr-none" style="max-width: 310px">
              <div>
                <p class="q-ma-none">
                  {{ $t('signedApplications.dateFinish') }}
                </p>
                <date-application-input
                  :from.sync="filter.fromDateFinish"
                  :to.sync="filter.toDateFinish"
                />
              </div>
            </div> -->
            <div class="q-mt-sm col q-ml-md">
              <div>
                {{ $t('signedApplications.dateApplication') }}
                <date-application-input
                  :from.sync="filter.fromDateStart"
                  :to.sync="filter.toDateStart"
                />
              </div>
            </div>
          </div>
          <div class="col-auto q-mt-md srow-md q-gutter-x-md justify-end" >
            <q-btn
              icon="search"
              color="primary"
              style="width: 15%;height: 100%"
              :label="$t('statements.Common.button.search')"
              :loading="loading"
              :disable="!searchButtonActive"
              @click="startSearch()"
            />
          </div>
        </q-card-section>
        <q-btn
          dense
          flat
          class="absolute-top-right"
          color="grey-7"
          icon="close"
          size="10px"
          @click="resetFilter(true)"
        />
      </q-card>
    </q-slide-transition>
  </div>
</template>


<script lang="ts">
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
import {
  convertDateFormat,
  convertDateFormatWithoutLocale,
  convertDateFromBackendFormat,
  parseDateFromString,
} from '@utils/format-date';
import { StatementsSearchQuery } from '@components/statements';
import { ServiceApi } from '@openapi/registry-service';
import omit from 'lodash/omit';
import { notifyError } from '@utils/notify';
import { DateFormat } from '@constants/utils/format-date';
import DateApplicationInput from '@components/statements/components/date-application-input.vue';
import XDateRange from '@components/statements/components/x-date-range.vue';
import isEqual from 'lodash/isEqual';
import get from 'lodash/get';
import isEmpty from 'lodash/isEmpty';
import { isArray } from 'lodash';

export interface SignedStatementsSearchQuery extends StatementsSearchQuery {
  finishDateRange: string;
  startDateRange: string;
  decisionCode: string;
}

export interface Filter {
  search: string;
  services?: string;
  goals?: any;
  visible: boolean;
  page?: number;
  decisionCode?: string;
  fromDateFinish: Date | null;
  toDateFinish: Date | null;
  fromDateStart: Date | null;
  toDateStart: Date | null;
}

@Component({
  methods: {
    convertDateFromBackendFormat,
    convertDateFormatWithoutLocale,
  },
  components: {
    DateApplicationInput,
    XDateRange,
  },
})
export default class SearchBar extends Vue {
  @Prop() loading: boolean;
  @Prop() query!: SignedStatementsSearchQuery;

  services = {
    search: '',
    records: [],
    selected: null,
    loading: false,
  };

  decisionCode = {
    selected: null as any,  
  }

  starusData = [
    {
      label: 'Услуга оказана',
      value: 10,
    },
    {
      label: 'Отказано в предоставлении услуги',
      value: 11,
    },
    {
      label: 'Отказано в приеме документов',
      value: 12,
    },
  ];

  daterange:any;
  daterangeDecision:any;
  goalsList: any[] = [];
  filter: Filter = {
    search: '',
    services: '',
    decisionCode: '',
    goals: [],
    visible: false,
    fromDateFinish: null,
    toDateFinish: null,
    fromDateStart: null,
    toDateStart: null,
  };

  get searchButtonActive() {
    return this.searchIsFilled || this.subSearchIsFilled;
  }

  get subSearchIsFilled(): boolean {
    return !!this.filter.decisionCode ||
      !!this.filter.services ||
      !!this.filter.goals?.length ||
      !!this.filter.fromDateFinish ||
      !!this.filter.toDateFinish ||
      !!this.filter.fromDateStart ||
      !!this.filter.toDateStart;
  }

  get searchIsFilled(): boolean {
    return !!this.filter.search;
  }

  get filledFields(): number {
    return Object.keys(this.filter).reduce((count, key) => {
      if (['visible', 'search'].includes(key)) return count;
      const value = get(this.filter, key);
      let n = !!value ? 1 : 0;
      if (isArray(value)) {
        n = isEmpty(value) ? 0 : 1
      }
      
      return count + n;
    }, 0)
  }

  @Watch('filter', { deep: true })
  filterHandler(filter: Filter): void {
    this.setRoute(filter);
  }

  @Watch('query', { deep: true })
  queryHandler(query: SignedStatementsSearchQuery): void {
    this.parseQueryParams(query);
  }

  toggleFilter(): void {
    this.filter.visible = !this.filter.visible;
  }

  handelDecisionCodeChange(decision: {value:string}): void {
    this.filter.decisionCode = decision.value;
  }

  resetFilter(close = false): void {
    if (close) this.filter.visible = false;
    this.services = {
      search: '',
      records: [],
      selected: null,
      loading: false,
    };
    this.filter.services = undefined;
    this.filter.decisionCode = undefined;
    this.filter.goals = [];
    this.filter.fromDateFinish = null;
    this.filter.toDateFinish = null;
    this.filter.fromDateStart = null;
    this.filter.toDateStart = null;
    this.decisionCode.selected = null;
    this.startSearch();
    // this.$router.push({ name: 'signedApplications',});
  }

  private resetPagination() {
    this.$emit('pagination');
    return omit(this.$route.query, 'page');
  }

   startSearch(): void {
    const fulltext: string[] = [];
    const query: string[] = [];
    const {
      services,
      goals,
      decisionCode,
      fromDateFinish,
      toDateFinish,
      fromDateStart,
      toDateStart,
    } = this.filter;
    let { search } = this.filter;

    if (search) {
      if (search && !/^\d+$/g.test(search)) {
        // Проверяем, что не только числа в строке ввели иначе ищем по common.orderId
        search = search.replace(/\\/g, '');
        search = search.replace(/'/g, "\\'");
        search = search.replace(/"/g, '\\"');

        fulltext.push(`system.shortName=searchprefix="${search}"`);
        fulltext.push(`system.shortName=search="${search}"`);
        fulltext.push(`system.shortName=searchany="${search}"`);
      } else if (search) {
        query.push(`common.orderId=like=${search}*`); // Префиксный полнотекстовый поиск для номера заявления и полного имени заявителя
      }
    }
    if (services?.length) {
      const services = this.filter.services || undefined;
      const goals = this.filter.goals || undefined;
      query.push(`system.serviceId==${services}`);
    }
    if (goals?.length) {
      const goalsQuery = goals
        .map((value: string) => `statement.goal==${value}`)
        .join(' or ');
      query.push(`(${goalsQuery})`);
    }
    if (decisionCode) {
      query.push(`system.decision.code==${decisionCode}`);
    }

    if (fromDateFinish) {
      query.push(
        `common.finishDate>=${convertDateFromBackendFormat(
          fromDateFinish,
          DateFormat.invertedDate
        )}`
      );
    }
    if (toDateFinish) {
      const toPlus = new Date(toDateFinish);
      toPlus.setDate(toPlus.getDate() + 1);
      query.push(
        `common.finishDate<${convertDateFromBackendFormat(
          toPlus,
          DateFormat.invertedDate
        )}`
      );
    }

    if (fromDateStart) {
      query.push(
        `system.startDateIso>=${convertDateFromBackendFormat(
          fromDateStart,
          DateFormat.invertedDate
        )}`
      );
    }
    if (toDateStart) {
      const toPlus = new Date(toDateStart);
      toPlus.setDate(toPlus.getDate() + 1);
      query.push(
        `system.startDateIso<${convertDateFromBackendFormat(
          toPlus,
          DateFormat.invertedDate
        )}`
      );
    }

    const qObj = {
      query: query.join(' and '),
      fulltext: fulltext.join(' or '),
    };
    this.$emit('query', qObj);
  }

  private async getService() {
    try {
      this.services.loading = true;
      const fulltextString = this.services.search
        ? `(shortName=searchprefix="${this.services.search}" or shortName=search="${this.services.search}") or (fullName=searchprefix="${this.services.search}" or fullName=search="${this.services.search}")`
        : '';
      const records = await new ServiceApi().searchService('', fulltextString);
      return records.data;
    } catch (e) {
      if (e instanceof Error) notifyError(e.message);
    } finally {
      this.services.loading = false;
    }
  }

  private handleServicesValues(val: any): void {
    if (val) {
      this.goalsList = val.goalsList || [];
      this.filter.services = val.id || '';
    } else {
      this.filter.services = '';
      this.goalsList = [];
      this.filter.goals = [];
    }
  }

  setRoute(filter: Filter): void {
    const oldQueryParams = this.resetPagination();

    const search = this.filter.search || undefined;

    const services = this.filter.services || undefined;
    const goals = this.filter.goals?.join() || undefined;

    const decisionCode = this.filter.decisionCode;

    let finishDateRange: string | undefined;
    if (this.filter.fromDateFinish || this.filter.toDateFinish) {
      finishDateRange = [
        `${(this.filter.fromDateFinish
          ? convertDateFormatWithoutLocale(this.filter.fromDateFinish)
          : '')}`,
        `${(this.filter.toDateFinish
          ? convertDateFormatWithoutLocale(this.filter.toDateFinish)
          : '')}`,
      ].join(',');
    }

    let startDateRange: string | undefined;
    if (this.filter.fromDateStart || this.filter.toDateStart) {
      startDateRange = [
        `${(this.filter.fromDateStart
          ? convertDateFormatWithoutLocale(this.filter.fromDateStart)
          : '')}`,
        `${(this.filter.toDateStart
          ? convertDateFormatWithoutLocale(this.filter.toDateStart)
          : '')}`,
      ].join(',');
    }

    const query = {
      ...oldQueryParams,
      search,
      services,
      goals,
      decisionCode,
      finishDateRange,
      startDateRange,
    };
    
    if (!isEqual(oldQueryParams, query))
    this.$router.push({ query });
  }

  private parseQueryParams(query: SignedStatementsSearchQuery): void {
    if (query) {
      const {
        search,
        services,
        goals,
        finishDateRange,
        startDateRange,
        decisionCode,
      } = query;
      
      if (goals?.length) {
        const codes = typeof goals === 'string' ? goals.split(',') : [];
        this.filter.goals = codes;
      }

      if (services) {
        this.filter.services = services;
        this.setServicesQuery();
      }

      if (search) {
        this.filter.search = search;
      }

      if (decisionCode) {
        this.filter.decisionCode = decisionCode;
        this.decisionCode.selected = this.starusData.find((el)=> el.value === parseInt(decisionCode) );
      }

      if (startDateRange) {
        const [
          fromDateStart,
          toDateStart,
        ] = startDateRange.split(',').map((d) => !!d ? parseDateFromString(d, DateFormat.date) : null);
        this.filter = {
          ...this.filter,
          fromDateStart,
          toDateStart,
        }
      }

      if (finishDateRange) {
        const [
          fromDateFinish,
          toDateFinish,
        ] = finishDateRange.split(',').map((d) => !!d ? parseDateFromString(d, DateFormat.date) : null);
        this.filter = {
          ...this.filter,
          fromDateFinish,
          toDateFinish,
        }
      }

    }
  }

  private async setServicesQuery() {
    if (this.filter.services?.length) {
      const queryServices = `id==${this.filter.services}`;
      const organizationsSelected = await new ServiceApi().searchService(
        queryServices
      );
      // @ts-ignore
      this.services.selected = organizationsSelected.data[0];
      // @ts-ignore
      this.goalsList = organizationsSelected.data[0].goalsList;
    }
  }

  private async created(): Promise<void> {
    this.parseQueryParams(this.query);
    if (this.subSearchIsFilled) {
      this.filter.visible = true;
    }
    this.startSearch();
  }
}
</script>

<style lang="sass">
.m-search-bar .q-field__control-container > .q-field__native.row.items-center > span
  white-space: nowrap
  text-overflow: ellipsis
  overflow: hidden

.m-search-bar
  justify-content: space-between
  background: white
  color: #757575
</style>
