import { UITagListCheckTag } from './../data/ui-tag-list-check';
import { UITagListCheckConfig, UITagListCheckModel } from '../data/ui-tag-list-check';
import { computedFrom, Disposable } from 'aurelia-binding';
import { PictureHelper } from './../files/picture-helper';
import { Router } from 'aurelia-router';
import { AuditLog, AuditLogChanges, AuditLogCustom } from './../../model/common-model';
import { EntityTypeNames } from './../../constants/constants';
import { I18N } from 'aurelia-i18n';
import { HttpClient } from 'aurelia-fetch-client';
import { autoinject, bindable, customElement, BindingEngine, TaskQueue } from 'aurelia-framework';
import { Subscription } from "aurelia-event-aggregator";
import moment from 'moment';
import { ServiceBase } from '../../data/service-base';
import { Datacontext } from '../../data/data-context';
import { UIInternal } from '../../utils/ui-internal';
import { CamelCase } from '../../utils/came-case';
import { Config } from '../../config';
import { Utils } from './../../utils/utils';
export const EVT_REFRESH_HISTORY = "EVT_REFRESH_HISTORY";

@customElement('ui-entity-history')
@autoinject
export class UIEntityHistory {
  @bindable
  public entityType: string;

  @bindable
  public entityId: number;

  public auditLogs: Array<AuditLog>;
  public isLoading: boolean;
  protected auditLogService: ServiceBase<AuditLog>;
  private eventSub: Subscription;
  private disposables: Disposable[] = [];

  public auditLogsToDisplay: Array<AuditLogByDate> = [];
  private auditLogLastDate: Date = moment().add(1, "days").toDate();
  private queryInProcess: boolean = false;
  private stopQueryLog: boolean = false;
  private viewHistory: boolean = true;
  private disabledSaveFilter: boolean = true;
  public filterModelEntityName: UITagListCheckModel;
  public filterModelUser: UITagListCheckModel;
  public filterConfig: UITagListCheckConfig = {
    size: 'nm',
    offBackgroundColor: 'white',
    offTextColor: 'ui-theme--primary',
    onBackgroundColor: 'ui-theme--primary',
    onTextColor: 'white'
  };
  public tagsSelected: Array<UITagListCheckTag> = [];
  public userTagsSelected: Array<UITagListCheckTag> = [];

  public file: string = HistorySpecificType.File;
  public picture: string = HistorySpecificType.Picture;
  public comment: string = HistorySpecificType.Comment;
  public entitiesInfo: EntityInfo[];

  constructor(private element: Element, private router: Router, private httpClient: HttpClient, private config: Config, private i18n: I18N, private context: Datacontext, private pictureHelper: PictureHelper, private bindingEngine: BindingEngine, private taskQueue: TaskQueue) {
    this.auditLogService = new ServiceBase<AuditLog>(EntityTypeNames.AuditLog);
    this.auditLogs = [];
    this.isLoading = true;
  }

  async bind() {
    this.eventSub = UIInternal.subscribe(EVT_REFRESH_HISTORY, async () => {
      this.refreshHistory(true);
    });
    await this.refreshHistory(true);
  }

  detached() {
    this.eventSub.dispose();
  }

  async entityIdChanged() {
    await this.refreshHistory(true);
  }

