<template>
  <q-dialog
    ref="dialog"
    persistent
    v-bind="$attrs"
    v-on="$listeners"
    @before-hide="clear"
  >
    <q-card
      class="no-shadow q-pa-md create-card"
      :style="!$q.screen.lt.md ? 'min-width: 600px' : ''"
    >
      <q-card-section>
        <close-button class="float-right" />
        <div class="text-h6">
          {{ $t('reports.creating') }}
        </div>
      </q-card-section>

      <q-card-section class="q-pb-md">
        <q-form ref="form" class="row q-col-gutter-md" greedy @submit="submit">
          <div class="col-md-12 col-sm-12 q-gutter-y-md">
            <base-label-value>
              <template #label>
                {{ $t('reports.columns.reportName') }}
              </template>
              <template #value>
                <select-base
                  :options="[baseReport]"
                  :value="baseReport"
                  option-label="name"
                  option-value="id"
                  disable
                  :title="baseReport && baseReport.name"
                />
              </template>
            </base-label-value>
            <base-label-value v-for="(option, i) in options" :key="i + 123456">
              <template #label>
                {{ $t(option.label) }}
              </template>
              <template #value>
                <component
                  v-bind="mapLinked(option.props, option.linked)"
                  :is="option.component"
                  v-model="result[option.name]"
                  :style="option.style"
                  v-on="option.listeners"
                  @isAllSelected="e => setAllSelected(e, option.name)"
                  @proxyOrganisations="addProxyOrganisation" 
                  @department="addProxyDepartment" 
                  :role="reportAccessRole"
                  :isSubDepartment="baseReport && baseReport.isSubDepartment"
                />
              </template>
            </base-label-value>
          </div>
          <!-- 

            Скрываем пока не починим периоды 

            <div class="col-md-6 col-sm-12 q-gutter-y-md">
            <base-label-value>
              <template #label>
                {{ $t('reports.auto') }}
              </template>
              <template #value>
                <q-checkbox v-model="auto" style="margin: -8px 0 0 -10px" />
              </template>
            </base-label-value>
            <template v-if="auto">
              <base-label-value v-for="(option, i) in autoOptions" :key="i">
                <template #label>
                  {{ $t(option.label) }}
                </template>
                <template #value>
                  <component
                    v-bind="option.props"
                    :is="option.component"
                    v-model="result[option.name]"
                    :style="option.style"
                    v-on="option.listeners"
                  />
                </template>
              </base-label-value>
            </template>
          </div> -->
        </q-form>
      </q-card-section>
      <q-card-actions align="right">
        <q-btn
          :label="$t('reports.create')"
          unelevated
          color="primary"
          @click="$refs.form.submit()"
        />
      </q-card-actions>
    </q-card>
  </q-dialog>
</template>

<script lang="ts">
/* eslint-disable @typescript-eslint/ban-ts-comment */
import { Component, Mixins, Vue, Prop } from 'vue-property-decorator'
import { oidcClientComputed } from '@state/modules/oidc-client'
import { set, map, get, isEmpty, merge } from 'lodash'
import { convertDateFormat, doMathWithDate } from '@utils/format-date';
import { DateFormat } from '@constants/utils/format-date';
import { QDialog } from 'quasar'
import { getNameStrings, mapOptionsResults } from '@components/reports/utils'
import SelectAccounts from '../components/select-accounts.vue'
import SelectRegions from '../components/select-regions.vue'
import SelectOrganizations from '../components/select-organizations.vue'
import SelectServices from '../components/select-services.vue'
import SelectBase from '../components/select-base.vue'
import XDatetimeRange from '../components/x-datetime-range.vue'
import SelectEvery from '../components/select-every.vue'
import CloseButton from '../components/close-button.vue'
import { USER_SCOPES } from '@constants/entities/Scope'
import { Region, RegionApi, DepartmentApi } from '@openapi/idm'
import {
  OrganizationApi,
  Organization,
  Department,
} from '@openapi/registry-service';
import findQueryDefinitionId, {
  BaseReport,
  BaseReportCreateColumn,
  Report,
} from '../reports'
import { DocumentApi } from '@openapi/document-registry';
import { notifyError } from '@utils/notify';
import { getAuthorizationType, AUTH_LOCAL } from '@/utils/save-profile-info'

const documentApi = new DocumentApi();
const departmentApi = new DepartmentApi();
const organizationApi = new OrganizationApi();

const reports = Vue.extend({
  computed: {
    ...oidcClientComputed,
  },
});

interface DepartmentWithParent extends Department {
  parent: Organization;
}

