<template>
  <div class="register-new-recruit">
    <block-loader type="QBtn" :loading="loading">
      <r-btn
        dense
        label="Вызвать"
        icon="pgs-roll"
        :disable="disable || disabled"
        @click="open"
        no-wrap
      >
        <q-tooltip max-width="200px" v-if="disabledTooltip">
          {{ disabledTooltip }}
        </q-tooltip>
      </r-btn>
    </block-loader>
    <operation-dialog
      persistent
      ref="dialog"
      :title="title"
      width="750px"
      :sub="sub"
      process-key="milBaseRouteProcess"
      v-model="opened"
      @hide="close"
    >
      <div class="row q-col-gutter-md">
        <div class="col-12">
          <r-select-group
            label="Причина вызова в военкомат"
            dense
            options-dense
            v-model="summonObjective"
            :string-options="reasonsCalling"
            :display-value="summonObjectiveName"
          >
          </r-select-group>
        </div>
        <div class="col-12 SummonDateInput">
          <r-date-time-input
            v-model="summonDate"
            :emit-format="isoDateFormat"
            :date-options="isDateAvailable"
            :time-options="isTimeAvailable"
            :default-time="defaultTime"
            :default-year-month="defaultYearMonth"
            label="Дата и время явки"
          />
          <span v-if="summonDate" class="SummonDateInput-Count">
            Записано на день:
            <span>{{ countRecruitOfDay }}</span>
          </span>
        </div>
        <div class="full-width wrapper-block">
          <span class="wrapper-block__title">Адреса и способы направления</span>
          <div class="CallListTable">
            <div class="full-width headers CallListTable-Header">
              <div class="q-pl-xs flex">
                <div class="self-center">Адреса направления</div>
              </div>
              <div class="text-center">
                <q-checkbox
                  class="LabelSelect-Select"
                  id="meet"
                  size="sm"
                  type="checkbox"
                  :value="massCheckbox['14']"
                  @input="(v) => setCheckboxColumn('14', v)"
                />Нарочно
              </div>
              <div class="text-center">
                <q-checkbox
                  class="LabelSelect-Select"
                  id="mail"
                  size="sm"
                  type="checkbox"
                  :value="massCheckbox['15']"
                  @input="(v) => setCheckboxColumn('15', v)"
                />Письмо
              </div>
              <div class="flex flex-center cursor-pointer">
                <q-icon
                  color="negative"
                  size="19px"
                  name="pgs-delete"
                  @click="deleteFields"
                />
              </div>
            </div>
            <div class="full-width">
              <q-table grid :hidePagination="true" :data="rows" row-key="name">
                <template v-slot:item="props">
                  <div class="full-width body CallListTable-Row">
                    <div class="center">
                      <div class="CallListTable-Row__Address">
                        <span>{{
                          getAddressTypesDictionary[props.row.name]
                        }}</span>
                        <span>{{ props.row.reg }}</span>
                      </div>
                    </div>
                    <div class="flex justify-center">
                      <q-checkbox
                        class="LabelSelect-Select"
                        :id="props.row.name"
                        type="checkbox"
                        :value="props.row['14']"
                        @input="(v) => setInputValue(props.row.index, '14', v)"
                      />
                    </div>
                    <div class="flex justify-center">
                      <q-checkbox
                        class="LabelSelect-Select"
                        :id="props.row.name"
                        type="checkbox"
                        :value="props.row['15']"
                        @input="(v) => setInputValue(props.row.index, '15', v)"
                      />
                    </div>
                    <div class="flex flex-center cursor-pointer">
                      <q-icon
                        color="negative"
                        size="23px"
                        name="pgs-delete"
                        @click="deleteField(props.row.index)"
                      />
                    </div>
                  </div>
                </template>
              </q-table>
            </div>
            <div
              :class="[
                'AddNewField-Group',
                { 'AddNewField-Extend': getAddFieldOption },
              ]"
            >
              <r-select
                dense
                options-dense
                placeholder="Адреса направления"
                v-model="newAddressType"
                :options="getAddressTypesOptions"
              />
              <r-btn
                action
                :label="getAddFieldOption ? '' : 'Добавить адреса'"
                icon="pgs-plus"
                @click="
                  getAddFieldOption
                    ? addNewField()
                    : (addFieldOption = !addFieldOption)
                "
              />
            </div>
          </div>
        </div>
      </div>
      <template #process>
        <result-block type="info" icon="pgs-document" :header="processMessage">
        </result-block>
      </template>
      <template #result>
        <result-block icon="pgs-document" :header="resultMessage">
        </result-block>
      </template>
      <template #right-actions>
        <r-btn
          action
          label="Вызвать"
          :disable="disable || disableSubmitBtn || !dateIsAvailable"
          @click="action"
        >
          <q-tooltip max-width="250px" v-if="emptyTypeCheck.empty">
            {{ emptyTypeCheck.message }}
          </q-tooltip>
        </r-btn>
      </template>
      <template #right-actions-result>
        <r-btn
          action
          label="Продолжить"
          icon-right="pgs-shevron-right-off"
          @click="finish"
        />
      </template>
    </operation-dialog>
  </div>