  async getFilterEntityNames() {
    let results = await this.httpClient.fetch(this.config.globalConfig.remoteServiceName + "/AuditLog/EntityNamesAndUserNames?entityId=" + this.entityId + "&entityType=" + this.entityType);
    let entityNames: string[];
    let userInfos: UserInfo[];
    if (results.ok) {
      let json = await results.json();
      console.log(json.EntityInfos);
      this.entitiesInfo = json.EntityInfos;
      entityNames = json.EntityNames;
      userInfos = json.UserInfos;
    }
    this.filterModelEntityName = {
      label: null,
      tags: []
    };
    this.entitiesInfo.forEach(x => {
      this.filterModelEntityName.tags.push({
        id: x.EntityName,
        label: this.i18n.tr(this.getTranslation(x.EntityName)),
        icon: x.Icon
      });

    })
    // entityNames.forEach(x => {
    //   let specificEntity = this.historyCustom.entitiesIcons.filter(s => s.entityName == x);
    //   if (specificEntity != null && specificEntity.length > 0) {
    //     this.filterModelEntityName.tags.push({
    //       id: specificEntity[0].entityName,
    //       label: this.i18n.tr(this.getTranslation(specificEntity[0].entityName)),
    //       icon: specificEntity[0].icon
    //     });
    //   } else {
    //     console.log("EntityName ", x, " is missing");
    //   }
    // });
    this.filterModelEntityName.tags.forEach(x => {
      let selectedTag = this.tagsSelected.find(t => t.id == x.id)
      if (selectedTag != null) {
        x.selected = true;
        this.tagsSelected = this.tagsSelected.filter(t => t.id != x.id);
        this.tagsSelected.push(x);
        this.updateDisabledSaveFilter();
      }
      this.disposables.push(
        this.bindingEngine.propertyObserver(x, "selected").subscribe(async (newValue, oldValue) => {
          if (newValue != oldValue) {
            if (newValue) {
              this.disabledSaveFilter = false;
              this.tagsSelected.push(x);
            } else {
              let tagFind = this.tagsSelected.find(tag => tag == x);
              if (tagFind != null) {
                this.tagsSelected = this.tagsSelected.filter(tag => tag != x);
              }
              await this.refreshHistory(false);
              this.updateDisabledSaveFilter();
            }
          }
        })
      );
    });

    this.filterModelUser = {
      label: null,
      tags: userInfos.map(x => {
        return {
          id: x.UserName,
          label: x.UserName,
          icon: x.AvatarUri
        }
      })
    };
    this.filterModelUser.tags.forEach(x => {
      let selectedTag = this.userTagsSelected.find(t => t.id == x.id)
      if (selectedTag != null) {
        x.selected = true;
        this.userTagsSelected = this.userTagsSelected.filter(t => t.id != x.id);
        this.userTagsSelected.push(x);
        this.updateDisabledSaveFilter();
      }
      this.disposables.push(
        this.bindingEngine.propertyObserver(x, "selected").subscribe(async (newValue, oldValue) => {
          if (newValue != oldValue) {
            if (newValue) {
              this.disabledSaveFilter = false;
              this.userTagsSelected.push(x);
            } else {
              let tagFind = this.userTagsSelected.find(tag => tag == x);
              if (tagFind != null) {
                this.userTagsSelected = this.userTagsSelected.filter(tag => tag != x);
              }
              await this.refreshHistory(false);
              this.updateDisabledSaveFilter();
            }
          }
        })
      );
    });

  }

  private updateDisabledSaveFilter() {
    if (this.filterModelUser.tags.some(x => x.selected == true) || this.filterModelEntityName.tags.some(x => x.selected == true)) {
      this.disabledSaveFilter = false;
    } else {
      this.disabledSaveFilter = true;
    }
  }

  protected async refreshHistory(refreshFilter: boolean) {
    if (refreshFilter) {
      await this.getFilterEntityNames();
    }
    this.auditLogs.splice(0);
    this.auditLogsToDisplay?.splice(0);
    this.stopQueryLog = false;
    this.auditLogLastDate = moment().add(1, "day").toDate();
    if (this.entityId != null && this.entityType != null) {
      this.isLoading = true;
      await this.getAuditLogs();
      this.isLoading = false;
    }
  }


  private isEllipsisActive(e: Element) {
    var tolerance = 2; // In px. Depends on the font you are using
    return e.offsetHeight + tolerance < e.scrollHeight;
  }