@Component({
  components: {
    SelectAccounts,
    SelectRegions,
    SelectOrganizations,
    SelectServices,
    SelectBase,
    SelectEvery,
    XDatetimeRange,
    CloseButton,
  },
})
export default class ReportCreate extends Mixins(reports) {
  @Prop() protected baseReport!: BaseReport;
  @Prop() protected defaultParams: ReportParams;

  protected reportAccessRole: reportAccessScope | null = null;
  protected currentUserRegion: Region | null = null;
  protected currentUserOrganization: Organization | null = null;
  USER_SCOPES = USER_SCOPES;

  protected async submit() {
    if ( this.reportAccessRole === reportAccessScope.observerRF
      && this.baseReport.id !== '20' 
      && !(this.result.regions?.length 
        || this.result.services?.length 
        || this.result.organizations?.length)) return
    this.save();
    (this.$refs.dialog as QDialog).hide();
  }

  protected get notAuto() {
    return !this.auto;
  }

  protected mapLinked(
    props: BaseReportCreateColumn['props'] = {},
    linked?: BaseReportCreateColumn['linked']
  ) {
    if (!linked || !this.visibleColums.length) {
      return props
    }
    // fixme
    map(linked, ({ column, default: def, value }, key) => {
      if (this.visibleColums.includes(column)) {
        if (value === undefined) return;
        if (value.startsWith('!!')) {
          value = value.slice(2);
          props[key] = !!get(this, value);
        } else if (value.startsWith('!')) {
          value = value.slice(1)
          props[key] = !get(this, value);
        } else {
          props[key] = get(this, value);
        }
      } else {
        props[key] = def;
      }
    })

    return props;
  }

  protected columns: Array<BaseReportCreateColumn> = [
    {
      field: 'params.regions',
      label: 'reports.columns.region',
      name: 'regions',
      component: 'select-regions',
      props: {
        multiple: true,
        required: true,
      },
      fieldMap: ['id', 'code', 'name'],
    },
    {
      field: 'params.organizations',
      label: 'reports.columns.organization',
      name: 'organizations',
      component: 'select-organizations',
      props: {
        multiple: true,
      },
      linked: {
        regions: {
          column: 'regions',
          default: 'all',
          value: 'result.regions',
        },
        required: {
          column: 'regions',
          default: true,
        },
      },
      fieldMap: ['id', 'fullname', 'shortname'],
    },
    {
      field: 'params.services',
      label: 'reports.columns.serviceName',
      name: 'services',
      component: 'select-services',
      props: {
        multiple: true,
      },
      linked: {
        organizations: {
          column: 'organizations',
          default: 'all',
          value: 'result.organizations',
        },
        required: {
          column: 'organizations',
          default: true,
        },
      },
      fieldMap: ['id', 'targetId', 'fullName', 'shortName', 'shortNameStat'],
    },
    {
      field: 'params.accounts',
      label: 'reports.columns.accounts',
      name: 'accounts',
      component: 'select-accounts',
      props: {
        multiple: true,
      },
      linked: {
        organizations: {
          column: 'organizations',
          default: 'all',
          value: 'result.organizations',
        },
      },
      fieldMap: {
        id: 'id',
        fullname: 'fullname',
        shortname: 'shortname',
        firstname: 'person.firstname',
        middlename: 'person.middlename',
        surname: 'person.surname',
      },
    },
    {
      field: 'comment',
      label: 'reports.columns.comment',
      name: 'comment',
      component: 'q-input',
      props: {
        dense: true,
        filled: true,
      },
    },
    {
      field: 'params.range',
      label: 'reports.columns.range',
      name: 'range',
      component: 'x-datetime-range',
      props: {
        dense: true,
        filled: true,
        default: {
          to: convertDateFormat(new Date(), '', DateFormat.backend),
          from: convertDateFormat(
            doMathWithDate('subMonths', new Date(), 1),
            '',
            DateFormat.backend,
          ),
        },
      },
      linked: {
        disable: {
          column: 'every',
          default: false,
          value: 'auto',
        },
        required: {
          column: 'every',
          default: true,
          value: 'notAuto',
        },
      },
      style: 'display: flex; flex-wrap: nowrap',
    },
    {
      auto: true,
      field: 'auto.startDate',
      label: 'reports.columns.startDateFirst',
      name: 'startDate',
      component: 'x-date-input',
      props: {
        dense: true,
        filled: true,
      },
      style: 'width: 100%',
    },
    {
      auto: true,
      field: 'auto.last',
      label: 'reports.columns.last',
      name: 'last',
      props: {
        emitArray: false,
        required: true,
      },
      component: 'select-every',
    },
    {
      auto: true,
      field: 'auto.every',
      label: 'reports.columns.last', // 'reports.columns.everu'
      name: 'every',
      props: {
        emitArray: false,
        required: true,
      },
      component: 'select-every',
    },
  ];

