<template>
  <div class="register-new-recruit">
    <block-loader type="QBtn" :loading="loading">
      <r-btn
        dense
        :label="label"
        icon="pgs-roll"
        :disable="disable"
        @click="buttonOptions.hideDialog ? action() : open()"
        no-wrap
      />
    </block-loader>
    <operation-dialog
      persistent
      ref="dialog"
      :title="title"
      width="750px"
      :sub="sub"
      process-key="milBaseRouteProcess"
      v-model="opened"
    >
      <div class="row q-col-gutter-md">
        <div class="col-12">
          <r-select-group
            v-if="isFieldHidden('summonObjective')"
            label="Цель вызова в военкомат"
            dense
            options-dense
            v-model="summonObjective"
            :options="summonOptions"
            :string-options="actionSelectGroupDataList(filterAny, filterNotAll)"
            :display-value="summonObjectiveName"
            :disable="isFieldDisabled('summonObjective')"
            :hide-selected="!isFieldDisabled('summonObjective')"
          >
          </r-select-group>
        </div>
        <div class="col-12 SummonDateInput">
          <r-date-time-input
            v-if="isFieldHidden('summonDate')"
            label="Дата и время явки"
            :emit-format="emitFormat"
            :date-options="isDateAvailable"
            :time-options="isTimeAvailable"
            :default-year-month="defaultYearMonth"
            :default-time="defaultTime"
            :disable="isFieldDisabled('summonDate')"
            v-model="summonDate"
          />
          <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="full-width 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
                  :disabled="isFieldDisabled('sendInfo')"
                  class="LabelSelect-Select"
                  id="meet"
                  size="sm"
                  type="checkbox"
                  :value="massCheckbox.meet"
                  @input="
                    (v) =>
                      !isFieldDisabled('sendInfo') &&
                      setCheckboxColumn('meet', v)
                  "
                />Нарочно
              </div>
              <div class="text-center">
                <q-checkbox
                  :disabled="isFieldDisabled('sendInfo')"
                  class="LabelSelect-Select"
                  id="mail"
                  size="sm"
                  type="checkbox"
                  :value="massCheckbox.mail"
                  @input="
                    (v) =>
                      !isFieldDisabled('sendInfo') &&
                      setCheckboxColumn('mail', v)
                  "
                />Письмо
              </div>
              <div class="flex flex-center cursor-pointer">
                <q-icon
                  :disabled="isFieldDisabled('sendInfo')"
                  color="negative"
                  size="19px"
                  name="pgs-delete"
                  @click="!isFieldDisabled('sendInfo') && 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>{{ getAddressCurrentType(props.row.name) }}</span>
                      </div>
                    </div>
                    <div class="flex justify-center">
                      <q-checkbox
                        class="LabelSelect-Select"
                        :id="props.row.name"
                        type="checkbox"
                        :value="props.row.meet"
                        @input="
                          (v) => setInputValue(props.row.index, 'meet', v)
                        "
                        :disabled="isFieldDisabled('sendInfo')"
                      />
                    </div>
                    <div class="flex justify-center">
                      <q-checkbox
                        class="LabelSelect-Select"
                        :id="props.row.name"
                        type="checkbox"
                        :value="props.row.mail"
                        @input="
                          (v) => setInputValue(props.row.index, 'mail', v)
                        "
                        :disabled="isFieldDisabled('sendInfo')"
                      />
                    </div>
                    <div class="flex flex-center cursor-pointer">
                      <q-icon
                        color="negative"
                        size="25px"
                        name="pgs-delete"
                        @click="
                          !isFieldDisabled('sendInfo') &&
                            deleteField(props.row.index)
                        "
                        :disabled="isFieldDisabled('sendInfo')"
                      />
                    </div>
                  </div>
                </template>
              </q-table>
            </div>
            <div
              v-show="!isFieldDisabled('sendInfo')"
              :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 ||
            !get(summonObjective, 'value') ||
            !rows[0] ||
            !summonDate ||
            !dateIsAvailable
          "
          @click="action"
        />
      </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 {
  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;
  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;
      }
    }
  }
}
.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;
  }
}

.Field-Delete {
  align-items: center;
  cursor: pointer;
}
.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;
  }
}
.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 { RecruitV4 } from '@/recruits/openapi/person-registry';
import {
  SubpoenaOneResponseV3,
  SubpoenaRegistryApi,
} from '@/recruits/openapi/subpoena-service';
import { AddressArrayDeliveryV1 } from '@/recruits/openapi/summon-list-service';
import OperationDialog from '@/components/common/operation-dialog/index.vue';
import { get, isArray, isString } 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 moment from 'moment';
import {
  getNWorkDaysSince,
  HOLYDAYS,
  getDictionaryFormatedToOptions,
} from '@/recruits/utils';
import SummonDate from '@/recruits/mixins/summon-date';
import ActionSelectGroupData from '@/recruits/mixins/action-select-group-data';
import RSelectGroup from '@/recruits/components/common/r-select-group.vue';
import { notifyError } from '@utils/notify';

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