  private async getAuditLogs() {
    if (!this.queryInProcess && !this.stopQueryLog) {
      // console.log("this.queryInProcess, auditLogLastDate : ", this.auditLogLastDate);
      this.queryInProcess = true;

      let filterEntityName = this.filterModelEntityName.tags?.filter(x => x.selected == true).map(x => x.id).toString();
      let filterUser = this.filterModelUser.tags?.filter(x => x.selected == true).map(x => x.id).toString();
      // let results = await this.httpClient.fetch(this.config.remoteServiceName + "/AuditLog/" + EntityTypeNames.ResourceNames.AuditLog + "?entityId=" + this.entityId + "&entityType=" + this.entityType + "&auditLogLastDate=" + this.auditLogLastDate.toJSON() + (filterEntityName.length > 0 ? "&filterEntityName=" + filterEntityName : "") + (filterUser.length > 0 ? "&filterUser=" + filterUser : ""));
      let results = await this.httpClient.fetch(this.config.globalConfig.remoteServiceName + "/AuditLog/" + EntityTypeNames.ResourceNames.AuditLog + "?entityId=" + this.entityId + "&entityType=" + this.entityType + (filterEntityName.length > 0 ? "&filterEntityName=" + filterEntityName : "") + (filterUser.length > 0 ? "&filterUser=" + filterUser : ""));
      if (results.ok) {
        let newHistories: AuditLog[] = await results.json();
        // this.auditLogLastDate = moment(this.auditLogLastDate).add(-30, "day").toDate();
        this.auditLogs.push(...newHistories);
        this.sortAuditLogs(newHistories);

        this.taskQueue.queueTask(() => {
          const commentDetail: HTMLCollectionOf<Element> = this.element.getElementsByClassName('comment_detail');
          for (var i = 0; i < commentDetail.length; i++) {
            let e: Element = commentDetail[i];
            if (this.isEllipsisActive(e)) {
              e.classList.add("value_overflow_hidden");
            }
          }
          const oldValue: HTMLCollectionOf<Element> = this.element.getElementsByClassName('history_container__old');
          for (var i = 0; i < oldValue.length; i++) {
            let e: Element = oldValue[i];
            if (this.isEllipsisActive(e)) {
              e.classList.add("value_overflow_hidden");
            }
          }
          const newValue: HTMLCollectionOf<Element> = this.element.getElementsByClassName('history_container__new');
          for (var i = 0; i < newValue.length; i++) {
            let e: Element = newValue[i];
            if (this.isEllipsisActive(e)) {
              e.classList.add("value_overflow_hidden");
            }
          }
          const containerPicture: HTMLCollectionOf<Element> = this.element.getElementsByClassName('history_container_picture');
          for (var i = 0; i < containerPicture.length; i++) {
            let e: Element = containerPicture[i];
            if (this.isEllipsisActive(e)) {
              e.classList.add("value_overflow_hidden");
            }
          }
        });

      }
      this.queryInProcess = false;
    }
  }

  public sortAuditLogs(auditLogs: AuditLog[]) {
    auditLogs.forEach((audit: AuditLog) => {
      if (this.router.hasOwnRoute(audit.LinkEntityType)) {
        try {
          let newRoute = this.router.generate(audit.LinkEntityType, { param1: audit.LinkEntityPK.toString() })
          audit.Link = newRoute;
        }
        catch (error) { }
      }
      if (audit.Changes != null && audit.Changes.length > 0) {
        this.enrichChanges(audit);
      }

      let date = moment.utc(audit.DateTime).local().hour(0).minute(0).second(0).millisecond(0).toDate()
      let display: AuditLogByDate = this.auditLogsToDisplay.find(x => moment(date).diff(x.date, "days") == 0);
      if (display == null) {
        display = {
          date: date,
          groupBlocs: []
        }
        this.auditLogsToDisplay.push(display);
      }
      let startDate = moment.utc(audit.DateTime).local().minute(0).second(0).millisecond(0).toDate();
      let endDate = moment(startDate).clone().add(1, "hours").toDate();
      let groupBloc: AuditLogGroupBloc = display.groupBlocs.find(x => x.blocs.some(b => moment(startDate).diff(b.startDate, 'hours') == 0));
      if (groupBloc == null) {
        groupBloc = display.groupBlocs.find(x => x.blocs.some(b => moment(startDate).diff(b.endDate, 'hours') == 0));
        if (groupBloc == null) {
          groupBloc = {
            startDate: startDate,
            endDate: endDate,
            blocs: []
          }
          display.groupBlocs.push(groupBloc);
          display.groupBlocs = this.sortArray(display.groupBlocs, "endDate", "desc");
        }
      }
      let bloc: AuditLogBlocHour = groupBloc.blocs.find(x => moment(endDate).diff(x.endDate, 'hours') == 0);
      if (bloc == null) {
        bloc = {
          startDate: startDate,
          endDate: endDate,
          lastOfBloc: false,
          entities: []
        }
        groupBloc.blocs.push(bloc);
        groupBloc.blocs = this.sortArray(groupBloc.blocs, "endDate", "desc");
        groupBloc.startDate = bloc.startDate;
      }

      let name = this.getEntityName(audit);
      let type = this.getSpecificTypeOfEntity(name, audit.ActionType);
      let operation = this.getOperation(audit, type);
      let entity: AuditLogEntity = bloc.entities.find(x => x.name == name && x.operation == operation);

      if (entity == null) {
        entity = {
          name: name,
          operation: operation,
          viewDetail: true,
          // icon: this.historyCustom?.entitiesIcons?.find(x => x.entityName == name)?.icon,
          icon: this.entitiesInfo.find(x => x.EntityName == name).Icon,
          link: audit.Link,
          minutes: [],
          type: type
        }
        bloc.entities.push(entity);
      }
      let minute: AuditLogBlocMinute = entity.minutes.find(x => moment.utc(audit.DateTime).local().diff(x.date, 'minutes') == 0 && x.user == audit.AuditUser)
      if (minute == null) {
        minute = {
          date: moment.utc(audit.DateTime).local().toDate(),
          user: audit.AuditUser,
          data: []
        }
        entity.minutes.push(minute);
        entity.minutes = this.sortArray(entity.minutes, "date", "desc");
      }

      if (type == this.picture || type == this.file) {
        let url = audit.Changes?.find(x => x.PropertyName == "Url");
        if (url != null) {
          let urlData: UrlData = {
            url: url.NewValue,
            name: audit.Display
          }
          minute.data.push(urlData);
        }
      } else if (type == this.comment) {
        let description = audit.Changes?.find(x => x.PropertyName == "Description")?.NewValue;
        description = this.formatHtml(description);

        let commentData: CommentData = {
          type: (audit.Changes?.find(x => x.PropertyName == "CommentTypeId")?.NewValue as any)?.Auto,
          description: description,
          createdBy: (!audit.ActionType.startsWith("Create") ? audit.Changes?.find(x => x.PropertyName == "CreatedByFullName")?.NewValue : null),
          Changes: this.getCommentChanges(audit),
        }
        minute.data.push(commentData);
      } else {
        audit.Changes == audit.Changes?.filter(x => x.PropertyName != "CreatedByFullName");
        minute.data.push(audit);
      }
    });
    this.auditLogsToDisplay.forEach(byDate => byDate.groupBlocs.forEach(x => (x.blocs.last() as AuditLogBlocHour).lastOfBloc = true));
  }

