import * as util from '../utils/util';
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, computed, inject, input, model, output, signal, ViewChild } from "@angular/core";
import { FAST_KENDO_COMMON } from "../../app.config";
import { ChunkSettings, ErrorEvent, FileRestrictions, SuccessEvent, UploadEvent, SelectEvent, UploadComponent, FileInfo } from "@progress/kendo-angular-upload";
import { FastSVGComponent } from './fast-svg.component';

@Component({
  selector: 'fast-upload',
  changeDetection: ChangeDetectionStrategy.OnPush,
  standalone: true,
  imports: [FAST_KENDO_COMMON, FastSVGComponent],
  template: `
  <kendo-upload #uploadElem
    [chunkable]="chunkable()"
    [saveUrl]="saveUrl()"
    [saveField]="saveField()"
    [autoUpload]="autoUpload()"
    [multiple]="multiple()"
    [restrictions]="restrictions()"
    [showFileList]="showFileList()"
    (upload)="upload.emit($event)"
    (success)="success.emit($event)"
    (complete)="complete.emit($event)"
    (error)="errorEvent.emit($event)"
    (select)="internalAttachmentSelect($event)"
    [class]="conditionalClasses()"
    [disabled]="isDisabled()"
    >
  <kendo-upload-messages class="flex flex-col grow" [select]="importText()" [dropFilesHere]="dropFilesHere()">
    @if(!showDropZone()) {
      <fast-svg #importIconElem icon="excelFile" />
    }
  </kendo-upload-messages>
  <ng-content></ng-content>
  </kendo-upload>
  `
})

export class FastUploadComponent implements AfterViewInit {
  @ViewChild("uploadElem") private uploadElem: UploadComponent;

  cdr = inject(ChangeDetectorRef);
  util = util;

  @ViewChild('importIconElem') importIconElem: FastSVGComponent;

  showDropZone = input<boolean>(true);
  chunkable = input<boolean | ChunkSettings>(false);
  saveUrl = input<string>("");
  saveField = input<string>();
  autoUpload = input<boolean>(true);
  multiple = input<boolean>(true);
  restrictions = input<FileRestrictions>();
  showFileList = input<boolean>(false);
  importIcon = input<string>('excelFile');
  upload = output<UploadEvent>();
  errorEvent = output<ErrorEvent>();
  selectEvent = output<SelectEvent>();
  importText = input<string>('Import');
  dropFilesHere = input<string>('Drop files here to upload');
  success = output<SuccessEvent>();
  complete = output<unknown>();
  disabled = model<boolean>(false);

  // Internal signal to track form control disabled state
  private formControlDisabled = signal<boolean>(false);

  // Computed signal that combines input disabled state and form control disabled state
  isDisabled = computed(() => this.disabled() || this.formControlDisabled());

  setDisabledState(isDisabled: boolean) {
    this.formControlDisabled.set(isDisabled);
    this.cdr.markForCheck();
  }

  ngAfterViewInit(): void {
    this.setImportIcon();
  }

  setImportIcon() {
    setTimeout(() => {
      const originalSpan = document.querySelector('.k-upload .k-upload-button span');
      const newElem = this.importIconElem as unknown as HTMLElement;
      if (!newElem || !originalSpan)
        return;

      newElem.hidden = false;
      originalSpan.replaceWith(newElem);
      newElem.after(this.importText());
    }, 100);
  }

  isManuallyAttachingFiles = false;

  addFiles(files: FileInfo[]) {
    this.isManuallyAttachingFiles = true;
    this.uploadElem.addFiles(files);
    setTimeout(() => {
      this.isManuallyAttachingFiles = false;
    }, 100);
  }

  clearFiles() {
    setTimeout(() => {
      this.uploadElem.clearFiles();
      //for some reason focusing and blurring the upload button is needed for the upload display to reliably update after uploadElem.clearFiles
      const uploadButtonElem = this.uploadElem.wrapper.querySelector('.k-upload-button') as HTMLButtonElement;
      uploadButtonElem.focus();
      uploadButtonElem.blur()
    }, 150);
  }

  focus() {
    this.uploadElem.focus();
  }

  protected internalAttachmentSelect(selectEvent: SelectEvent) {
    if (!this.isManuallyAttachingFiles)
      this.selectEvent.emit(selectEvent);
  }