interface IRow {
  index: number;
  name: string;
  meet: boolean;
  mail: boolean;
}

interface IModelObject extends SubpoenaOneResponseV3 {
  recruit: RecruitV4;
}

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

interface ButtonOptions {
  fields?: {
    summonObjective?: string; // из повестки reason
    summonDate?: string; // из повестки visitDate (2023-09-13T17:00:00.000Z)
    sendInfo?: AddressArrayDeliveryV1[]; // из повестки deliveryMethod
  };
  startStatus: string;
  editableFields?: string[]; // поля которые можно редактировать
  hideFields?: string[]; // поля, которые нужно скрывать
  hideDialog?: boolean; // если надо скрыть модальное окно
}

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

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

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

  @Prop({ default: () => 'YYYY-MM-DDTHH:mm:ss.SSSZ' })
  readonly emitFormat: string;

  @Prop({ default: () => ({}) })
  declare readonly model: IModelObject | RecruitV4;

  @Ref('dialog') operationDialog: OperationDialog;

  summonDate: string | null = null;
  summonObjective: Option | null = null;
  sendInfo: AddressArrayDeliveryV1[] | null = null;
  filterAny: [string] | null = null;
  filterNotAll: [string] | null = null;
  addFieldOption = false;
  localRows: IRow[] = [];
  newAddressType: Option | null = null;
  massCheckbox = {
    meet: false,
    mail: false,
  };

  get getAddFieldOption() {
    return this.addFieldOption;
  }

  get rows() {
    return this.localRows;
  }

  get startStatus(): string | undefined {
    return this.buttonOptions.startStatus;
  }

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

  get recruitInfo(): RecruitV4 {
    const model = this.model;
    if (model && 'recruit' in model) {
      return model.recruit;
    } else {
      return model;
    }
  }

  get summonOptions(): { value: string; label: string }[] {
    // Необходимо для определения целей вызова для разных статусов
    const statuses: Record<string, string[]> = {
      '1': ['101'],
      '1.2': [
        '102',
        '103',
        '104',
        '105',
        '106',
        '107',
        '201',
        '202',
        '203',
        '204',
        '205',
        '206',
        '207',
        '208',
        '209',
        '210',
        '211',
      ],
      '15': [
        '201',
        '202',
        '203',
        '204',
        '205',
        '206',
        '207',
        '208',
        '209',
        '210',
        '211',
      ],
    };

    const dict: Record<string, string> =
      this.$store.getters[
        'ervuDictionaries/militaryRegistrationUpdatingGoalsDictionary'
      ] || {};

    const statusOptions = getDictionaryFormatedToOptions(dict);

    const tempModel = this.recruitInfo;

    if (isString(tempModel)) {
      return statusOptions;
    }

    // Если со стороны процесса приходит прежний статус, то использовать его.
    const status = this.startStatus || tempModel?.status;

    if (status) {
      switch (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;
      }
    }
    if (!statuses[status]) return statusOptions;
    return statusOptions.filter((element) => {
      return statuses[status].includes(element?.value);
    });
  }

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

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

  setInputValue(index: number, field: string, value: boolean) {
    if (!this.isFieldDisabled('sendInfo')) {
      this.localRows[index][field as keyof Pick<IRow, 'meet' | 'mail'>] = value;
    }
  }

  deleteFields() {
    if (!this.isFieldDisabled('sendInfo')) {
      this.localRows.splice(0, this.rows.length);
    }
  }

  setCheckboxColumn(field: string, value: boolean) {
    this.massCheckbox[field as keyof Pick<IRow, 'meet' | 'mail'>] = value;
    this.localRows.forEach((row) => {
      row[field as keyof Pick<IRow, 'meet' | 'mail'>] = value;
    });
  }

  getAddressCurrentType(type: string) {
    return (
      (this.recruitInfo as
        | RecruitV4
        | IModelObject['recruit'])?.mainInfo?.addresses.find(
        (address) => address?.type === type
      )?.reg || ''
    );
  }

  addNewField() {
    if (this.newAddressType?.value) {
      if (
        this.rows.find(
          (el: IRow) =>
            this.newAddressType && el.name === this.newAddressType.value
        )?.name
      ) {
        notifyError('Поле уже имеется');
        return;
      }
      this.localRows.push({
        index: this.rows.length,
        name: this.newAddressType.value,
        meet: false,
        mail: false,
      });
      this.newAddressType = null;
    }
  }

  deleteField(index: number) {
    this.localRows.splice(index, 1);
  }

  get sub(): string {
    if (isArray(this.model))
      return `${this.$tc('Summon.selected', this.model.length)}`;
    return (
      (this.recruitInfo as RecruitV4 | IModelObject['recruit']).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 buttonOptions(): ButtonOptions {
    return get(
      this.userTask,
      ['outData', 'options', this.buttonSettings.id],
      {}
    );
  }

  getDefaultOption(options: Option[], defaultValue?: string): Option {
    const summonObjective = options.find(({ value }) => value === defaultValue);
    return (
      summonObjective || {
        value: '',
        label: '',
      }
    );
  }

  getDefaultDate(defaultDate?: string): string | null {
    if (!defaultDate) return null;
    return moment(defaultDate).format(this.emitFormat);
  }

  isFieldDisabled(fieldName: string): boolean {
    return !this.buttonOptions.editableFields?.includes(fieldName);
  }

  isFieldHidden(fieldName: string): boolean {
    return !this.buttonOptions.hideFields?.includes(fieldName);
  }

  get personIds(): string[] {
    return [this.recruitInfo.id];
  }

  get formModel() {
    return {
      id: this.buttonSettings.id,
      personIds: this.personIds,
      summonObjective: this.summonObjective?.value,
      summonDate: this.summonDate,
    };
  }

  get threeWorkDaysSinceNow(): string[] {
    let disabledDates = getNWorkDaysSince(0, new Date());
    if (
      this.buttonOptions.fields?.summonDate &&
      disabledDates.includes(
        moment(this.buttonOptions.fields?.summonDate).format('YYYY/MM/DD')
      )
    ) {
      disabledDates = disabledDates.filter(
        (e) =>
          e !==
          moment(this.buttonOptions.fields?.summonDate).format('YYYY/MM/DD')
      );
    }
    return disabledDates;
  }

  isDateAvailable(date: string): boolean {
    const now = moment().format('YYYY/MM/DD');
    if (this.buttonOptions.fields?.summonDate) {
      if (date < moment(this.buttonOptions.fields?.summonDate).format('YYYY/MM/DD') || HOLYDAYS.includes(moment(date).get('day'))) return false;
    } else {
      if (date < now || HOLYDAYS.includes(moment(date).get('day'))) return false;
    }
    return !this.threeWorkDaysSinceNow.includes(date);
  }

  get defaultYearMonth(): string {
    let date = moment();
    do {
      date = date.add(1, 'day');
    } while (this.isDateAvailable(date.format('YYYY/MM/DD')));
    return date.format('YYYY/MM');
  }

  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.isFieldDisabled('summonDate')) {
      if (!this.isDateAndTimeValid()) return;
      // FIXME когда понадобиться эта же проверка на листы вынести в миксин summonDate
      if (
        !this.isNextYearAvailable(
          this.momentSummonDate.format(CALENDAR_DATE_FORMAT)
        )
      ) {
        notifyError(
          'Вы можете выбрать дату вызова только до конца следующего года'
        );
        return;
      }
    }
    this.operationDialog.toProcess();
    const sendData = this.rows.reduce(
      (acc: AddressArrayDeliveryV1[], row: IRow) => {
        const sendCode = [];
        row.meet && sendCode.push('14');
        row.mail && sendCode.push('15');
        acc.push({ sendCode, addressType: row.name });
        return acc;
      },
      []
    );
    try {
      const taskId = this.userTask.taskId;
      const traceId = this.taskProcess.traceId;
      await this.$store.dispatch('wfActions/processes/submitForm', {
        formModel: {
          ...this.formModel,
          sendInfo: [
            {
              personId: this.personIds[0],
              sendData,
            },
          ],
        },
        taskId,
        traceId,
      });

      this.registerListener((message, removeListener) => {
        if (traceId !== message.traceId) return;
        if (message.body.type === 'finish') {
          this.operationDialog.toResult();
          removeListener();
        }
      });
    } catch (error) {
      this.operationDialog.toResult();
      console.error(error);
    }
  }

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

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

  defaultInitialFields(): IRow[] {
    if (!this.localRows.length) {
      return (this.model as RecruitV4).mainInfo?.addresses.reduce<IRow[]>(
        (acc, address, index) => {
          if (initialFields.includes(address.type)) {
            acc.push({
              index,
              name: address.type,
              meet: false,
              mail: false,
            });
          }
          return acc;
        }, []);
    } else {
      return [];
    }
  }

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

  open(): void {
    if (this.disable) return;
    this.opened = true;
    this.$emit('open');
    this.summonObjective = this.getDefaultOption(
      this.summonOptions,
      this.buttonOptions?.fields?.summonObjective
    );

    this.sendInfo = this.buttonOptions?.fields?.sendInfo || null;

    if (this.sendInfo?.length) {
      this.localRows = this.sendInfo.reduce<IRow[]>(
        (acc, el: AddressArrayDeliveryV1, index) => {
          const meet = el.sendCode?.includes('14') || false;
          const mail = el.sendCode?.includes('15') || false;
          el.addressType && acc.push({ index, name: el.addressType, meet, mail });
          return acc;
        },
        []
      );
    } else {
      this.localRows = this.defaultInitialFields();
    }
    this.summonDate = this.getDefaultDate(
      this.buttonOptions.fields?.summonDate
    );
  }

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