  private getCommentChanges(audit: AuditLog): AuditLogChanges[] {
    if (audit.ActionType == ActionType.Update || audit.ActionType == ActionType.UpdateFK) {
      return audit.Changes?.filter(x => x.PropertyName != "CreatedByFullName" && x.PropertyName != "Description" && x.PropertyName != "CommentTypeId")
    }
    return [];
  }

  private formatHtml(html: string) {
    return Utils.innerTextFromHTML(html);
  }

  private getSpecificTypeOfEntity(entityName: string, actionType: string): string {
    let entityInfo = this.entitiesInfo.find(x => x.EntityName == entityName);
    if (entityInfo.SpecificType == HistorySpecificType.File && actionType != ActionType.Update && actionType != ActionType.UpdateFK) {
      return HistorySpecificType.File;
    }
    if (entityInfo.SpecificType == HistorySpecificType.Picture && actionType != ActionType.Update && actionType != ActionType.UpdateFK) {
      return HistorySpecificType.Picture;
    }
    if (entityInfo.SpecificType == HistorySpecificType.Comment) {
      return HistorySpecificType.Comment;
    }
    return null;
  }

  private getOperation(entity: AuditLog, type: string) {
    if (entity.ActionType != null) {
      switch (entity.ActionType) {
        case "Create":
          return `${this.getOperationTranslation(entity, entity.ClrEntityType)}  <span class="body__historique--title--creation">${this.i18n.tr("history.created", { ns: "common" })}</span>`;
        case "Update":
          return `${this.getOperationTranslation(entity, entity.ClrEntityType)} <span class="body__historique--title--update">${this.i18n.tr("history.updated", { ns: "common" })}</span>`;
        case "CreateFK":
          return `${this.getOperationTranslation(entity, entity.LinkEntityType)}${this.displayNameCreateFk(entity, type)} <span class="body__historique--title--creation">${this.i18n.tr("history.created", { ns: "common" })}</span>`;
        case "UpdateFK":
          return `${this.getOperationTranslation(entity, entity.LinkEntityType)}${this.getDisplayName(entity)} <span class="body__historique--title--update">${this.i18n.tr("history.updated", { ns: "common" })}</span>`;
        case "DeleteFK":
          return `${this.getOperationTranslation(entity, entity.LinkEntityType)}${this.getDisplayName(entity)} <span class="body__historique--title--delete">${this.i18n.tr("history.deleted", { ns: "common" })}</span>`;
      }
    }
  }

