import { Component, inject, OnInit } from '@angular/core';
import { HttpResponse } from '@angular/common/http';
import { ActivatedRoute, Router } from '@angular/router';
import { Observable, first, Subscription, of } from 'rxjs';
import { finalize, map } from 'rxjs/operators';

import SharedModule from 'app/shared/shared.module';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

import { AlertError } from 'app/shared/alert/alert-error.model';
import { EventManager, EventWithContent } from 'app/core/util/event-manager.service';
import { DataUtils, FileLoadError } from 'app/core/util/data-util.service';
import { IPeriod } from 'app/entities/period/period.model';
import { PeriodService } from 'app/entities/period/service/period.service';
import { IOrganization } from 'app/entities/organization/organization.model';
import { OrganizationService } from 'app/entities/organization/service/organization.service';
import { UploadType } from 'app/entities/enumerations/upload-type.model';
import { UploadStatus } from 'app/entities/enumerations/upload-status.model';
import { InputDataUploadService } from '../service/input-data-upload.service';
import { IInputDataUpload } from '../input-data-upload.model';
import { InputDataUploadFormService, InputDataUploadFormGroup } from './input-data-upload-form.service';
import { ResilientEnvironmentService } from 'app/resilient/resilient-environment/service/resilient-environment.service';
import { AccountService } from 'app/core/auth/account.service';
import { Resources } from 'app/security/resources.model';
import { SecurityAction } from 'app/security/security-action.model';
import { SecurityPermission } from 'app/security/security-permission.model';
import { OrganizationNature } from 'app/entities/enumerations/organization-nature.model';
import { Authority } from 'app/config/authority.constants';
import { PeriodStatus } from 'app/entities/enumerations/period-status.model';

@Component({
  standalone: true,
  selector: 'jhi-input-data-upload-update',
  templateUrl: './input-data-upload-update.component.html',
  imports: [SharedModule, FormsModule, ReactiveFormsModule],
})
export class InputDataUploadUpdateComponent implements OnInit {
  // Properties with defaults by Environment
  ownerOrganizationDefault : IOrganization | null = null;
  subscriptionWorkOrganization!: Subscription;  // Store the subscription
  
  isSaving = false;
  isLoading = false;
  inputDataUpload: IInputDataUpload | null = null;
  uploadStatusValues = Object.keys(UploadStatus);

  periodsSharedCollection: IPeriod[] = [];
  organizationsSharedCollection: IOrganization[] = [];
  uploadTypeValues: string[] = [];

  protected dataUtils = inject(DataUtils);
  protected eventManager = inject(EventManager);
  protected inputDataUploadService = inject(InputDataUploadService);
  protected inputDataUploadFormService = inject(InputDataUploadFormService);
  protected periodService = inject(PeriodService);
  protected organizationService = inject(OrganizationService);
  protected activatedRoute = inject(ActivatedRoute);
  protected accountService = inject(AccountService);
  protected envService = inject(ResilientEnvironmentService);
  protected router = inject(Router);

  // eslint-disable-next-line @typescript-eslint/member-ordering
  editForm: InputDataUploadFormGroup = this.inputDataUploadFormService.createInputDataUploadFormGroup();

  comparePeriod = (o1: IPeriod | null, o2: IPeriod | null): boolean => this.periodService.compareEntity(o1, o2);

  compareOrganization = (o1: IOrganization | null, o2: IOrganization | null): boolean =>
    this.organizationService.compareEntity(o1, o2);

  ngOnInit(): void {
    this.isLoading=true;
	
    this.editForm.get('period')?.valueChanges
      .subscribe(value => {
        this.periodValueChange(value);
      });
	  
    this.activatedRoute.data.subscribe(({ inputDataUpload }) => {
      this.inputDataUpload = inputDataUpload;
      if (inputDataUpload) {
        // Check state of inputDataUpload. Edit is only allowed in UPLOADED state
        if (inputDataUpload.state !== UploadStatus.UPLOADED) {
          //Auto redirect to VIEW mode. With a friendly message explaining the redirect
          this.router.navigate(['/input-data-upload', inputDataUpload.id, 'view'], {
          state: { message: 'O estado do registo não permite a edição.' }
          });
        }
        
        // Editing. Set defaults form HTML form behavior
        this.ownerOrganizationDefault = inputDataUpload.owner;
        
        this.updateForm(inputDataUpload);
        this.loadRelationshipsOptions();	// Load all relations
        
        this.isLoading=false;
      } else {
        // Create a new InputDataUpload
        // Get the currently selected ORGANIZATION, by ResilientEnvironmentService
        this.subscriptionWorkOrganization = this
          .envService
          .selectedWorkOrganization
          /* .pipe(first())		// READS the Observable only once. Doesn't react to later changes on the subscription */
          .subscribe(org => {
            if (org === undefined) {
              //Do nothing.
            } else {
              // If I already have a owner default, ignore user changes
              if (this.ownerOrganizationDefault==null) {
                this.ownerOrganizationDefault = org;
              if(org){
                // Load the Owner Organization list (only this one)
                this.loadRelationshipsOptionsOrganization(org);
              } else {
                this.loadRelationshipsOptionsOrganization(null);
              }
              
              this.loadRelationshipsOptionsPeriod();
              }
            }
          });
        }

    });
  }

  byteSize(base64String: string): string {
    return this.dataUtils.byteSize(base64String);
  }

