import { UIColumn } from './../data/grid/ui-column';
import { UIPictures } from '../pictures/ui-pictures';
import { bindable, autoinject, customElement, bindingMode, BindingEngine, processContent, children } from 'aurelia-framework';
import { EnumerationTypeService } from '../../services/enumeration-type-service';
import { Disposable, observable } from 'aurelia-binding';
import { PictureHelper } from './picture-helper';
import { IFile, UIFilesColumnInfo } from '../../model/common-model';
import { Config } from '../../config';
import { RemoteFileStorage } from '../../services/file-storage-service';

@autoinject
@customElement('ui-files')
@children({ name: 'customColumns', selector: ['ui-column'] })
@processContent((compiler, resources, node, instruction) => {
  instruction.inheritBindingContext = true;
  return true;
})
export class UIFiles {
  private fileTypeService: EnumerationTypeService;

  @bindable({ bindingMode: bindingMode.twoWay }) files: FileType[];
  @bindable({ bindingMode: bindingMode.twoWay }) enumerationCategory: number;
  @bindable({ bindingMode: bindingMode.twoWay }) enumerationDisplayPropertyName: string = 'fileType';
  @bindable({ bindingMode: bindingMode.twoWay }) enumerationIdPropertyName: string = 'fileTypeId';
  @bindable({ bindingMode: bindingMode.oneTime }) fileAddedFn: () => {};
  @bindable({ bindingMode: bindingMode.oneTime }) fileUploadedFn: () => {};
  @bindable({ bindingMode: bindingMode.oneTime }) confirmUploadFn: () => boolean | Promise<boolean>;
  @bindable({ bindingMode: bindingMode.oneTime }) uploadCompleteFn: () => {};
  @bindable({ bindingMode: bindingMode.oneTime }) accept: string = 'all';
  @bindable({ bindingMode: bindingMode.twoWay }) folderName: string;
  @bindable({ bindingMode: bindingMode.twoWay }) canAdd: boolean = true;
  @bindable({ bindingMode: bindingMode.twoWay }) canEdit: boolean = true;
  @bindable({ bindingMode: bindingMode.twoWay }) canDownload: boolean = true;
  @bindable({ bindingMode: bindingMode.twoWay }) canDelete: boolean = false;
  @bindable({ bindingMode: bindingMode.oneTime }) deleteFileFn: () => {};
  @bindable({ bindingMode: bindingMode.oneTime }) deleteFilesFn: () => {};
  @bindable({ bindingMode: bindingMode.oneTime }) massiveDownloadFn: () => {};
  @bindable({ bindingMode: bindingMode.twoWay }) selectedFiles: FileType[];
  @bindable({ bindingMode: bindingMode.twoWay }) isSelectable: boolean = false;
  @bindable({ bindingMode: bindingMode.twoWay }) acceptSelectable: string = 'all';

  @bindable({ bindingMode: bindingMode.oneTime }) columnsInfo: Array<UIFilesColumnInfo>;
  @bindable({ bindingMode: bindingMode.oneTime }) autoConvert = false;

  @bindable({ bindingMode: bindingMode.twoWay }) dropZoneMode: 'Top' | 'Inner' | 'None' = 'Inner';
  @bindable({ bindingMode: bindingMode.oneTime }) public designWithBorder: boolean = false;
  @bindable({ bindingMode: bindingMode.oneTime }) uploadBtn: HTMLElement;
  @bindable({ bindingMode: bindingMode.oneTime }) uploadBtnPosition: 'Auto' | 'Custom' = "Auto";
  @bindable({ bindingMode: bindingMode.oneTime }) ignoreFileExistence: boolean = false;
  @bindable({ bindingMode: bindingMode.oneTime }) useVirtualization: boolean = false;

  customColumns: Array<UIColumn> = [];

  @observable public currentSearch: string;

  private filesSearched: FileType[] = [];

  private disposables: Disposable[] = [];
  filesObserver: Disposable;

  constructor(private bindingEngine: BindingEngine, private pictureHelper: PictureHelper, private config: Config, private fileStorageService: RemoteFileStorage.Service) {
    this.fileTypeService = new EnumerationTypeService(this.enumerationCategory);
  }