  private displayNameCreateFk(entity: AuditLog, type: string) {
    if (type == null || (type != HistorySpecificType.File && type != HistorySpecificType.Picture && type != HistorySpecificType.Comment)) {
      return this.getDisplayName(entity);
    }
    return '';
  }

  private getEntityName(entity: AuditLog) {
    if (entity.ActionType != null) {
      switch (entity.ActionType) {
        case "Create":
        case "Update":
          return entity.ClrEntityType;
        case "CreateFK":
        case "UpdateFK":
        case "DeleteFK":
          return entity.LinkEntityType;
      }
    }
  }

  public enrichChanges(entity: AuditLog) {
    entity.Changes.forEach((change: AuditLogChanges) => {
      (change as any).TransPropertyName = (entity.ActionType != null && change.PropertyName != null && change.PropertyName.length >= 1) ?
        (entity.ActionType == "Update" && entity.ClrEntityType != null) ?
          this.i18n.tr(entity.ClrEntityType.toLowerCase() + "." + CamelCase.toCamelCase(change.PropertyName))
          : ((entity.ActionType == "UpdateFK" && entity.LinkEntityType != null) ?
            this.i18n.tr(entity.LinkEntityType.toLowerCase() + "." + CamelCase.toCamelCase(change.PropertyName))
            : change.PropertyName)
        :
        change.PropertyName;

      (change as any).TransOldValue = this.valueFormating(change.OldValue);
      (change as any).TransOldValue = this.formatHtml((change as any).TransOldValue);
      (change as any).TransNewValue = this.valueFormating(change.NewValue);
      (change as any).TransNewValue = this.formatHtml((change as any).TransNewValue);
      (change as any).showChangesContainer = ((change as any).TransOldValue as string)?.length > 0 || ((change as any).TransNewValue as string)?.length > 0;
    });
  }

  public valueFormating(value: any): string {
    if (value != null) {
      if (Object.keys(value).indexOf("Lang1") > -1
        || Object.keys(value).indexOf("Lang2") > -1
        || Object.keys(value).indexOf("Lang3") > -1
        || Object.keys(value).indexOf("Lang4") > -1
        || Object.keys(value).indexOf("Lang5") > -1) {
        return value[this.translatePropertyName];
      }
      else if (typeof value == "boolean") {
        return value ? this.i18n.tr("general.yes", { ns: "common" }) : this.i18n.tr("general.no", { ns: "common" });
      }
      else if (typeof value == "number") {
        return value.toString();
      }
      else if (jQuery.isEmptyObject(value)) {
        return "";
      }
      else if (moment(value, "DD-MM-YYYY HH:mm:ss", true).isValid()) {
        //DateTime
        return moment.utc(value, "DD-MM-YYYY HH:mm:ss", true).local().format("DD/MM/YYYY HH:mm");
      }
      else if (moment(value, "DD/MM/YYYY", true).isValid()) {
        //DateOnly
        return moment.utc(value, "DD/MM/YYYY", true).local().format("DD/MM/YYYY");
      }
      else if (moment(value, "HH:mm:ss", true).isValid()) {
        //TimeOnly
        return moment.utc(value, "HH:mm:ss", true).local().format("HH:mm:ss");
      }
      else if (moment(value, "HH:mm", true).isValid()) {
        //DurationTime
        return value;
      }
      else {
        var strValue = value as string;
        if (strValue?.length > 10000) return '';
        return value;
      }
    }
    else {
      return "";
    }
  }

  public getTranslation(type: string) {
    return `${type.toLowerCase()}.${type.toLowerCase()}`
  }

  public getOperationTranslation = (entity: AuditLog, type: string) => {
    const entry = this.getTranslation(type);
    const trans = this.i18n.tr(entry);
    let result = "";
    if (trans === entry) result = entity.ClrEntityType;
    result = trans;
    // this.getDisplayName(entity);
    return result;
  }

  public getDisplayName(entity: AuditLog) {
    let result = "";
    if (entity.Display != null) {
      result += " ";
      switch (entity.DisplayType) {
        case "TranslatedProperty":
          try {
            let parsedDisplay = JSON.parse(entity.Display);
            result += parsedDisplay[this.translatePropertyName];
          }
          catch (error) {
            //console.log(error);
          }
          break;
        default:
          result += entity.Display;
          break;
      }
    }
    return result;
  }

  @computedFrom("context")
  public get translatePropertyName() {
    return `Lang${this.context.currentLanguage.columnIndex}`;
  }

