import { Injectable } from '@angular/core';
import { EISPublicService, FileDTO, ProcessingStatus, QueryTokenDTO } from '@swagger/eis';
import { DateAdapter } from '@ui/common';
import { memorize } from '@utils/common';
import { map, shareReplay, switchMap } from 'rxjs/operators';
import { InfoType, ProcessingStatusList } from './defs';

@Injectable({
  providedIn: 'root',
})
export class DomainTaskCalendarService {
  readonly currentBranchId$ = this.eisPublicService.EISPublicGetCurrentBranch({}).pipe(
    map((response) => response.result?.id),
    shareReplay()
  );

  constructor(private eisPublicService: EISPublicService, private dateAdapter: DateAdapter) {}

  getSettings() {
    return this.eisPublicService.EISPublicQueryDisplayInfoSettings().pipe(map((settings) => settings.result));
  }

  getInfos(queryToken: QueryTokenDTO) {
    return this.eisPublicService.EISPublicQueryDisplayInfo({
      queryToken,
    });
  }

  getInfoById({ infoId }: { infoId: number }) {
    return this.eisPublicService.EISPublicGetDisplayInfoById({
      infoId,
    });
  }

  setToEdit({ infoId }: { infoId: number }) {
    return this.eisPublicService.EISPublicSetInfoToEdit({
      infoId,
    });
  }

  complete({ infoId, file }: { infoId: number; file?: string | ArrayBuffer }) {
    let fileDTO: FileDTO;
    let _file: string;

    if (typeof file === 'string') {
      _file = file;
    } else if (file instanceof ArrayBuffer) {
      _file = this.arrayBufferToString(file);
    }

    if (_file) {
      fileDTO = {
        name: 'confirmation image',
        mime: this.parseMimeTypeFromBase64String(_file),
        content: this.removeMetaDataFromBase64(_file),
      };
    } else {
      fileDTO = {};
    }

    return this.eisPublicService.EISPublicCompleteConfirmation({
      infoId,
      file: fileDTO,
    });
  }

  /* @internal */
  arrayBufferToString(arrayBuffer: ArrayBuffer): string {
    return String.fromCharCode.apply(null, new Uint16Array(arrayBuffer));
  }

  /* @internal */
  parseMimeTypeFromBase64String(base64: string): string {
    return base64.substring('data:'.length, base64.indexOf(';'));
  }

  /* @internal */
  removeMetaDataFromBase64(base64: string): string {
    const stringFromWhichToStart = 'base64,';
    return base64.substring(base64.indexOf(stringFromWhichToStart) + stringFromWhichToStart.length, base64.length);
  }

  resetConfirmation({ infoId }: { infoId: number }) {
    return this.eisPublicService.EISPublicResetConfirmation({
      infoId,
    });
  }

  @memorize({ ttl: 60000 })
  getFile({ fileId, download }: { fileId: number; download?: boolean }) {
    return this.eisPublicService
      .EISPublicGetFileContent({
        fileId,
        download,
      })
      .pipe(shareReplay());
  }

  @memorize({ ttl: 60000 })
  getFiles({ infoId }: { infoId: number }) {
    return this.eisPublicService
      .EISPublicGetFiles({
        infoId,
      })
      .pipe(shareReplay());
  }

  @memorize({ ttl: 60000 })
  getImageFiles({ infoId }: { infoId: number }) {
    return this.eisPublicService
      .EISPublicGetImages({
        infoId,
      })
      .pipe(shareReplay());
  }

  @memorize({ ttl: 60000 })
  getTeaserFile({ infoId }: { infoId: number }) {
    return this.eisPublicService
      .EISPublicGetTeaserImage({
        infoId,
      })
      .pipe(shareReplay());
  }

  getConfirmationFiles({ infoId }: { infoId: number }) {
    return this.currentBranchId$.pipe(
      switchMap((branchId) => this.eisPublicService.EISPublicGetConfirmationFilesByBranchId({ infoId, branchId }))
    );
  }

