import { Component, ChangeDetectionStrategy, ChangeDetectorRef, ViewChild, ElementRef, ViewEncapsulation, HostListener, inject } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { tap, map, catchError, switchMap, shareReplay, retry } from 'rxjs/operators';
import { of, BehaviorSubject, Subject, combineLatest, zip } from 'rxjs';
import { MessageService } from '../_shared/services/message.service';
import { Validators } from '@angular/forms';
import { CustomFormBuilder } from '../_shared/services/custom-form-builder.service';
import { DialogService, KENDO_DIALOG } from '@progress/kendo-angular-dialog';
import { NotifyService } from '../_shared/services/notify.service';
import { TooltipDirective } from '@progress/kendo-angular-tooltip';
import * as util from '../_shared/utils/util';
import { EmailSettingsService, Detail, RequiredData } from './email-settings.service';
import { FAST_KENDO_COMMON, FAST_PAGE_COMMON } from '../app.config';

@Component({
  selector: 'app-EmailSettings',
  templateUrl: './email-settings.component.html',
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [FAST_PAGE_COMMON, FAST_KENDO_COMMON, KENDO_DIALOG]
})
export class EmailSettingsComponent {
  private service = inject(EmailSettingsService);
  private messageService = inject(MessageService);
  private titleService = inject(Title);
  private fb = inject(CustomFormBuilder);
  private ref = inject(ChangeDetectorRef);
  private dialogService = inject(DialogService);
  private notify = inject(NotifyService);

  @ViewChild("grid", { read: ElementRef }) kendoGridEl: ElementRef;
  @ViewChild('tooltipGrid') tooltipGrid: TooltipDirective;
  @HostListener('window:resize') onResize() {
    //this function is empty but for some reason it helps the window to resize faster
  };

  constructor() {

  }


  detailForm = this.getDetailForm();
  detailTestEmailForm = this.getDetailTestEmailForm()
  detailLoading$ = new BehaviorSubject<boolean>(true)
  refreshRequiredData$ = new BehaviorSubject(null)
  hasModifyPermission = false;
  localRequiredData: RequiredData;
  save$ = new Subject()
  refreshDetail$ = new BehaviorSubject<number>(null)
  mySelection: number[] = [];
  detailInitialValues: Detail = this.detailForm.value as Detail;
  selectedTestEmail: null;
  detailTestEmailOpened$ = new BehaviorSubject<boolean>(false);
  sendTestEmail$ = new Subject()
  sendingTestEmail$ = new Subject<boolean>()

  getDetailForm() {
    const fb = this.fb;
    const fg: util.FormModel<Detail> = fb.group({
      emailSettingsId: fb.ctr(0, Validators.required),
      smtpServer: fb.ctr(null, Validators.required),
      port: fb.ctr(null, Validators.required),
      userName: fb.ctr(null, Validators.required),
      password: fb.ctr(null, Validators.required),
      connectionType: fb.ctr(null, Validators.required)
    });

    return fg;
  }

  getDetailTestEmailForm() {
    const fb = this.fb;
    const fg: util.FormModel<util.NameOnly> = fb.group({
      name: fb.ctr(null, Validators.required)
    });

    return fg;
  }

  requiredData$ = this.refreshRequiredData$.pipe(
    switchMap(refreshType => {
      return combineLatest([this.service.requiredData$, of(refreshType)]);
    }),
    map(([requiredData, refreshType]) => {
      this.localRequiredData = requiredData;
      if (refreshType === util.RefreshType.SelfOnly)
        this.detailLoading$.next(false);
      return requiredData;
    }),
    tap((requiredData) => {
      this.hasModifyPermission = requiredData.hasModifyPermission;
      util.focusInputTarget()
    }),
    shareReplay(1),
    catchError(err => {
      return util.handleError(err, this.messageService)
    }), retry(10)
  )

  localDetailLoading = true;
  detailLoadingWatcher$ = this.detailLoading$.pipe(
    tap(isLoading => {
      this.localDetailLoading = isLoading;
    }),
    shareReplay(1)
  )

  detail$ = this.refreshDetail$.pipe(
    switchMap(id => {
      this.detailLoading$.next(true);
      this.detailForm.disable();
      this.detailForm.reset();
      if (id === 0)
        return of(this.detailInitialValues);
      else
        return this.service.getDetail(id);
    }),
    map(result => {
      const detail: Detail = result;
      if (detail) {
        util.convertToDates(detail);
        this.detailForm.setValue(detail);
      }
      return detail;
    }),
    shareReplay(1),
    catchError(err => {
      return util.handleError(err, this.messageService)
    }), retry(10)
  )

  saveResult$ = this.save$.pipe(
    switchMap(() => {
      this.detailLoading$.next(true);
      this.detailForm.disable();
      const itemToSave: Detail = this.detailForm.value as Detail;
      return this.service.saveDetail(itemToSave);
    }),
    tap(saveResult => {
      this.notify.success('save successful');
      this.mySelection = [saveResult];
      this.detailFinishedLoading();
    }),
    shareReplay(1),
    catchError(err => {
      this.detailFinishedLoading();
      return util.handleError(err, this.messageService)
    }), retry(10)
  )

  detailFinishedLoading(): void {
    this.detailForm.enable();
    this.detailLoading$.next(false);
    util.focusInputTarget();
  }

  save(instance: EmailSettingsComponent): void {
    instance.detailForm.markAllAsTouched();
    if (instance.detailForm.valid)
      instance.save$.next(null);
    else
      instance.notify.error("validation failed");
  }

  sendTestEmailResult$ = this.sendTestEmail$.pipe(
    switchMap(() => {
      const newTestEmailName = (this.detailTestEmailForm.value).name;
      const detail: Detail = this.detailForm.value as Detail;
      return this.service.sendNewTestEmail(detail, newTestEmailName);
    }),
    tap(() => {
      this.sendingTestEmail$.next(false);
      this.detailTestEmailOpened$.next(false);
      this.notify.success('Email Sent');
    }),
    shareReplay(1),
    catchError(err => {
      this.detailTestEmailForm.enable();
      this.sendingTestEmail$.next(false);
      return util.handleError(err, this.messageService)
    }), retry(10)
  )

  openSendTestEmail(): void {
    if (this.hasModifyPermission) {
      this.detailTestEmailForm.enable();
      this.selectedTestEmail = null;
      const newTestEmail: util.NameOnly = { name: null };
      this.detailTestEmailForm.setValue(newTestEmail);
      this.detailTestEmailForm.markAsUntouched();
      this.detailTestEmailOpened$.next(true);
      util.focusInputTarget()
    }
  }

  onDetailTestEmailClosing() {
    this.closeDetailTestEmail(this);
  }

  closeDetailTestEmail(instance: EmailSettingsComponent) {
    instance.detailTestEmailOpened$.next(false);
  }

  sendTestEmail() {
    if (this.detailTestEmailForm.valid) {
      this.sendingTestEmail$.next(true);
      this.detailTestEmailForm.disable();
      this.sendTestEmail$.next(null);
    } else {
      this.notify.error("validation failed");
    }
  }

  title$ = of('Email Settings').pipe(
    tap((title) => util.trySetTitle(this.titleService, title))
  )

  filterConnectionTypes$ = new BehaviorSubject<string>(null)

  connectionTypes$ = this.filterConnectionTypes$.pipe(util.filterIdNames(this.detailLoading$, this.requiredData$, 'connectionTypes'));

  detailAndRequiredData$ = zip(this.detail$, this.requiredData$, this.connectionTypes$).pipe(
    tap(() => {
      this.detailFinishedLoading();
    })
  )
}