</template>

<i18n>
{
  "ru": {
    "Summon": {
      "selected": "не выбрано | один рекрут | {n} рекрута | {n} рекрутов",
      "process": " | Документ формируется | Документы формируются | Документы формируются",
      "result": " | Документ сформирован | Документы сформированы | Документы сформированы"
    }
  }
}
</i18n>

<style lang="scss" scoped>
.wrapper-block {
  position: relative;
  padding-top: 23px;
  &__title {
    font-family: 'Golos Text', sans-serif;
    font-style: normal;
    font-weight: 600;
    font-size: 12px;
    line-height: 16px;
    color: rgba(2, 12, 18, 0.58);
    position: absolute;
    padding: 0 5px;
    background: #ffffff;
    top: 13px;
    left: 24px;
  }
}
.CallListTable {
  border: 1px solid rgba(2, 12, 18, 0.15);
  border-radius: 8px;
  padding: 10px 10px 0 10px;
  &-Header {
    display: grid;
    grid-template-columns: 1.4fr 0.4fr 0.4fr 0.4fr;
    padding: 5px;
    background: #e5edf5;
    border-bottom: 1px solid rgba(2, 12, 18, 0.15);
    box-sizing: border-box;
    div:not(:last-child) {
      border-right: 1px solid rgba(2, 12, 18, 0.15);
    }
  }
  &-Row {
    display: grid;
    grid-template-columns: 1.4fr 0.4fr 0.4fr 0.4fr;
    border-bottom: 1px solid rgba(2, 12, 18, 0.15);
    padding: 5px;
    //margin: 5px 0;
    div:not(:last-child) {
      border-right: 1px solid rgba(2, 12, 18, 0.15);
    }
    &__Address {
      display: flex;
      flex-direction: column;
      font-family: 'Golos UI', sans-serif;
      font-style: normal;
      font-weight: 400;
      font-size: 12px;
      line-height: 14px;
      color: rgba(2, 12, 18, 0.58);
      align-self: center;
      span:nth-child(2n) {
        color: rgba(2, 12, 18, 1);
        font-size: 14px;
      }
    }
  }
}
.headers {
  > div {
    color: rgba(2, 12, 18, 0.58);
    overflow: hidden;
    font-family: 'Golos Text', sans-serif;
    font-style: normal;
    font-weight: 600;
    font-size: 10px;
    line-height: 12px;
    letter-spacing: 0.05em;
    text-transform: uppercase;
  }
}
.SummonDateInput {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 8px;
  &-Count {
    line-height: 32px;
    margin-top: 16px;
    align-self: end;
  }
}
.MultiSelect__Form {
  ::v-deep > label {
    height: 39px;
    min-height: 39px;
    background: #e5edf5;
    border-radius: 4px 4px 0 0;
    background-blend-mode: multiply;
    border: none;
    border-bottom: 1px solid rgba(1, 72, 116, 0.18);
    padding: 0 8px !important;
    box-sizing: border-box;
    transition: 0.1s;
  }
}

.AddNewField {
  &-Group {
    will-change: width, opacity;
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.5rem 0;
    .RSelect {
      margin: 0;
      padding: 0;
      width: 0;
      opacity: 0;
      ::v-deep {
        .RSelect-Label {
          margin: 0;
          padding: 0;
        }
        .q-field__control {
        }
      }
    }
    .RButton {
      margin-left: -16px;
      width: 100%;
    }
  }
  &-Extend {
    .RSelect {
      width: 80%;
      opacity: 1;
      transition: width 0.5s;
    }
    .RButton {
      width: 20%;
      transition: width 0.5s;
    }
  }
}
</style>