  protected get mappedColumns() {
    let cols: any = [];
    const baseCreate = this.baseReport?.columns?.create;
    const observerRFCreate = this.baseReport?.columns?.observerRFCreate;
    const observerRegionCreate = this.baseReport?.columns?.observerRegionCreate;
    const observerOrganizationCreate = this.baseReport?.columns
      ?.observerOrganizationCreate;
    switch (this.reportAccessRole) {
      case reportAccessScope.observerRF:
        cols = this.reduceColumn(observerRFCreate || baseCreate);
        break;
      case reportAccessScope.observerRegion:
        cols = this.reduceColumn(observerRegionCreate || baseCreate);
        break;
      case reportAccessScope.observerOrganization:
        cols = this.reduceColumn(observerOrganizationCreate || baseCreate);
        break;
      default:
        cols = this.reduceColumn(baseCreate);
        break;
    }

    if (isEmpty(cols)) {
      return this.columns
    } else {
      return this.columns.map(
        (col) =>
          cols && (col.name in cols ? merge({}, col, cols[col.name]) : col)
      );
    }
  }

  protected reduceColumn(
    cols: Array<string | BaseReportCreateColumn<string>> | undefined
  ): BaseReportCreateColumn[] {
    if (!cols) return []
    return cols
      .filter(
        (col: string | BaseReportCreateColumn): col is BaseReportCreateColumn =>
          typeof col !== 'string'
      )
      .reduce((o, v) => {
        o[v.name] = v
        return o
      }, Object.create(null));
  }

  protected result: any = {};
  protected resultAll: { [key: string]: boolean } = {};
  protected auto = false;
  protected proxyOrganisation: {}[] = [];
  protected proxyDepartment: {}[] = [];

  protected get visibleColums() {
    return (
      this.baseReport?.columns?.create?.map((col) =>
        typeof col === 'string' ? col : col.name,
      ) || []
    );
  }

  protected get options() {
    return this.mappedColumns.filter(({ name, auto, props }) => {
      const { required, hidden } = props;
      return !auto && !hidden && (required || this.visibleColums.includes(name))
    })
  }

  protected get optionsWithHidden() {
    return this.mappedColumns.filter(
    ({ name, auto, props }) => {
      const { required } = props;
      return !auto && (required || this.visibleColums.includes(name))
    },
    )
  }

  protected get autoOptions() {
    return this.mappedColumns.filter(
      ({ name, props, auto }) => {
        const { required } = props
        return auto && (required || this.visibleColums.includes(name))
    })
  }

  protected async created() {
    this.clear();
    this.setRole();
    if (!isEmpty(this.defaultParams)) {
      this.setDefault(this.defaultParams);
    }
  }

  protected clear() {
    this.result = this.options.reduce((o, { name }) => {
      o[name] = null
      return o
    }, Object.create(null))
    if (this.currentUserRegion) {
      this.result.regions = [this.currentUserRegion]
    }
    if (this.currentUserOrganization) {
      this.result.organizations = [this.currentUserOrganization]
    }
  }

  protected async setRole(): Promise<void> {
    if (
      this.$AC.haveOneOfScope([
        USER_SCOPES.RF_OBSERVER_SCOPE,
        USER_SCOPES.FED_STAT_OBSERVER,
      ])
    ) {
      this.reportAccessRole = reportAccessScope.observerRF;
      return;
    }
    if (
      this.$AC.haveOneOfScope([
        USER_SCOPES.REGION_OBSERVER,
        USER_SCOPES.REGION_ADMIN,
        USER_SCOPES.REG_STAT_OBSERVER,
      ])
    ) {
      this.reportAccessRole = reportAccessScope.observerRegion;
      await this.setDefaultRegion();
      this.result.regions = [this.currentUserRegion];
      return;
    }
    if (
      this.$AC.haveOneOfScope([
        USER_SCOPES.ORGANIZATION_ADMIN,
        USER_SCOPES.ORG_STAT_OBSERVER,
        USER_SCOPES.SIGNED_SPECIALIST,
      ])
    ) {
      this.reportAccessRole = reportAccessScope.observerOrganization;
      await this.setDefaultRegion();
      this.result.regions = [this.currentUserRegion];
      this.result.organizations = [this.currentUserOrganization];
    }
  }

