import { Component, ChangeDetectionStrategy, ChangeDetectorRef, ViewEncapsulation, Output, EventEmitter, Input, OnInit } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { tap, map, catchError, switchMap, shareReplay, retry } from 'rxjs/operators';
import { BehaviorSubject, Subject, Observable } from 'rxjs';
import { MessageService } from '../../_shared/services/message.service';
import { FormsModule, UntypedFormBuilder } from '@angular/forms';
import { DialogService } from '@progress/kendo-angular-dialog';
import { NotifyService } from '../../_shared/services/notify.service';
import * as util from '../../_shared/utils/util';
import { SosSettingsService, DisplayInfo, SosSettingItem, AllDisplayInfos, PipeAndDefaultSettings } from './sos-settings.service';
import { SortDescriptor } from '@progress/kendo-data-query';
import { DrawerItem, DrawerSelectEvent, KENDO_DRAWER } from '@progress/kendo-angular-layout';
import { FAST_KENDO_COMMON, FAST_PAGE_COMMON } from '../../app.config';
import { KENDO_DROPDOWNLIST } from '@progress/kendo-angular-dropdowns';
import { KENDO_SORTABLE } from '@progress/kendo-angular-sortable';

export interface localSettings {
  fontSize: number;
  mainOrderables: DisplayInfo[];
  transferOrderables: DisplayInfo[];
  sorts: SortDescriptor[];
  mainFrozenColCount: number;
  transferFrozenColCount: number;
}