  getArticles({ infoId }: { infoId: number }) {
    return this.eisPublicService.EISPublicGetArticles({
      infoId,
    });
  }

  getProcessingStatusList({ processingStatus = 0 }: { processingStatus?: ProcessingStatus }): ProcessingStatusList {
    /**
     * ProcessingStatus
     * 1 = Approved
     * 2 = InProcess
     * 4 = Completed
     * 8 = Overdue
     * 16 = Archived
     * 32 = Removed
     * 64 = Uncompleted
     */
    const processingStatusList: ProcessingStatusList = [];

    if (!!(processingStatus & 1)) {
      processingStatusList.push('Approved');
    }

    if (!!(processingStatus & 2)) {
      processingStatusList.push('InProcess');
    }

    if (!!(processingStatus & 4)) {
      processingStatusList.push('Completed');
    }

    if (!!(processingStatus & 8)) {
      processingStatusList.push('Overdue');
    }

    if (!!(processingStatus & 16)) {
      processingStatusList.push('Archived');
    }

    if (!!(processingStatus & 32)) {
      processingStatusList.push('Removed');
    }

    if (!!(processingStatus & 64)) {
      processingStatusList.push('Uncompleted');
    }

    return processingStatusList;
  }

  getProcessingStatusColorCode({
    processingStatus,
    hasTask,
    publicationDate,
    announcementDate,
  }: {
    processingStatus?: ProcessingStatus;
    publicationDate?: string;
    announcementDate?: string;
    hasTask?: boolean;
  }) {
    const type = this.getInfoType({ hasTask, publicationDate, announcementDate });

    if (type === ('Info' || 'PreInfo')) {
      return '#8A949E';
    }

    const processingStatusList = this.getProcessingStatusList({ processingStatus });

    if (processingStatusList.includes('Archived')) {
      return '#44942e';
    }

    if (processingStatusList.includes('Completed')) {
      return '#44942e';
    }

    if (processingStatusList.includes('Uncompleted')) {
      return '#f70400';
    }

    if (processingStatusList.includes('Overdue')) {
      return '#f70400';
    }

    if (processingStatusList.includes('InProcess')) {
      return '#FFCC01';
    }

    if (processingStatusList.includes('Approved')) {
      return '#8A949E';
    }

    return '#8A949E';
  }

  getInfoType({
    hasTask,
    publicationDate,
    announcementDate,
    taskDate,
    isSpecial,
  }: {
    publicationDate?: string;
    announcementDate?: string;
    hasTask?: boolean;
    taskDate?: string;
    isSpecial?: boolean;
  }): InfoType {
    if (hasTask) {
      const _publicationDate = new Date(publicationDate);
      const _taskDate = new Date(taskDate);

      return this.dateAdapter.compareDate(_taskDate, _publicationDate) > 0 ? 'PreInfo' : 'Task';
    }

    return 'Info';
  }

  getDisplayInfoDate(source: { taskDate?: string; publicationDate?: string; announcementDate?: string }) {
    // Wenn announcementDate abgelaufen ist wird der taskDate/publicationDate genommen
    let displayDate = new Date(source.publicationDate || source.taskDate);

    if (source.announcementDate && new Date(source.announcementDate) >= this.dateAdapter.today()) {
      displayDate = new Date(source.announcementDate);
    }

    return displayDate;
  }

  getComments({ infoId }: { infoId: number }) {
    return this.currentBranchId$.pipe(
      switchMap((branchId) =>
        this.eisPublicService.EISPublicGetCommentsByBranchId({
          branchId,
          infoId,
        })
      )
    );
  }
  addComment({ infoId, text }: { infoId: number; text: string }) {
    return this.currentBranchId$.pipe(
      switchMap((branchId) =>
        this.eisPublicService.EISPublicAddComment({
          infoId,
          payload: { text, branch: { id: branchId } },
        })
      )
    );
  }
}