  conditionalClasses = computed(() => {
    const classes = [] as string[];

    classes.push(...this.getCommonClasses());
    classes.push(...this.getLightBaseClasses());
    classes.push(...this.getDarkBaseClasses());
    if (!this.isDisabled()) {
      classes.push(...this.getLightHoverClasses());
      classes.push(...this.getDarkHoverClasses());
      classes.push(...this.getLightActiveClasses());
      classes.push(...this.getDarkActiveClasses());
    }

    const conditionalClasses = this.getConditionalClassesFromArrays(classes);
    return conditionalClasses;
  });

  getConditionalClassesFromArrays(classArray: string[]): { [key: string]: boolean } {
    const classes: { [key: string]: boolean } = {};
    classArray.forEach(className => {
      classes[className] = true;
    });
    return classes;
  }

  // make sure to put classes totally separately, otherwise it will not work (i.e. "flex flex-col h-full" will not work, but "flex" "flex-col" "h-full" will work)
  getCommonClasses() {
    const classes: string[] = [];
    classes.push(
      "flex",
      "flex-row",
      "grow",
      "items-center",
      "[&_.k-dropzone]:w-full",
      "[&_.k-dropzone]:items-center",
      "[&_.k-dropzone]:h-full",
      "[&_.k-dropzone]:flex-col",
      "[&_.k-dropzone]:grow",
      "[&_.k-upload-button-wrap]:flex",
      "[&_.k-upload-button-wrap]:self-start",
      "[&_.k-dropzone-hint]:flex",
      "[&_.k-dropzone-hint]:self-center",
      "[&_.k-dropzone-hint]:items-center",
      "[&_.k-widget.k-upload.k-header]:bg-none",
      "[&_.k-widget.k-upload.k-header]:border-none",
      "[&_button]:flex",
      "[&_button]:grow",
      "[&_button]:m-0",
      "[&_button]:h-7.5",
      "[&_button]:w-28",
      "[&_button]:text-sm",
      "[&_button]:leading-0",
      "[&_button]:border-solid",
      "[&_button]:border-1",
      "[&_button]:rounded-sm",
      "[&_button]:px-2",
      "[&_button]:pb-1",
      "[&_button]:gap-1",
      "[&_button]:items-center",
      "[&_button]:justify-center",
    );
    if (!this.showDropZone()) {
      classes.push(
        "border-none",
        "[&_.k-dropzone]:p-0",
        "[&_.k-dropzone-hint]:hidden",
        "[&_.ng-star-inserted]:hidden",
        "[&_.k-upload-files]:hidden",
        "[&_.k-upload-status]:hidden",
      );
      if (this.isDisabled()) {
        classes.push(
          "cursor-none"
        )
      }
    }
    return classes;
  }
  getLightBaseClasses() {
    return [
      "[&_button]:text-base-black-1000",
      "[&_button]:border-base-gray-1000",
      "[&_button]:bg-gradient-to-b",
      "[&_button]:from-base-white-250",
      "[&_button]:via-base-blue-250",
      "[&_button]:to-base-blue-250",
    ];
  }

  getDarkBaseClasses() {
    return [
      "dark:[&_button]:text-base-white-500",
      "dark:[&_button]:border-alt-white-1000",
      "dark:[&_button]:bg-gradient-to-b",
      "dark:[&_button]:from-alt-blue-250",
      "dark:[&_button]:via-alt-gray-1000",
      "dark:[&_button]:to-alt-blue-750",
    ];
  }

  getLightHoverClasses() {
    return [
      "[&_button]:hover:text-alt-blue-250",
      "[&_button]:hover:border-alt-blue-250",
      "[&_button]:hover:brightness-90",
    ];
  }

  getDarkHoverClasses() {
    return [
      "[&_button]:dark:hover:brightness-150",
      "[&_button]:dark:hover:text-base-blue-250",
      "[&_button]:dark:hover:border-base-blue-250",
    ];
  }

  getLightActiveClasses() {
    return [
      "[&_button]:active:bg-gradient-to-b",
      "[&_button]:active:from-base-blue-250",
      "[&_button]:active:via-base-blue-250",
      "[&_button]:active:to-base-white-250",
      "[&_button]:active:hover:sepia"
    ];
  }

  getDarkActiveClasses() {
    return [
      "dark:[&_button]:active:bg-gradient-to-b",
      "dark:[&_button]:active:from-alt-blue-750",
      "dark:[&_button]:active:via-alt-gray-1000",
      "dark:[&_button]:active:to-alt-blue-250"
    ];
  }
}
