import {Component, Input, ViewChild} from "@angular/core";
import {Stakeholder} from "../../../monitor/entities/stakeholder";
import {UntypedFormBuilder, UntypedFormGroup, Validators} from "@angular/forms";
import {Option} from "../../../sharedComponents/input/input.component";
import {Subscription} from "rxjs";
import {StakeholderService} from "../../../monitor/services/stakeholder.service";
import {UtilitiesService} from "../../../services/utilities.service";
import {Role, Session, User} from "../../../login/utils/helper.class";
import {UserManagementService} from "../../../services/user-management.service";
import {StringUtils} from "../../../utils/string-utils.class";
import {NotifyFormComponent} from "../../../notifications/notify-form/notify-form.component";
import {NotificationUtils} from "../../../notifications/notification-utils";
import {Notification} from "../../../notifications/notifications";
import {NotificationHandler} from "../../../utils/notification-handler";
import {StatsProfilesService} from "../../utils/services/stats-profiles.service";
import {StakeholderBaseComponent} from "../../utils/stakeholder-base.component";

@Component({
  selector: 'edit-stakeholder',
  template: `
      <div class="uk-margin-medium-bottom">
          <form *ngIf="stakeholderFb" [formGroup]="stakeholderFb">
              <div class="uk-grid uk-grid-large" uk-grid>
                  <div class="uk-width-1-2@m">
                      <div input id="name" [formInput]="stakeholderFb.get('name')"
                           placeholder="Name"></div>
                  </div>
                  <div class="uk-width-1-2@m">
                      <div input [formInput]="stakeholderFb.get('alias')"
                           placeholder="URL Alias"></div>
                  </div>
                  <div class="uk-width-1-3@m">
                      <div input [formInput]="stakeholderFb.get('index_id')"
                           placeholder="Index ID"></div>
                  </div>
                  <div class="uk-width-1-3@m">
                      <div input [formInput]="stakeholderFb.get('index_name')"
                           placeholder="Index Name"></div>
                  </div>
                  <div class="uk-width-1-3@m">
                      <div input [formInput]="stakeholderFb.get('index_shortName')"
                           placeholder="Index Short Name"></div>
                  </div>
                  <ng-container *ngIf="isCurator">
                      <div class="uk-width-1-3@m">
                          <div *ngIf="statsProfiles" input [formInput]="stakeholderFb.get('statsProfile')"
                               [type]="'select'"
                               [options]="statsProfiles"
                               placeholder="Stats Profile"></div>
                      </div>
                      <div class="uk-width-1-3@m">
                          <div input [formInput]="stakeholderFb.get('projectUpdateDate')" [type]="'date'"
                               placeholder="Last Project Update"></div>
                      </div>
                  </ng-container>
                  <div class="uk-width-1-3@m">
                      <div input [formInput]="stakeholderFb.get('locale')" [type]="'select'"
                           [options]="stakeholderUtils.locales"
                           placeholder="Locale"></div>
                  </div>
                  <div class="uk-width-1-1">
                      <div input [type]="'textarea'" placeholder="Description"
                           [rows]="4" [formInput]="stakeholderFb.get('description')"></div>
                  </div>
                  <div class="uk-width-1-1">
                      <input #file id="photo" type="file" class="uk-hidden" (change)="fileChangeEvent($event)"/>
                      <div *ngIf="!stakeholderFb.get('isUpload').value" class="uk-grid uk-grid-column-large" uk-grid>
                          <div class="uk-margin-xsmall-top uk-width-auto@l uk-width-1-1">
                              <div class="uk-grid uk-grid-column-large uk-flex-middle" uk-grid>
                                  <div class="uk-width-auto@l uk-width-1-1 uk-flex uk-flex-center">
                                      <button class="uk-button uk-button-primary uk-flex uk-flex-middle uk-flex-wrap"
                                              (click)="file.click()">
                                          <icon name="cloud_upload" [flex]="true"></icon>
                                          <span class="uk-margin-small-left">Upload a file</span>
                                      </button>
                                  </div>
                                  <div class="uk-text-center uk-text-bold uk-width-expand">
                                      OR
                                  </div>
                              </div>
                          </div>
                          <div input class="uk-width-expand" type="logoURL" [placeholder]="'Link to the logo'"
                               [formInput]="stakeholderFb.get('logoUrl')"></div>
                      </div>
                      <div *ngIf="stakeholderFb.get('isUpload').value" class="uk-width-1-1 uk-flex uk-flex-middle">
                          <div class="uk-card uk-card-default uk-text-center uk-border-circle">
                              <img class="uk-position-center uk-blend-multiply" [src]="photo">
                          </div>
                          <div class="uk-margin-left">
                              <button (click)="remove()" class="uk-button-danger uk-icon-button uk-icon-button-small">
                                  <icon [flex]="true" ratio="0.8" name="delete"></icon>
                              </button>
                          </div>
                          <div class="uk-margin-small-left">
                              <button class="uk-button-secondary uk-icon-button uk-icon-button-small"
                                      (click)="file.click()">
                                  <icon [flex]="true" ratio="0.8" name="edit"></icon>
                              </button>
                          </div>
                      </div>
                      <!-- Full width error message -->
                      <div *ngIf="uploadError"
                           class="uk-text-danger uk-margin-small-top uk-width-1-1">{{uploadError}}</div>
                  </div>
                  <div class="uk-width-1-1">
                      <div class="uk-grid uk-child-width-expand@m uk-child-width-1-1" uk-grid>
                          <div *ngIf="showVisibility">
                              <div input [formInput]="stakeholderFb.get('visibility')"
                                   [placeholder]="'Select a status'"
                                   [options]="stakeholderUtils.visibilities" type="select"></div>
                          </div>
                          <div [class.uk-width-1-2@m]="!showVisibility && !showFunderType && !canChooseTemplate">
                              <div input [formInput]="stakeholderFb.get('type')"
                                   [placeholder]="'Select a type of ' + entities.stakeholder"
                                   [options]="typesByRole" type="select"></div>
                          </div>
                          <div *ngIf="showFunderType">
                              <div input [formInput]="stakeholderFb.get('funderType')"
                                   [placeholder]="'Select a type of ' + entities.funder"
                                   [options]="stakeholderUtils.funderTypes" type="select"></div>
                          </div>
                          <div *ngIf="canChooseTemplate">
                              <div [placeholder]="'Select a template'"
                                   input [formInput]="stakeholderFb.get('defaultId')"
                                   [options]="defaultStakeholdersOptions" type="select"></div>
                          </div>
                      </div>
                  </div>
              </div>
          </form>
          <div #notify [class.uk-hidden]="!stakeholderFb" notify-form
               class="uk-width-1-1 uk-margin-large-top"></div>
      </div>
  `,
  styleUrls: ['edit-stakeholder.component.less']
})
export class EditStakeholderComponent extends StakeholderBaseComponent {
  @Input()
  public disableAlias: boolean = false;
  public stakeholderFb: UntypedFormGroup;
  public secure: boolean = false;
  public defaultStakeholdersOptions: Option[];
  public defaultStakeholders: Stakeholder[];
  public alias: string[];
  public stakeholder: Stakeholder;
  public isDefault: boolean;
  public isNew: boolean;
  public loading: boolean = false;
  public typesByRole: Option[];
  public statsProfiles: string[];
  /**
   * Photo upload
   * */
  public file: File;
  public photo: string | ArrayBuffer;
  public uploadError: string;
  public deleteCurrentPhoto: boolean = false;
  private maxsize: number = 200 * 1024;
  user: User;
  @ViewChild('notify', {static: true}) notify: NotifyFormComponent;
  private notification: Notification;

