import { StartSendingAudit } from './../store/actions';
import { MediaMatcher } from '@angular/cdk/layout';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { AuditMetadata, AuditMetadataMap } from '../models/audit-metadata';
import { MatDialog, MatSnackBar } from '@angular/material';
import { DARSState } from '../store/state';
import { Store } from '@ngrx/store';
import { GlobalState } from '@app/core/state';
import * as selectors from '../store/selectors';
import { Observable, Subscription } from 'rxjs';
import * as darsActions from '../store/actions';
import { Alert } from '@app/core/models/alert';
import {
  NewDegreeAuditDialogComponent,
  NewDegreeAuditFields,
} from '../new-degree-audit-dialog/new-degree-audit-dialog.component';
import {
  NewWhatIfAuditDialogComponent,
  NewWhatIfAuditFields,
} from '../new-what-if-audit-dialog/new-what-if-audit-dialog.component';
import { shareReplay, distinctUntilChanged, map } from 'rxjs/operators';
import { WebsocketService } from '@app/shared/services/websocket.service';

const flattenAndSortMetadataMap = (metadataMap: AuditMetadataMap) => {
  return (Object.values(metadataMap) as AuditMetadata[]).sort((a, b) => {
    if (a.darsAuditRunDate > b.darsAuditRunDate) {
      return 1;
    } else if (a.darsAuditRunDate < b.darsAuditRunDate) {
      return -1;
    } else {
      return 0;
    }
  });
};

@Component({
  selector: 'cse-dars-view',
  templateUrl: './dars-view.component.html',
  styleUrls: ['./dars-view.component.scss'],
})
export class DARSViewComponent implements OnInit, OnDestroy {
  public metadataStatus$: Observable<DARSState['metadata']['status']>;
  public programWaiting$: Observable<{ outstanding: number; pending: number }>;
  public programMetadata$: Observable<AuditMetadata[]>;
  public whatIfWaiting$: Observable<{ outstanding: number; pending: number }>;
  public whatIfMetadata$: Observable<AuditMetadata[]>;
  public mobileView: MediaQueryList;
  public alerts$: Observable<Alert[]>;
  public messageSub: Subscription;

  constructor(
    private store: Store<GlobalState>,
    public dialog: MatDialog,
    public mediaMatcher: MediaMatcher,
    websocketService: WebsocketService,
    private snackBar: MatSnackBar,
  ) {
    this.mobileView = mediaMatcher.matchMedia('(max-width: 959px)');
    this.messageSub = websocketService.messages.subscribe(message => {
      const newMessage = JSON.parse(message);
      if (newMessage && newMessage.type === 'auditStatus') {
        this.store.dispatch(
          new darsActions.RefreshMetadata({
            callback: () => this.snackBar.open('Audit Complete'),
          }),
        );
      }
    });
  }

  public ngOnInit() {
    this.store.dispatch(new darsActions.StartLoadingDARSView());
    this.metadataStatus$ = this.store.select(selectors.metadataStatus);
    this.programWaiting$ = this.store.select(
      selectors.outstandingAndPendingPrograms,
    );
    this.programMetadata$ = this.store.select(selectors.programMetadata).pipe(
      distinctUntilChanged(),
      map(flattenAndSortMetadataMap),
      shareReplay(),
    );
    this.whatIfWaiting$ = this.store.select(
      selectors.outstandingAndPendingWhatIf,
    );
    this.whatIfMetadata$ = this.store.select(selectors.whatIfMetadata).pipe(
      distinctUntilChanged(),
      map(flattenAndSortMetadataMap),
      shareReplay(),
    );
    this.alerts$ = this.store.select(selectors.alerts);
  }

  public ngOnDestroy() {
    this.messageSub.unsubscribe();
  }

  public onDismissAlert(key: string) {
    this.store.dispatch(new darsActions.DismissAlert({ key }));
  }

  public openDegreeAuditDialog() {
    const subscription = this.dialog
      .open<any, any, NewDegreeAuditFields>(NewDegreeAuditDialogComponent, {
        panelClass: this.mobileView.matches ? 'dialog-fullscreen' : '',
      })
      .afterClosed()
      .subscribe(event => {
        subscription.unsubscribe();
        if (event) {
          return this.store.dispatch(
            new StartSendingAudit({
              auditType: 'program',
              darsInstitutionCode: event.darsInstitutionCode,
              darsDegreeProgramCode: event.darsDegreeProgramCode,
              degreePlannerPlanName: event.degreePlannerPlanName,
              whichEnrolledCoursesIncluded: event.whichEnrolledCoursesIncluded,
              darsHonorsOptionCode: event.darsHonorsOptionCode,
            }),
          );
        }
      });
  }

  public openWhatIfAuditDialog() {
    const subscription = this.dialog
      .open<any, any, NewWhatIfAuditFields>(NewWhatIfAuditDialogComponent, {
        panelClass: this.mobileView.matches ? 'dialog-fullscreen' : '',
      })
      .afterClosed()
      .subscribe(event => {
        subscription.unsubscribe();
        if (event) {
          return this.store.dispatch(
            new StartSendingAudit({
              auditType: 'whatIf',
              darsInstitutionCode: event.darsInstitutionCode,
              darsDegreeProgramCode: event.darsDegreeProgramCode,
              degreePlannerPlanName: event.degreePlannerPlanName,
              whichEnrolledCoursesIncluded: event.whichEnrolledCoursesIncluded,
              darsHonorsOptionCode: event.darsHonorsOptionCode,
            }),
          );
        }
      });
  }
}