import { checkExistedLocalization } from '@utils/localizations';
import { RegionApi } from '@openapi/idm';

import { DateFormat } from '@constants/utils/format-date';
import { WorkCalendarForDomain } from './WorkCalendarForDomain';
import {
  convertDateFromBackendFormat,
  getDifferenceBetweenDates,
  parseDateFromString,
  toTimestamp,
  isCorrectDate
} from '@utils/format-date';

const regionApi = new RegionApi();

export async function formatResponse(response: {}[], domain: string, getDictionary: (val: string) => {}): Promise<string> {
  const regions = await regionApi
    .searchRegions()
    .then(({ data }) => data)
    .catch(() => {
      throw new Error('[components][statements][index][searchRegions]');
    });

  const regionsName: any = {};

  regions.forEach((region: any) => {
    regionsName[region.code] = region.fullname;
  });

  let workCalendar: WorkCalendarForDomain | null = null;
  workCalendar = new WorkCalendarForDomain(domain);
  await workCalendar.fetch();

  const checkValue = (val: any) => val || '-';
  const departmentRestWeekDays = ['1', '7']; // keys(this.workCalendar?.restDaysOfWeek);

  const federalRestDays = workCalendar?.restDaysCalendar
    && Object.values(workCalendar?.restDaysCalendar).map(day => day.longDate);

  response = response.map((el: any) => {
    const status = el.system.status.internal;
    const now = convertDateFromBackendFormat(Date.now(), DateFormat.date);
    const startDate = isCorrectDate(parseDateFromString(el?.system?.startDate, DateFormat.date))
      ? parseDateFromString(el?.system?.startDate, DateFormat.date)
      : parseDateFromString(el?.system?.startDate, DateFormat.invertedDate);
    const finishString = convertDateFromBackendFormat(el?.common?.finishDate, DateFormat.date);
    const dueDate = convertDateFromBackendFormat(el?.common?.dueDate, DateFormat.date);

    let daysRemain = getDifferenceBetweenDates('days',
      parseDateFromString(dueDate, DateFormat.date),
      parseDateFromString(now, DateFormat.date));
    let datesRemain: {}[] = [];
    let daysRemainRegistration = 0;
    
    let finishDate = parseDateFromString(finishString, DateFormat.date) 
    finishDate && finishDate.setHours(finishDate.getHours() + 6)
    const finishTimestamp = finishDate && toTimestamp(finishDate);
    const nowTimestamp = toTimestamp(new Date);

    switch (status) {
      case '01':
      case '01.2':
      case '01.3':
      case '70.1':
        daysRemainRegistration = getDifferenceBetweenDates('days',
          parseDateFromString(now, DateFormat.date), startDate);
        if (daysRemainRegistration <= 1) {
          daysRemain = countWithRestDays(daysRemainRegistration) || daysRemainRegistration;
        } else {
          daysRemain = countRegistrationVialation(daysRemainRegistration, nowTimestamp);
        }
        break;
      case '10':
      case '11':
        const completedInTime = getDifferenceBetweenDates('days',
          parseDateFromString(dueDate, DateFormat.date),
          parseDateFromString(finishString, DateFormat.date)
        ) >= 0;
        if (completedInTime) {
          datesRemain = [];
          daysRemain = 0;
        } else {
          const completedWithViolation = getDifferenceBetweenDates('days',
            parseDateFromString(dueDate, DateFormat.date),
            parseDateFromString(finishString, DateFormat.date)
          )
          countWithRestDays(completedWithViolation);
        }
        break;
      case '12':
        daysRemainRegistration = getDifferenceBetweenDates('days',
          parseDateFromString(finishString, DateFormat.date), startDate);
          
        if (daysRemainRegistration <= 1) {
          datesRemain = [];
          daysRemain = 0;
        } else {
          daysRemain = finishTimestamp && countRegistrationVialation(daysRemainRegistration, finishTimestamp) || 0;
        }
        break;
      default:
        countWithRestDays(daysRemain);
        break;
    }

    function countWithRestDays(violationDays: number) {
      for (let index = 1; index <= Math.abs(violationDays) + 1; index++) {
        const timestamp = violationDays > 0 ? nowTimestamp + 86400 * index : nowTimestamp - 86400 * index;
        const date = new Date(timestamp * 1000);
        const numDayOfWeek = date.getDay() + 1;

        if (violationDays === 0) {
          datesRemain.push({
            nowTimestamp,
            numDayOfWeek,
            date: date.toDateString()
          })
          return;
        } else {
          if (!departmentRestWeekDays.includes(String(numDayOfWeek))
            && !federalRestDays?.includes(timestamp)) {
            datesRemain.push({
              timestamp,
              numDayOfWeek,
              date: date.toDateString()
            })
          }
        }
      }
      return datesRemain.length;
    }

    function countRegistrationVialation(violationDays: number, stamp: number) {
      for (let index = 0; index <= Math.abs(violationDays); index++) {
        const timestamp = stamp - 86400 * index;
        const date = new Date(timestamp * 1000);
        const numDayOfWeek = date.getDay() + 1;

        if (!departmentRestWeekDays.includes(String(numDayOfWeek))
          && !federalRestDays?.includes(timestamp)) {
          datesRemain.push({
            timestamp,
            numDayOfWeek,
            date: date.toDateString()
          });
        };
      }
      datesRemain = datesRemain.slice(0, -2);
      return -datesRemain.length;
    }
    return [
      checkValue(regionsName[el?.system?.regionCode]), // Регион
      checkValue(el?.system?.department?.fullName), // Наименование ведомства
      checkValue(el?.service), // Название услуги
      checkValue(el?.system?.applicant?.fullName), // Заявитель
      addressInfo(el), // Адрес заявителя
      checkValue(el?.common?.orderId), // Номер заявления в ЛК ЕПГУ
      checkValue(el?.common?.chanel), // Канал поступления
      checkExistedLocalization(
        `statements.statusTypes.${el?.system?.status?.external}`,
        '-'
      ), // Статус заявления на ЕПГУ
      checkValue(el?.common?.regNumber), // Регистрационный номер
      checkValue(el?.system?.startDate), // Дата подачи
      checkValue(dueDate), // Максимальный срок предоставления
      checkValue(daysRemain >= 0 ? datesRemain.length : ''), // Количество дней до окончания срока
      checkValue(finishString), // Дата предоставления услуги
      checkValue(daysRemain < 0 ? datesRemain.length : ''), // Количество дней нарушения срока
      checkValue(getDictionary(status)), // Статус на текущую дату
      checkValue(el?.common?.assignee?.fullName), // Ответственный
      checkValue(el?.applicant?.dateBirth), // Дата рождения лица, подавшего заявление
    ]
  });

  response.unshift([
    'Регион',
    'Наименование ведомства',
    'Название услуги',
    'ФИО Заявителя',
    'Адрес заявителя',
    'Номер заявления в ЛК ЕПГУ',
    'Канал поступления',
    'Статус заявления на ЕПГУ',
    'Регистрационный номер',
    'Дата подачи',
    'Максимальный срок предоставления',
    'Количество дней до окончания срока',
    'Дата предоставления услуги',
    'Количество дней нарушения срока',
    'Статус на текущую дату',
    'Ответственный',
    'Дата рождения лица, подавшего заявление',
  ]);

  const responseString = response
    .map((el: any) => {
      const row = el.map((col: any) => {
        if (typeof col === 'string') {
          return `"${col}"`;
        } else {
          return col;
        }
      });
      const rowString = row.join(';');
      return `${rowString}\r\n`;
    })
    .join('') ;
  return responseString;
}

// Also change defaultColumnsExtraFields in './columns.ts'
export function addressInfo(statement: any): string {
  if (statement.applicant?.addressInfo?.adressRegistration?.fullAddress) {
    return statement.applicant.addressInfo.adressRegistration.fullAddress;
  }
  if (statement.applicant?.address?.register?.text) {
    return statement.applicant.address.register.text;
  }
  if (statement.statement?.recipientPersonalData?.appRegAddress) {
    return statement.statement.recipientPersonalData.appRegAddress;
  }
  if (statement.applicant?.addressInfo?.adressStay?.fullAddress) {
    return statement.applicant.addressInfo.adressStay.fullAddress;
  }
  return '-';
}