  protected async setDefaultRegion() {
    const { currentUser } = this;
    let currentUserOrganization = null;
    let currentUserRegionId;
    let currentUserDepartment = null;
    let parentOrganization = null;
    const authType = getAuthorizationType(currentUser);
    if (authType === AUTH_LOCAL || !!currentUser.ogrn) {
      try {
        currentUserOrganization = await organizationApi
          .getOrganization(currentUser.domain_id)
          .then(({ data }) => data);
        currentUserRegionId = currentUserOrganization?.regionId;
      } catch (e) {
        currentUserDepartment = await departmentApi
          .getDepartment(currentUser.domain_id, 'parent')
          .then(({ data }) => data);

        parentOrganization = await organizationApi
          .getOrganization(
            (currentUserDepartment as DepartmentWithParent)?.parent.id
          )
          .then(({ data }) => data);
        currentUserRegionId = parentOrganization.regionId;
      }
    } else {
      currentUserOrganization = null;
      currentUserRegionId = currentUser.domain_id;
    }

    const currentUserRegion: Region = await new RegionApi()
      .getRegion(currentUserRegionId)
      .then(({ data }) => data);

    if (currentUserRegion) {
      this.currentUserRegion = currentUserRegion;
    }
    if (currentUserOrganization) {
      this.currentUserOrganization = currentUserOrganization;
    } else if (parentOrganization) {
      this.currentUserOrganization = parentOrganization;
    }
  }

  protected setDefault(params: ReportParams): void {
    if (params.regions?.length) {
      this.result.regions = params.regions;
    }
    if (params.organizations?.length) {
      this.result.organizations = params.organizations;
    }
    if (params.services?.length) {
      const servicesWithShortNameStat = params.services.filter(
        (service) => service.shortNameStat
      );
      this.result.services = servicesWithShortNameStat;
    }
  }

  protected async save() {
    let { optionsWithHidden, currentUser, auto } = this;
    const report: Report = Object.create(null);

    report.parentId = this.baseReport.id;
    report.name = this.baseReport.name;
    if (auto) {
      report.auto = {
        enabled: true,
      };
      optionsWithHidden = optionsWithHidden.concat(this.autoOptions);
    }

    if (currentUser) {
      // eslint-disable-next-line camelcase,@typescript-eslint/naming-convention
      const { given_name, middle_name, family_name, sub, domain_id } = currentUser;
      report.creator = {
        id: sub,
        organizationId: domain_id,
        firstname: given_name,
        middlename: middle_name,
        surname: family_name,
        ...getNameStrings(given_name, middle_name, family_name),
      }
    }
    Object.assign(report, mapOptionsResults(optionsWithHidden, this.result));
    Object.assign(report.params, this.resultAll);

    if (report.parentId === '11') {
      if (report.params.allRegions) {
        report.params.regions = [];
      }
      if (report.params.allOrganizations) {
        report.params.organizations = [];
      }
      // TODO: Нужно разобраться почему задуманная логика не работает с отчетом 11 (во всяком случае с услугами)
      // if (report.params.allServices) {
      //   report.params.services = [];
      // }
    }

    if (report.auto) {
      report.auto.enabled = true
      delete report.params.range
    }

    const queryDefinitionId =
      this.reportAccessRole &&
      findQueryDefinitionId(report, this.reportAccessRole);

    if (!queryDefinitionId) {
      notifyError('queryDefinitionId не найден');
      return;
    }

    report.queryDefinitionId = queryDefinitionId;

    report.number = +convertDateFormat(new Date(), '', DateFormat.dateNumber)

    try {
      const save = documentApi
        .createDocument('StatReport', [report as any]) // TODO: ERROR! Type 'Report' is not assignable to type 'Document'.
        .then(({ data: response }) =>
          set(report, 'id', get(response, 'data.objectIds[0]'))
        );

      this.$emit('creating', save)
      await save
      this.clear()
    } catch (e) {
      notifyError(e.message.toString());
    }
  }

  setAllSelected(value: boolean, name: string) {
    const capitalizedName = name.slice(0, 1).toUpperCase() + name.slice(1);
    this.resultAll[`all${capitalizedName}`] = !!value;
  }

  addProxyOrganisation(org: Organization[]) {
    this.proxyOrganisation = org;
  }

  addProxyDepartment(org: Organization[]) {
    this.proxyDepartment = org;
  }
}

export enum reportAccessScope {
  observerRF = 'observerRF',
  observerRegion = 'observerRegion',
  observerOrganization = 'observerOrganization',
  // observerDepartment = 'observerDepartment',
}

type ReportParams = {
  regions?: Record<string, string>[];
  organizations?: Record<string, string>[];
  services?: Record<string, string>[];
}

</script>
<style lang="sass">
.create-card
  margin-top: 100px,
  align-self: flex-start
</style>