@Component({
  selector: 'app-sos-crude-settings[pipeId][pipeName]',
  templateUrl: './sos-settings.component.html',
  styleUrls: ['./sos-settings.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
  imports: [FAST_PAGE_COMMON, FAST_KENDO_COMMON, FormsModule, KENDO_DROPDOWNLIST, KENDO_DRAWER, KENDO_SORTABLE]
})
export class SosSettingsComponent implements OnInit {
  @Input() pipeId: number
  @Input() pipeName: string
  @Output() closed = new EventEmitter<SosSettingItem>()

  util = util
  icons = util.icons
  editorOpened = false
  isAddNew: boolean
  expanded = true
  hasValueCount = 0

  pipeLocals: localSettings = {
    fontSize: 0,
    mainOrderables: [],
    transferOrderables: [],
    sorts: [],
    mainFrozenColCount: 0,
    transferFrozenColCount: 0
  }

  defaultLocals: localSettings = {
    fontSize: 0,
    mainOrderables: [],
    transferOrderables: [],
    sorts: [],
    mainFrozenColCount: 0,
    transferFrozenColCount: 0
  }

  mainFrozenColCounts: number[] = [];
  transferFrozenColCounts: number[] = [];
  fontSizes: number[] = [];
  saveTypes: util.IdName[] = [];
  pipeSettings: SosSettingItem;
  defaultSettings: SosSettingItem;
  selectedDrawerText: string;
  settingDrawerItems: DrawerItem[];

  loading$ = new BehaviorSubject<boolean>(true)
  refreshSettings$ = new BehaviorSubject<string>(null)
  saveSettings$ = new Subject<string>()
  allDisplayInfos$: Observable<AllDisplayInfos>
  allMainColumnDisplayInfos$: Observable<DisplayInfo[]>
  allTransferColumnDisplayInfos$: Observable<DisplayInfo[]>
  settings$: Observable<PipeAndDefaultSettings>
  saveResult$: Observable<SosSettingItem>

  constructor(private messageService: MessageService, private titleService: Title, private service: SosSettingsService, private fb: UntypedFormBuilder, private ref: ChangeDetectorRef, private dialogService: DialogService, private notify: NotifyService) {
    this.allDisplayInfos$ = this.service.getAllColumnDisplayInfos().pipe(
      shareReplay(1),
      catchError(err => {
        return util.handleError(err, this.messageService)
      }), retry(10)
    );

    this.allMainColumnDisplayInfos$ = this.allDisplayInfos$.pipe(
      map(allColumnDisplayInfos => {
        return allColumnDisplayInfos.allMainColumnDisplayInfos;
      })
    );

    this.allTransferColumnDisplayInfos$ = this.allDisplayInfos$.pipe(
      map(allColumnDisplayInfos => {
        return allColumnDisplayInfos.allTransferColumnDisplayInfos;
      })
    );

    this.settings$ = this.refreshSettings$.pipe(
      tap(() => {
        this.loading$.next(true);
      }),
      switchMap(() => {
        return this.service.getSettings(this.pipeId);
      }),
      tap((result) => {
        this.pipeLocals.fontSize = result.pipeSettings.fontSize;
        this.pipeLocals.mainFrozenColCount = result.pipeSettings.mainFrozenColumnCount;
        this.pipeLocals.transferFrozenColCount = result.pipeSettings.transferFrozenColumnCount;
        this.pipeLocals.mainOrderables = [...result.pipeSettings.mainDisplayInfos];
        this.pipeLocals.transferOrderables = [...result.pipeSettings.transferDisplayInfos];
        this.pipeLocals.sorts = result.pipeSettings.sorts;

        this.defaultLocals.fontSize = result.defaultSettings.fontSize;
        this.defaultLocals.mainFrozenColCount = result.defaultSettings.mainFrozenColumnCount;
        this.defaultLocals.transferFrozenColCount = result.defaultSettings.transferFrozenColumnCount;
        this.defaultLocals.mainOrderables = [...result.defaultSettings.mainDisplayInfos];
        this.defaultLocals.transferOrderables = [...result.defaultSettings.transferDisplayInfos];
        this.defaultLocals.sorts = result.defaultSettings.sorts;

        this.loading$.next(false);
      }),
      shareReplay(1),
      catchError(err => {
        return util.handleError(err, this.messageService)
      }), retry(10)
    )

    this.saveResult$ = this.saveSettings$.pipe(
      tap(() => {
        this.loading$.next(true);
      }),
      switchMap(() => {
        this.pipeSettings = {
          fontSize: this.pipeLocals.fontSize,
          mainFrozenColumnCount: this.pipeLocals.mainFrozenColCount,
          mainDisplayInfos: this.pipeLocals.mainOrderables,
          transferFrozenColumnCount: this.pipeLocals.transferFrozenColCount,
          transferDisplayInfos: this.pipeLocals.transferOrderables,
          sorts: this.pipeLocals.sorts
        };

        this.defaultSettings = {
          fontSize: this.defaultLocals.fontSize,
          mainFrozenColumnCount: this.defaultLocals.mainFrozenColCount,
          mainDisplayInfos: this.defaultLocals.mainOrderables,
          transferFrozenColumnCount: this.defaultLocals.transferFrozenColCount,
          transferDisplayInfos: this.defaultLocals.transferOrderables,
          sorts: this.defaultLocals.sorts
        };

        const settings: PipeAndDefaultSettings = { pipeSettings: this.pipeSettings, defaultSettings: this.defaultSettings };
        return this.service.saveSettings(settings, this.pipeId); //this is the loaded pipeId, not the one in the settings object
      }),
      tap(saveSettingResult => {
        SosSettingsComponent.getAdjustedSettings(saveSettingResult);
        this.closed.emit(saveSettingResult);
        this.loading$.next(false);
        this.notify.success('settings saved');
      }),
      shareReplay(1),
      catchError(err => {
        this.loading$.next(false);
        return util.handleError(err, this.messageService);
      })
    )

    this.settingDrawerItems = [
      { text: 'Pipeline Settings', icon: '', selected: true },
      { text: 'Default Settings', icon: '', selected: false },
    ];
    this.selectedDrawerText = this.settingDrawerItems[0].text;
  }

  static getAdjustedSettings(settings: SosSettingItem) {
    this.resetDisplayOrders(settings.mainDisplayInfos);
    this.resetDisplayOrders(settings.transferDisplayInfos);

    //for each hidden column before the first visible column, reduce the frozen column count
    let mainFrozenColCountReduction = 0;
    settings.mainDisplayInfos.filter(x => !x.isVisible).forEach(x => {
      if (x.order <= settings.mainFrozenColumnCount)
        mainFrozenColCountReduction++;
    });
    settings.mainFrozenColumnCount -= mainFrozenColCountReduction;

    let transferFrozenColCountReduction = 0;
    settings.transferDisplayInfos.filter(x => !x.isVisible).forEach(x => {
      if (x.order <= settings.transferFrozenColumnCount)
        transferFrozenColCountReduction++;
    });
    settings.transferFrozenColumnCount -= transferFrozenColCountReduction;

    settings.mainDisplayInfos = settings.mainDisplayInfos.filter(x => x.isVisible);
    settings.transferDisplayInfos = settings.transferDisplayInfos.filter(x => x.isVisible);

    this.resetDisplayOrders(settings.mainDisplayInfos);
    this.resetDisplayOrders(settings.transferDisplayInfos);

    return settings;
  }

  static resetDisplayOrders(displayInfos: DisplayInfo[]) {
    let newOrderNum: number = 1;
    displayInfos.forEach(x => x.order = newOrderNum++);
  }

  ngOnInit(): void {
    for (let i = 8; i <= 20; i++)
      this.fontSizes.push(i);
    for (let i = 0; i <= 10; i++)
      this.mainFrozenColCounts.push(i);
    for (let i = 1; i <= 10; i++)
      this.transferFrozenColCounts.push(i);

    this.saveTypes = [{ id: this.pipeId, name: 'This Pipeline' }, { id: null, name: 'All Pipelines' }];
  }

  closeSettings(): void {
    this.closed.emit(null);
  }

  isDrawerItemSelected(drawerItemStr: string): boolean {
    let isSelected = false;
    if (drawerItemStr === this.selectedDrawerText)
      isSelected = true;

    return isSelected
  }

  onDrawerSelection($event: DrawerSelectEvent) {
    this.selectedDrawerText = $event.item.text;
  }

  copyDefaults() {
    this.pipeLocals.fontSize = this.defaultLocals.fontSize;
    this.pipeLocals.mainFrozenColCount = this.defaultLocals.mainFrozenColCount;
    this.pipeLocals.transferFrozenColCount = this.defaultLocals.transferFrozenColCount;
    this.pipeLocals.mainOrderables = [...this.defaultLocals.mainOrderables];
    this.pipeLocals.transferOrderables = [...this.defaultLocals.transferOrderables];
    this.pipeLocals.sorts = [...this.defaultLocals.sorts];
    this.notify.success('settings updated. save to keep changes');
  }
}