  openFile(base64String: string, contentType: string | null | undefined): void {
    this.dataUtils.openFile(base64String, contentType);
  }

  setFileData(event: Event, field: string, isImage: boolean): void {
    this.dataUtils.loadFileToForm(event, this.editForm, field, isImage).subscribe({
      error: (err: FileLoadError) =>
        this.eventManager.broadcast(new EventWithContent<AlertError>('resilientApp.error', { ...err, key: 'error.file.' + err.key })),
    });
  }

  previousState(): void {
    window.history.back();
  }

  save(): void {
    this.isSaving = true;
    const inputDataUpload = this.inputDataUploadFormService.getInputDataUpload(this.editForm);
    if (inputDataUpload.id !== null) {
      this.subscribeToSaveResponse(this.inputDataUploadService.update(inputDataUpload));
    } else {
      this.subscribeToSaveResponse(this.inputDataUploadService.create(inputDataUpload));
    }
  }

  periodValueChange(selectedPeriod: any): void {
	
  }
  
  protected subscribeToSaveResponse(result: Observable<HttpResponse<IInputDataUpload>>): void {
    result.pipe(finalize(() => this.onSaveFinalize())).subscribe({
      next: () => this.onSaveSuccess(),
      error: () => this.onSaveError(),
    });
  }

  protected onSaveSuccess(): void {
    this.previousState();
  }

  protected onSaveError(): void {
    // Api for inheritance.
  }

  protected onSaveFinalize(): void {
    this.isSaving = false;
  }

  protected updateForm(inputDataUpload: IInputDataUpload): void {
    this.inputDataUpload = inputDataUpload;
    this.inputDataUploadFormService.resetForm(this.editForm, inputDataUpload);

    this.periodsSharedCollection = this.periodService.addEntityToCollectionIfMissing<IPeriod>(
      this.periodsSharedCollection,
      inputDataUpload.period,
    );
    this.organizationsSharedCollection = this.organizationService.addEntityToCollectionIfMissing<IOrganization>(
      this.organizationsSharedCollection,
      inputDataUpload.owner,
    );
  }

  protected loadRelationshipsOptions(): void {
    this.loadRelationshipsOptionsPeriod();
    this.loadRelationshipsOptionsOrganization(null);
  }
  
  protected loadRelationshipsOptionsPeriod(): void {
	// Only active Period's
    this.periodService
    .queryByState(PeriodStatus.OPENED)
      .pipe(map((res: HttpResponse<IPeriod[]>) => res.body ?? []))
      .pipe(map((periods: IPeriod[]) => this.periodService.addEntityToCollectionIfMissing<IPeriod>(periods, this.inputDataUpload?.period)))
      .subscribe((periods: IPeriod[]) => {
		this.periodsSharedCollection = periods;
		
		// If there's only one, auto-select
		if (this.periodsSharedCollection.length === 1) {
			this.editForm.patchValue({ period: this.periodsSharedCollection[0] });
		}
		this.isLoading=false;
	  });
  }
  
  protected loadRelationshipsOptionsOrganization(organization: IOrganization | null): void {
    this.setUploadTypeValuesCollection();

    this.queryOrganization()
      .pipe(map((res: HttpResponse<IOrganization[]>) => res.body ?? []))
      .pipe(
        map((organizations: IOrganization[]) =>
          this.organizationService.addEntityToCollectionIfMissing<IOrganization>(organizations, this.inputDataUpload?.owner),
        ),
      )
      .subscribe((organizations: IOrganization[]) => {
        this.organizationsSharedCollection = organizations;
      
        if (organization) {
          this.ownerOrganizationDefault = this.organizationsSharedCollection.find(org => org.id === organization.id) ?? null;
          this.editForm.patchValue({ owner: this.ownerOrganizationDefault });
        }
      });
  }

  private setUploadTypeValuesCollection(): void {
    // Distinguish the organization collection, if user has access to ALL or only HIERARCHY
    if (this.accountService.hasAnyAuthority( [Authority.ADMIN, Authority.MANAGER])) {
      this.uploadTypeValues = Object.keys(UploadType);
    } else if (this.accountService.hasAnyAuthority(Authority.COORDINATOR)) {
      this.uploadTypeValues = [UploadType.INVENTORY];
    } else {
      this.uploadTypeValues = [];
    }

    if (this.uploadTypeValues.length == 1) {
      this.editForm.patchValue({ type: this.uploadTypeValues[0] as UploadType});
    }
  }

  private queryOrganization():  Observable<HttpResponse<IOrganization[]>> {
    // Distinguish the organization collection, if user has access to ALL or only HIERARCHY
    let  permission: SecurityPermission = SecurityPermission.NONE;
    if (this.inputDataUpload?.id) {
      permission = this.accountService.getPermission(Resources.INPUT_DATA_UPLOAD, SecurityAction.UPDATE);
    } else {
      permission = this.accountService.getPermission(Resources.INPUT_DATA_UPLOAD, SecurityAction.CREATE);
    }
    
    if (permission === SecurityPermission.ALL) {
      // Access to all
      return this.organizationService.queryByNature(OrganizationNature.ORGANIZATION);
    } if (permission === SecurityPermission.HIERARCHY) {
      // Only user hierarchy
      return this.organizationService.queryByNatureAndHierarchy(OrganizationNature.ORGANIZATION);
    } else {
      // NOTHING
      return of(new HttpResponse({ body: [], status: 200 }));
    }
  }
}