  public showColumn(columnName: string) {
    if (this.columnsInfo == null || this.columnsInfo.length == 0) return true;

    const i = this.columnsInfo.findIndex(x => x.columnName == columnName);
    if (i > -1) {
      return this.columnsInfo[i].columnVisibility;
    }
    return true;
  }

  public getWidthColumn(columnName: string) {
    if (this.columnsInfo == null || this.columnsInfo.length == 0) return true;
    const i = this.columnsInfo.findIndex(x => x.columnName == columnName);
    if (i > -1) {
      return this.columnsInfo[i].width ?? 1;
    }
    return 1;
  }

  public enumerationCategoryChanged(newVal, oldVal) {
    this.fileTypeService.gridDataSource.queryParameters = { category: this.enumerationCategory, onlyActifs: true };
  }

  bind() {
    this.fileTypeService.gridDataSource.queryParameters = { category: this.enumerationCategory, onlyActifs: true };
    if (this.columnsInfo == null || this.columnsInfo?.length == 0) {
      this.columnsInfo = this.config.globalConfig.defaultUIFilesColumnsInfo;
    } else {
      this.config.globalConfig.defaultUIFilesColumnsInfo.forEach((defaultName) => {
        const i = this.columnsInfo.findIndex(x => x.columnName == defaultName.columnName);
        if (i == -1) {
          this.columnsInfo.push(defaultName);
        }
      });
    }
    if (this.selectedFiles == null) {
      this.selectedFiles = [];
    }

    if (this.canDownload && !this.fileStorageService.canDownloadFiles) {
      this.canDownload = false;
    }
  }

  public attached() {
    this.disposables.forEach(d => d.dispose());
    this.disposables.splice(0);

    this.files.forEach(file => {
      if (this.isSelectable) {
        this.addObserverIsSelected(file);
      }
      file['enumerationDisplay'] = file[this.enumerationDisplayPropertyName];
      file['enumerationId'] = file[this.enumerationIdPropertyName];
    });

    this.disposables.push(
      this.bindingEngine.collectionObserver(this.files).subscribe(changeRecords => {
        if (changeRecords.length > 0 && changeRecords[0].addedCount > 0) {
          let index = changeRecords[0].index;
          while (index < this.files.length) {
            let file = this.files[index];
            if (this.isSelectable) {
              this.addObserverIsSelected(file);
            }
            file['enumerationDisplay'] = file[this.enumerationDisplayPropertyName];
            file['enumerationId'] = file[this.enumerationIdPropertyName];

            index++;
          }
        }
      })
    );

    this.disposables.push(
      this.bindingEngine.collectionObserver(this.files).subscribe(changeRecords => {
        this.resetFilteredFiles();
      })
    );
    this.resetFilteredFiles();
  }

  private addObserverIsSelected(file: FileType) {
    if (file.extension == null) {
      file.extension = this.pictureHelper.getFileExtension(file.url);
    }
    file.isSelectable = (this.acceptSelectable == 'all' || this.acceptSelectable.includes(file.extension));

    let observer = this.bindingEngine.propertyObserver(file, 'isSelected');
    let disposable = observer.subscribe((newVal, oldVal) => {
      if (newVal === true) {
        this.selectedFiles.push(file);
      }
      else {
        this.selectedFiles.remove(file);
      }
    });
    this.disposables.push(disposable);
  }

  public detached() {
    this.disposables.forEach(d => d.dispose());
  }

  private resetFilteredFiles() {
    if (this.filesSearched != null) {
      this.filesSearched.splice(0);
    } else {
      this.filesSearched = [];
    }
    if (this.currentSearch != null && this.currentSearch.trim()?.length > 0) {
      this.filesSearched.push(...this.files.filter(file => file.name?.toUpperCase().includes(this.currentSearch.toUpperCase()) || file.description?.toUpperCase().includes(this.currentSearch.toUpperCase())));
    } else {
      this.filesSearched.push(...this.files);
    }

  }

  public currentSearchChanged(n, o) {
    if (n != o) {
      this.resetFilteredFiles();
    }
  }
}

declare interface FileType extends IFile {
  extension: string;
  isSelectable: boolean;
  isSelected: boolean;
}
export const UIFilesComponents = [UIFiles, UIPictures];