  constructor(private fb: UntypedFormBuilder,
              private stakeholderService: StakeholderService,
              private statsProfileService: StatsProfilesService,
              private utilsService: UtilitiesService, private userManagementService: UserManagementService,) {
    super();
  }

  ngOnDestroy() {
    this.reset();
    super.ngOnDestroy();
  }

  public init(stakeholder: Stakeholder, alias: string[], defaultStakeholders: Stakeholder[], isDefault: boolean, isNew: boolean) {
    this.reset();
    this.deleteCurrentPhoto = false;
    this.stakeholder = stakeholder;
    if (this.stakeholderUtils.defaultValue(this.stakeholderUtils.visibilities)) {
      this.stakeholder.visibility = this.stakeholderUtils.defaultValue(this.stakeholderUtils.visibilities);
    }
    this.alias = alias;
    this.defaultStakeholders = defaultStakeholders;
    this.isDefault = isDefault;
    this.isNew = isNew;
    this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => {
      this.user = user;
      if (this.isCurator) {
        this.subscriptions.push(this.statsProfileService.getStatsProfiles().subscribe(statsProfiles => {
          this.statsProfiles = statsProfiles;
        }, error => {
          this.statsProfiles = [];
        }));
      } else {
        this.statsProfiles = [];
      }
      this.typesByRole = this.stakeholderUtils.getTypesByUserRoles(this.user, this.stakeholder.alias);
      this.stakeholderFb = this.fb.group({
        _id: this.fb.control(this.stakeholder._id),
        defaultId: this.fb.control(this.stakeholder.defaultId),
        name: this.fb.control(this.stakeholder.name, Validators.required),
        description: this.fb.control(this.stakeholder.description),
        index_name: this.fb.control(this.stakeholder.index_name, Validators.required),
        index_id: this.fb.control(this.stakeholder.index_id, Validators.required),
        index_shortName: this.fb.control(this.stakeholder.index_shortName),
        statsProfile: this.fb.control(this.stakeholder.statsProfile, Validators.required),
        locale: this.fb.control(this.stakeholder.locale, Validators.required),
        projectUpdateDate: this.fb.control(this.stakeholder.projectUpdateDate),
        creationDate: this.fb.control(this.stakeholder.creationDate),
        alias: this.fb.control(this.stakeholder.alias,
            [
              Validators.required,
              this.stakeholderUtils.aliasValidatorString(
                  this.alias.filter(alias => alias !== this.stakeholder.alias)
              )]
        ),
        isDefault: this.fb.control((this.isDefault)),
        visibility: this.fb.control(this.stakeholder.visibility, Validators.required),
        type: this.fb.control(this.stakeholder.type, Validators.required),
        funderType: this.fb.control(this.stakeholder.funderType),
        topics: this.fb.control(this.stakeholder.topics),
        isUpload: this.fb.control(this.stakeholder.isUpload),
        logoUrl: this.fb.control(this.stakeholder.logoUrl),
      });
      if (this.stakeholder.isUpload) {
        this.stakeholderFb.get('logoUrl').clearValidators();
        this.stakeholderFb.get('logoUrl').updateValueAndValidity();
      } else {
        this.stakeholderFb.get('logoUrl').setValidators([StringUtils.urlValidator()]);
        this.stakeholderFb.get('logoUrl').updateValueAndValidity();
      }
      this.subscriptions.push(this.stakeholderFb.get('isUpload').valueChanges.subscribe(value => {
        if (value == true) {
          this.stakeholderFb.get('logoUrl').clearValidators();
          this.stakeholderFb.updateValueAndValidity();
        } else {
          this.stakeholderFb.get('logoUrl').setValidators([StringUtils.urlValidator()]);
          this.stakeholderFb.updateValueAndValidity();
        }
      }));
      this.secure = (!this.stakeholderFb.get('logoUrl').value || this.stakeholderFb.get('logoUrl').value.includes('https://'));
      this.subscriptions.push(this.stakeholderFb.get('logoUrl').valueChanges.subscribe(value => {
        this.secure = (!value || value.includes('https://'));
      }));
      this.initPhoto();
      this.subscriptions.push(this.stakeholderFb.get('type').valueChanges.subscribe(value => {
        this.onTypeChange(value, defaultStakeholders);
      }));
      this.stakeholderFb.setControl('defaultId', this.fb.control(stakeholder.defaultId, (this.isDefault && !this.isNew) ? [] : Validators.required));
      if (!this.isNew) {
        this.notification = NotificationUtils.editStakeholder(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name);
        this.notify.reset(this.notification.message);
        if (this.isAdmin) {
          if (this.disableAlias) {
            setTimeout(() => {
              this.stakeholderFb.get('alias').disable();
            }, 0);
          }
        } else {
          if (!this.isCurator) {
            setTimeout(() => {
              this.stakeholderFb.get('statsProfile').disable();
            }, 0);
          }
          setTimeout(() => {
            this.stakeholderFb.get('alias').disable();
            this.stakeholderFb.get('index_id').disable();
            this.stakeholderFb.get('index_name').disable();
            this.stakeholderFb.get('index_shortName').disable();
          }, 0);
        }
        setTimeout(() => {
          this.stakeholderFb.get('type').disable();
        }, 0);
      } else {
        this.notification = NotificationUtils.createStakeholder(this.user.firstname + ' ' + this.user.lastname);
        this.notify.reset(this.notification.message);
        setTimeout(() => {
          this.stakeholderFb.get('type').enable();
        }, 0);
      }
    }));
  }

  public get isAdmin() {
    return Session.isPortalAdministrator(this.user);
  }

  public get isCurator() {
    return this.stakeholder && (this.isAdmin || Session.isCurator(this.stakeholder.type, this.user));
  }

  public get disabled(): boolean {
    return (this.stakeholderFb && this.stakeholderFb.invalid) ||
        (this.stakeholderFb && this.stakeholderFb.pristine && !this.isNew && !this.file) ||
        (this.uploadError && this.uploadError.length > 0);
  }

  public get dirty(): boolean {
    return this.stakeholderFb && this.stakeholderFb.dirty;
  }

  public get canChooseTemplate(): boolean {
    return this.isNew && this.stakeholderFb.get('type').valid && !!this.defaultStakeholdersOptions;
  }

  reset() {
    this.uploadError = null;
    this.stakeholderFb = null;
    this.subscriptions.forEach(subscription => {
      if (subscription instanceof Subscription) {
        subscription.unsubscribe();
      }
    });
  }

  onTypeChange(value, defaultStakeholders: Stakeholder[]) {
    this.stakeholderFb.setControl('defaultId', this.fb.control(this.stakeholder.defaultId, (this.isDefault && !this.isNew) ? [] : Validators.required));
    this.defaultStakeholdersOptions = [{
      label: 'New blank profile',
      value: '-1'
    }];
    defaultStakeholders.filter(stakeholder => stakeholder.type === value).forEach(stakeholder => {
      this.defaultStakeholdersOptions.push({
        label: 'Use ' + stakeholder.name + ' profile',
        value: stakeholder._id
      })
    });
  }

  public save(callback: Function, errorCallback: Function = null) {
    this.loading = true;
    if (this.file) {
      this.subscriptions.push(this.utilsService.uploadPhoto(this.properties.utilsService + "/upload/" + encodeURIComponent(this.stakeholderFb.getRawValue().type) + "/" + encodeURIComponent(this.stakeholderFb.getRawValue().alias), this.file).subscribe(res => {
        this.deletePhoto();
        this.stakeholderFb.get('logoUrl').setValue(res.filename);
        this.removePhoto();
        this.saveStakeholder(callback, errorCallback);
      }, error => {
        this.uploadError = "An error has been occurred during upload your image. Try again later";
        this.saveStakeholder(callback, errorCallback);
      }));
    } else if (this.deleteCurrentPhoto) {
      this.deletePhoto();
      this.saveStakeholder(callback, errorCallback);
    } else {
      this.saveStakeholder(callback, errorCallback);
    }
  }

  public saveStakeholder(callback: Function, errorCallback: Function = null) {
    if (this.isNew) {
      let defaultStakeholder = this.defaultStakeholders.find(value => value._id === this.stakeholderFb.getRawValue().defaultId);
      this.stakeholderFb.setValue(this.stakeholderUtils.createFunderFromDefaultProfile(this.stakeholderFb.getRawValue(),
          (defaultStakeholder ? defaultStakeholder.topics : []), this.stakeholderFb.getRawValue().isDefault));
      this.removePhoto();
      if (this.stakeholderFb.getRawValue().isDefault) {
        this.stakeholderFb.get('defaultId').setValue(null);
      }
      this.subscriptions.push(this.stakeholderService.buildStakeholder(this.properties.monitorServiceAPIURL,
        this.stakeholderFb.getRawValue()).subscribe(stakeholder => {
        this.notification.entity = stakeholder._id;
        this.notification.stakeholder = stakeholder.alias;
        this.notification.stakeholderType = stakeholder.type;
        this.notification.groups = [Role.curator(stakeholder.type)];
        this.notify.sendNotification(this.notification);
        NotificationHandler.rise(stakeholder.name + ' has been <b>successfully created</b>');
        callback(stakeholder);
        this.loading = false;
      }, error => {
        NotificationHandler.rise('An error has occurred. Please try again later', 'danger');
        if (errorCallback) {
          errorCallback(error)
        }
        this.loading = false;
      }));
    } else {
      this.subscriptions.push(this.stakeholderService.saveElement(this.properties.monitorServiceAPIURL, this.stakeholderFb.getRawValue()).subscribe(stakeholder => {
        this.notification.entity = stakeholder._id;
        this.notification.stakeholder = stakeholder.alias;
        this.notification.stakeholderType = stakeholder.type;
        this.notification.groups = [Role.curator(stakeholder.type), Role.manager(stakeholder.type, stakeholder.alias)];
        this.notify.sendNotification(this.notification);
        NotificationHandler.rise(stakeholder.name + ' has been <b>successfully saved</b>');
        callback(stakeholder);
        this.loading = false;
      }, error => {
        NotificationHandler.rise('An error has occurred. Please try again later', 'danger');
        if (errorCallback) {
          errorCallback(error)
        }
        this.loading = false;
      }));
    }
  }

  fileChangeEvent(event) {
    if (event.target.files && event.target.files[0]) {
      this.file = event.target.files[0];
      if (this.file.type !== 'image/png' && this.file.type !== 'image/jpeg') {
        this.uploadError = 'You must choose a file with type: image/png or image/jpeg!';
        this.stakeholderFb.get('isUpload').setValue(false);
        this.stakeholderFb.get('isUpload').markAsDirty();
        this.removePhoto();
      } else if (this.file.size > this.maxsize) {
        this.uploadError = 'File exceeds size\'s limit! Maximum resolution is 256x256 pixels.';
        this.stakeholderFb.get('isUpload').setValue(false);
        this.stakeholderFb.get('isUpload').markAsDirty();
        this.removePhoto();
      } else {
        this.uploadError = null;
        const reader = new FileReader();
        reader.readAsDataURL(this.file);
        reader.onload = () => {
          this.photo = reader.result;
          this.stakeholderFb.get('isUpload').setValue(true);
          this.stakeholderFb.get('isUpload').markAsDirty();
        };
      }
    }
  }

  initPhoto() {
    if (this.stakeholderFb.getRawValue().isUpload) {
      this.photo = this.properties.utilsService + "/download/" + this.stakeholderFb.get('logoUrl').value;
    }
  }

  removePhoto() {
    if (this.file) {
      if (typeof document != 'undefined') {
        (<HTMLInputElement>document.getElementById("photo")).value = "";
      }
      this.initPhoto();
      this.file = null;
    }
  }

  remove() {
    this.stakeholderFb.get('isUpload').setValue(false);
    this.stakeholderFb.get('isUpload').markAsDirty();
    this.removePhoto();
    this.stakeholderFb.get('logoUrl').setValue(null);
    if (this.stakeholder.isUpload) {
      this.deleteCurrentPhoto = true;
    }
  }

  public deletePhoto() {
    if (this.stakeholder.logoUrl && this.stakeholder.isUpload) {
      this.subscriptions.push(this.utilsService.deletePhoto(this.properties.utilsService + '/delete/' +
          encodeURIComponent(this.stakeholder.type) + "/" + encodeURIComponent(this.stakeholder.alias) + "/" + this.stakeholder.logoUrl).subscribe());
    }
  }

  get showFunderType() {
    return super.showFunderType && this.stakeholderFb?.get('type').value === 'funder' && !this.isDefault;
  }
}
