import {ChangeDetectionStrategy, ChangeDetectorRef, Component, computed, DestroyRef, inject,} from '@angular/core';
import {ToastrService} from 'ngx-toastr';
import {distinctUntilChanged, tap} from 'rxjs';
import {ThemeService} from 'src/app/_services/theme.service';
import {SiteTheme, ThemeProvider} from 'src/app/_models/preferences/site-theme';
import {User} from 'src/app/_models/user/user';
import {AccountService} from 'src/app/_services/account.service';
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
import {SentenceCasePipe} from '../../_pipes/sentence-case.pipe';
import {NgTemplateOutlet} from '@angular/common';
import {translate, TranslocoDirective} from "@jsverse/transloco";
import {CarouselReelComponent} from "../../carousel/_components/carousel-reel/carousel-reel.component";
import {ImageComponent} from "../../shared/image/image.component";
import {DownloadableSiteTheme} from "../../_models/theme/downloadable-site-theme";
import {DefaultValuePipe} from "../../_pipes/default-value.pipe";
import {ScrobbleProvider} from "../../_services/scrobbling.service";
import {ConfirmService} from "../../shared/confirm.service";
import {FileSystemFileEntry, NgxFileDropEntry, NgxFileDropModule} from "ngx-file-drop";
import {ReactiveFormsModule} from "@angular/forms";
import {LoadingComponent} from "../../shared/loading/loading.component";
import {PreviewImageModalComponent} from "../../shared/_components/carousel-modal/preview-image-modal.component";
import {ModalService} from "../../_services/modal.service";
import {
  FileDragAndDropUploadComponent
} from "src/app/shared/file-drag-and-drop-upload/file-drag-and-drop-upload.component";

interface ThemeContainer {
  downloadable?: DownloadableSiteTheme;
  site?: SiteTheme;
  isSiteTheme: boolean;
  name: string;
}

@Component({
    selector: 'app-theme-manager',
    templateUrl: './theme-manager.component.html',
    styleUrls: ['./theme-manager.component.scss'],
    changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [SentenceCasePipe, TranslocoDirective, CarouselReelComponent,
    ImageComponent, DefaultValuePipe, NgTemplateOutlet, NgxFileDropModule,
    ReactiveFormsModule, LoadingComponent, FileDragAndDropUploadComponent]
})
export class ThemeManagerComponent {
  private readonly destroyRef = inject(DestroyRef);
  protected readonly themeService = inject(ThemeService);
  protected readonly accountService = inject(AccountService);
  private readonly toastr = inject(ToastrService);
  private readonly cdRef = inject(ChangeDetectorRef);
  private readonly confirmService = inject(ConfirmService);
  private readonly modalService = inject(ModalService);

  protected readonly ThemeProvider = ThemeProvider;
  protected readonly ScrobbleProvider = ScrobbleProvider;

  currentTheme: SiteTheme | undefined;
  user: User | undefined;
  selectedTheme: ThemeContainer | undefined;
  downloadableThemes: DownloadableSiteTheme[] = [];
  downloadedThemes: SiteTheme[] = [];

  canUseThemes = computed(() => !this.accountService.hasReadOnlyRole());

  files: NgxFileDropEntry[] = [];
  acceptableExtensions = ['.css'].join(',');
  isUploadingTheme: boolean = false;

  constructor() {

    this.themeService.themes$.pipe(tap(themes => {
      this.downloadedThemes = themes;
      this.cdRef.markForCheck();
    })).subscribe();

    this.loadDownloadableThemes();

    this.themeService.currentTheme$.pipe(takeUntilDestroyed(this.destroyRef), distinctUntilChanged()).subscribe(theme => {
      this.currentTheme = theme;
      this.cdRef.markForCheck();
    });

  }

  loadDownloadableThemes() {
    this.themeService.getDownloadableThemes().subscribe(d => {
      this.downloadableThemes = d;
      this.cdRef.markForCheck();
    });
  }

  async deleteTheme(theme: SiteTheme) {
    if (!await this.confirmService.confirm(translate('toasts.confirm-delete-theme'))) {
      return;
    }

    this.themeService.deleteTheme(theme.id).subscribe(_ => {
      this.removeDownloadedTheme(theme);
      this.loadDownloadableThemes();
    });
  }

  removeDownloadedTheme(theme: SiteTheme) {
    this.selectedTheme = undefined;
    this.downloadableThemes = this.downloadableThemes.filter(d => d.name !== theme.name);
    this.cdRef.markForCheck();
  }

  applyTheme(theme: SiteTheme) {
    const user = this.accountService.currentUser();
    if (!user) return;

    // Updating theme emits the new theme to load on the themes$
    const pref = Object.assign({}, user.preferences);
    pref.theme = theme;
    this.accountService.updatePreferences(pref).subscribe();
  }

  updateDefault(theme: SiteTheme) {
    this.themeService.setDefault(theme.id).subscribe(() => {
      // TODO: Refactor this key to be in toasts
      this.toastr.success(translate('theme-manager.updated-toastr', {name: theme.name}));
    });
  }

  selectTheme(theme: SiteTheme | DownloadableSiteTheme | undefined) {
    if (theme === undefined) {
      this.selectedTheme = undefined;
      return;
    }

    if (theme.hasOwnProperty('provider')) {
      this.selectedTheme = {
        isSiteTheme: true,
        site: theme as SiteTheme,
        name: theme.name
      };
    } else {
      this.selectedTheme = {
        isSiteTheme: false,
        downloadable: theme as DownloadableSiteTheme,
        name: theme.name
      };
    }

    this.cdRef.markForCheck();
  }

  downloadTheme(theme: DownloadableSiteTheme) {
    this.themeService.downloadTheme(theme).subscribe(downloadedTheme => {
      this.removeDownloadedTheme(downloadedTheme);
      this.themeService.getThemes().subscribe(themes => {
        this.downloadedThemes = themes;
        const oldTheme = this.downloadedThemes.filter(d => d.name === theme.name)[0];
        this.selectTheme(oldTheme);
        this.cdRef.markForCheck();
      });

    });
  }

  public dropped(files: NgxFileDropEntry[]) {
    this.files = files;
    this.isUploadingTheme = true;
    this.cdRef.markForCheck();

    for (const droppedFile of files) {
      if (!droppedFile.fileEntry.isFile) continue;
      const fileEntry = droppedFile.fileEntry as FileSystemFileEntry;

      fileEntry.file((file: File) => {
        this.themeService.uploadTheme(file, droppedFile).subscribe(t => {
          this.isUploadingTheme = false;
          this.downloadedThemes.push(t);
          this.selectTheme(t);
          this.cdRef.markForCheck();
        });
      });
    }
  }

  previewImage(imgUrl: string) {
    if (imgUrl === '') return;

    const ref = this.modalService.open(PreviewImageModalComponent);
    ref.setInput('title', this.selectedTheme!.name);
    ref.setInput('image', imgUrl);
  }
}