<script lang="ts">
import { Component, Mixins, Prop, Ref, Watch } from 'vue-property-decorator';
import { Option } from '@/recruits/models';
import TaskButton from '@/mixins/TaskButton';
import { RecruitV3 } from '@/recruits/openapi/person-registry';
import OperationDialog from '@/components/common/operation-dialog/index.vue';
import { isArray, isString, get } from 'lodash';
import ProcessStarter from '@/mixins/ProcessStarter';
import Dialog from '@/mixins/Dialog';
import RDateTimeInput from '@/recruits/components/common/r-date-time-input.vue';
import RSelect from '@/recruits/components/common/r-select.vue';
import RSelectGroup from '@/recruits/components/common/r-select-group.vue';
import moment from 'moment';
import { SubpoenaRegistryApi } from '@/recruits/openapi/subpoena-service';
import SummonDate from '@/recruits/mixins/summon-date';
import ActionSelectGroupData, {
  groupDataModelInterface,
} from '@/recruits/mixins/action-select-group-data';
import { PushMessage, SocketMessage } from '@/mixins/CriptoProPlugin';
import { notifyError } from '@utils/notify';
import DataBlock from '@components/cards/statements/components/dataBlock.vue';

const initialFields = [
  'residenceAddress',
  'actualAddress',
  'residentialAddress',
];

interface IRow {
  index: number;
  name: string;
  reg: string;
  '14': boolean;
  '15': boolean;
}

const CALENDAR_DATE_FORMAT = 'YYYY/MM/DD';
const SUMMON_OBJECTIVES_DICT = 'MilitaryRegistrationUpdatingGoals';
const addressForSendDictionaryPath = 'ervuDictionaries/addressTypeDictionary';