  // public toggleDetails(auditLog: AuditLog) {
  //   auditLog.ShowDetails = !auditLog.ShowDetails;
  // }

  private sortArray(array, propertyName: string, direction: string = 'asc') {
    let factor = direction === 'asc' ? 1 : -1;
    return array.slice(0).sort((a: Date, b: Date) => {
      return (a[propertyName] - b[propertyName]) * factor;
    });
  }

  // TODO infini Scroll
  // public async getMore(scrollContext) {
  //   console.log("Scroll context : ", scrollContext);
  //   await this.getAuditLogs();
  // }

  public viewMoreChange($event: MouseEvent) {
    let list = $event.target.parentElement.getElementsByClassName("comment_detail");
    let parent: Element;
    if (list.length == 0) {
      list = $event.target.parentElement.getElementsByClassName("history_container_picture");
      if (list.length == 0) {
        let previous = $event.target.previousElementSibling;
        if (!previous.className.includes("history_container__old")) {
          let previous = $event.target.previousElementSibling;
          if (previous.className.includes("history_container__new")) {
            parent = previous;
          }
        } else {
          parent = previous;
        }
      } else {
        parent = list[0];

      }
    } else {
      parent = list[0];
    }
    parent.classList.remove("value_overflow_hidden");
    parent.classList.add("value_overflow_visible");
  }

  public viewLessChange($event: MouseEvent) {
    let list = $event.target.parentElement.getElementsByClassName("comment_detail");
    let parent: any;
    if (list.length == 0) {
      list = $event.target.parentElement.getElementsByClassName("history_container_picture");
      if (list.length == 0) {
        let previous = $event.target.previousElementSibling.previousElementSibling;
        if (!previous.className.includes("history_container__old")) {
          if (previous.className.includes("history_container__new")) {
            parent = previous;
          }
        } else {
          parent = previous;
        }
      } else {
        parent = list[0];
      }
    } else {
      parent = list[0];
    }

    parent.classList.remove("value_overflow_visible");
    parent.classList.add("value_overflow_hidden");

  }

  public async filter(open: boolean) {
    if (open) {
      this.viewHistory = false;
    } else {
      if (this.disabledSaveFilter) {
        await this.refreshHistory(false);
      }
      this.viewHistory = true;
    }
  }

  public async saveFilter() {
    this.viewHistory = true;
    await this.refreshHistory(false);
  }

  public removeUserTagsSelected(tag: UITagListCheckTag) {
    this.userTagsSelected = this.userTagsSelected.filter(x => x != tag);
    this.filterModelUser.tags.find(x => x.id == tag.id).selected = false;
  }

  public selectedUserTagsSelected(tag: UITagListCheckTag) {
    let findTag = this.filterModelUser.tags.find(x => x.id == tag.id)
    findTag.selected = !findTag.selected;
  }

  public beforeCloseFn(tag: UITagListCheckTag) {
    tag.selected = false;
  }
}
class EntityInfo {
  EntityName: string;
  Icon: string;
  SpecificType: string;
}


class UserInfo {
  UserName: string;
  AvatarUri: string;
}

class ActionType {
  public static Create = "Create";
  public static Update = "Update";
  public static CreateFK = "CreatedFK";
  public static UpdateFK = "UpdateFK";
  public static DeleteFK = "DeleteFK";
}

class HistorySpecificType {
  public static File = "File";
  public static Picture = "Picture";
  public static Comment = "Comment";
}
class AuditLogToDisplay {
  dates: Array<AuditLogByDate>;
}
class AuditLogByDate {
  date: Date;
  groupBlocs: Array<AuditLogGroupBloc>;
}
class AuditLogGroupBloc {
  endDate: Date;
  startDate: Date;
  blocs: Array<AuditLogBlocHour>;
}
class AuditLogBlocHour {
  startDate: Date;
  endDate: Date;
  lastOfBloc: boolean = false;
  entities: Array<AuditLogEntity>;
}
class AuditLogEntity {
  name: string;
  operation: string;
  viewDetail: boolean;
  icon: string;
  link: string;
  minutes: Array<AuditLogBlocMinute>;

  type: string;
}
class AuditLogBlocMinute {
  date: Date;
  user: string;
  data: Array<AuditLog | UrlData | CommentData>;
}
class UrlData {
  url: string;
  name: string;
}
class CommentData {
  type: string;
  description: string;
  createdBy: string;
  Changes: AuditLogChanges[];
}