@Component({
  components: {
    RDateTimeInput,
    RSelect,
    RSelectGroup,
    DataBlock,
  },
})
export default class Summon extends Mixins(
  TaskButton,
  Dialog,
  ProcessStarter,
  SummonDate,
  ActionSelectGroupData
) {
  @Prop({ default: () => false })
  readonly sign: boolean;

  @Prop({ default: '09:00' })
  readonly defaultTime: string;

  @Prop({ default: () => false })
  readonly disabled: boolean;

  @Prop({ default: () => '' })
  readonly startProcessId: string;

  @Prop({ default: () => 'Формирование повестки:' })
  readonly title: string;

  @Prop({ default: () => ({}) })
  declare readonly model: (string | RecruitV3)[] | RecruitV3;

  @Ref('dialog') operationDialog: OperationDialog;

  summonObjective: Option | null = null;
  deliveryMethod: Option | null = null;
  filterAny: [string] | null = null;
  filterNotAll: [string] | null = null;

  addFieldOption = false;
  newAddressType: Option | null = null;
  localRows: IRow[] = [];
  massCheckbox = {
    '14': false,
    '15': false,
  };

  @Watch('localRows', { deep: true })
  watchMassCheckBox(sendTypes: any[]) {
    const checkBox = sendTypes?.reduce(
      (acc, row) => {
        row?.['14'] && acc['14'].push('14');
        row?.['15'] && acc['15'].push('15');
        return acc;
      },
      { '14': [], '15': [] }
    );
    this.massCheckbox['14'] = checkBox['14']?.length === sendTypes?.length;
    this.massCheckbox['15'] = checkBox['15']?.length === sendTypes?.length;
  }

  get reasonsCalling(): groupDataModelInterface[] {
    const reasons = this.actionSelectGroupDataList(
      this.filterAny,
      this.filterNotAll
    );
    // При индивидуальном вызове, если рекрут не находиться в статусе предпоставлен
    // для 17-x летних граждан (флаг recruitmentEighteen = false),
    // или recruitmentConscriptionDisable = true (30+),
    // отображаем только причины из группы "Ведение воинского учета" (type = '2').
    if (
      !isArray(this.model) &&
      this.model.status !== '1' &&
      (this.model.stateRecruit.recruitmentConscriptionDisable ||
        !(this.model as RecruitV3).stateRecruit.recruitmentEighteen)
    )
      return reasons.filter((reason) => reason.type === '2');
    else return reasons;
  }

  get getAddFieldOption() {
    return this.addFieldOption;
  }

  get disabledTooltip() {
    return this.disabled ? 'Отбывает наказание в виде лишения свободы' : '';
  }

  created(): void {
    const tempModel: RecruitV3 | string = Array.isArray(this.model)
      ? this.model[0]
      : this.model;

    if (typeof tempModel !== 'string') {
      switch (tempModel.status) {
        case '1':
          this.filterAny = ['101'];
          break;
        case '1.2':
          this.filterNotAll = ['101'];
          break;
        case '14':
          this.filterNotAll = ['101'];
          break;
        case '15':
          this.filterNotAll = ['101'];
          break;
      }
    }
  }

  get rows() {
    return this.localRows;
  }

  get uniqIndex() {
    return this.rows[this.rows.length - 1]?.index
      ? this.rows[this.rows.length - 1].index + 1
      : this.rows.length;
  }

  setInputValue(index: number, field: string, value: boolean) {
    this.localRows.forEach(row => {
      if (row.index === index) {
        row[field as keyof Pick<IRow, '14' | '15'>] = value
      }
    });
  }

  setCheckboxColumn(field: string, value: boolean) {
    this.massCheckbox[field as '14' | '15'] = value;
    this.localRows.forEach((row) => {
      row[field as '14' | '15'] = value;
    });
  }

  get statusOptions(): Array<string> {
    return Object.keys(this.$store.getters[addressForSendDictionaryPath]);
  }

  get disableSubmitBtn() {
    return (
      !this.summonObjective ||
      !this.summonDate ||
      this.emptyTypeCheck.empty
    );
  }

  get emptyTypeCheck() {
    const filledFields = this.rows?.filter((el) => el?.['14'] || el?.['15'])
      ?.length;
    const empty = filledFields !== this.rows?.length || filledFields === 0;
    return {
      empty,
      message:
        'Выберите способ отправки по всем адресам направления повестки или удалите ненужный адрес',
    };
  }

  get getAddressTypesDictionary(): Record<string, string> {
    return this.$store.getters[addressForSendDictionaryPath] || {};
  }

  get getAddressTypesOptions() {
    return Object.keys(this.getAddressTypesDictionary).reduce((acc, el) => {
      if (
        !this.localRows.find((row) => row.name === el)?.name &&
        (this.model as RecruitV3).mainInfo?.addresses.find(
          (address) => address?.type === el
        )
      ) {
        acc.push({ value: el, label: this.getAddressTypesDictionary[el] });
      }
      return acc;
    }, [] as Record<string, string>[]);
  }

  addNewField() {
    if (this.newAddressType?.value) {
      if (
        this.rows.find(
          (el: IRow) =>
            this.newAddressType && el.name === this.newAddressType.value
        )?.name
      ) {
        notifyError('Поле уже имеется');
        return;
      }
      const addressField = (this.model as RecruitV3).mainInfo?.addresses.filter(
        (address) => address.type === this.newAddressType?.value
      );
      if (addressField?.length) {
        this.localRows.push({
          index: this.uniqIndex,
          reg: addressField[0].reg,
          name: this.newAddressType.value,
          '14': false,
          '15': false,
        });
        this.newAddressType = null;
      } else {
        notifyError('Нет адреса соответствующему выбранному типу');
      }
    }
  }

  deleteField(index: number) {
    this.localRows = this.localRows.filter((row) => row.index !== index);
  }

  deleteFields() {
    this.localRows = [];
  }

  get summonObjectiveName(): string {
    return this.summonObjective?.label || '';
  }

  get sub(): string {
    if (isArray(this.model))
      return `${this.$tc('Summon.selected', this.model.length)}`;
    return this.model.mainInfo.fullName || '';
  }

  get processMessage(): string {
    return this.$tc('Summon.process', this.personIds.length);
  }

  get resultMessage(): string {
    return this.$tc('Summon.result', this.personIds.length);
  }

  get personIds(): string[] {
    if (Array.isArray(this.model)) {
      return (
        this.model?.map((recruitOrId): string => {
          if (isString(recruitOrId)) return recruitOrId;
          return recruitOrId.id;
        }) || []
      );
    }
    return [this.model.id];
  }

  get formModel() {
    const sendData = this.rows.reduce((acc: any, row: IRow) => {
      const sendCode = [];
      row['14'] && sendCode.push('14');
      row['15'] && sendCode.push('15');
      sendCode?.[0] && acc.push({ sendCode, addressType: row.name });
      return acc;
    }, []);

    return {
      id: this.startProcessId || null,
      actionType: 'generateOrder',
      personIds: this.personIds,
      summonObjective: this.summonObjective?.value,
      summonDate: this.summonDate,
      sendInfo: [
        {
          personId: this.personIds[0],
          sendData,
        },
      ],
    };
  }

  get dateIsAvailable(): boolean {
    return this.countRecruitOfDay <= 50;
  }

  /**
   * от 0 до 20 зеленым
   * от 21 до 40 желтым
   * от 41 до 50 оранжевым
   * более 50 красным
   * @param num
   */
  getbookingColor(num: number): string {
    if (num > 50) return 'red';
    if (num > 40) return 'orange';
    if (num > 20) return 'yellow';
    return 'green';
  }

  countRecruitOfDay = 0;
  countRecruitOfHour = 0;

  async checkDate(summonDate: Date | null): Promise<void> {
    if (!summonDate) return;
    const dateTime = moment(summonDate).format();
    const { data } = await new SubpoenaRegistryApi().getCountRecruitForDate(
      dateTime
    );
    this.countRecruitOfDay = data.countRecruitOfDay || 0;
    this.countRecruitOfHour = data.countRecruitOfHour || 0;
  }

  @Watch('summonDate')
  onDateChange(summonDate: Date | null): void {
    this.checkDate(summonDate);
  }

  isNextYearAvailable(isCurrentDate: string): boolean {
    return moment(isCurrentDate).year() <= moment().year() + 1;
  }

  async action(): Promise<void> {
    if (!this.isDateAndTimeValid()) return;
    // FIXME когда понадобиться эта же проверка на листы вынести в миксин summonDate
    if (
      !this.isNextYearAvailable(
        this.momentSummonDate.format(CALENDAR_DATE_FORMAT)
      )
    ) {
      notifyError(
        'Вы можете выбрать дату вызова только до конца следующего года'
      );
      return;
    }
    this.operationDialog.toProcess();

    const option = `wfActions/processes/${
      this.startProcessId ? 'submitForm' : 'dispatchProcess'
    }`;
    const payload = this.startProcessId
      ? {
          taskId: this.userTask.taskId,
          traceId: this.taskProcess.traceId,
          processKey: 'milBaseRouteProcess',
          formModel: this.formModel,
        }
      : {
          processKey: 'milBaseRouteProcess',
          data: this.formModel,
        };

    try {
      const { traceId } = await this.$store.dispatch(option, payload);

      this.registerListener((message, removeListener) => {
        if (traceId !== message.traceId) return;
        if (
          get(message, 'body.type') === 'newTraceId' &&
          (message as SocketMessage<PushMessage>).body.newTraceId
        ) {
          this.newTraceIdListener(
            (message as SocketMessage<Required<PushMessage>>).body.newTraceId
          );
          removeListener();
        }
        if (message.body.type === 'finish') {
          this.operationDialog.toResult();
          removeListener();
        }
      });
    } catch (error) {
      this.operationDialog.toResult();
      console.error(error);
    }
  }

  newTraceIdListener(traceId: string) {
    this.registerListener((message, removeListener) => {
      if (traceId !== message.traceId) return;
      if (get(message, 'body.type') === 'finish') {
        this.operationDialog.toResult();
        removeListener();
      }
    });
  }

  finish(): void {
    this.$emit('done');
  }

  async initReasonsDictionary(): Promise<void> {
    await this.$store.dispatch(
      'registryService/referenceBooks/initReferenceBooks',
      [
        {
          id: SUMMON_OBJECTIVES_DICT,
        },
      ]
    );
  }

  mounted(): void {
    this.initReasonsDictionary();
  }

  open(): void {
    if (this.disable || this.disabled) return;
    if (!this.localRows.length) {
      (this.model as RecruitV3).mainInfo?.addresses.forEach((address) => {
        if (initialFields.includes(address.type)) {
          this.localRows.push({
            index: this.uniqIndex,
            reg: address.reg,
            name: address.type,
            '14': false,
            '15': false,
          });
        }
      });
    }
    this.opened = true;
    this.$emit('open');
  }

  close(): void {
    this.addFieldOption = false;
    this.opened = false;
    this.operationDialog.reset();
    this.$emit('close');
  }
}
</script>
