import { Component, Input, OnInit } from '@angular/core';
import { MatDialog } from '@angular/material';
import { Store, select } from '@ngrx/store';
import { Observable, of } from 'rxjs';
import * as utils from '@app/degree-planner/shared/utils';

import {
  AddCourse,
  AddSaveForLater,
  MoveCourseBetweenTerms,
  RemoveSaveForLater,
  RemoveCourse,
} from './../../store/actions/course.actions';
import { GlobalState } from '@app/core/state';
import { Course } from '@app/core/models/course';
import * as selectors from '@app/degree-planner/store/selectors';

import { DegreePlannerApiService } from '@app/degree-planner/services/api.service';
import { ConfirmDialogComponent } from '@app/shared/dialogs/confirm-dialog/confirm-dialog.component';
import { CourseDetailsDialogComponent } from '@app/degree-planner/dialogs/course-details-dialog/course-details-dialog.component';
// tslint:disable-next-line:max-line-length
import { RemoveCourseConfirmDialogComponent } from '@app/degree-planner/dialogs/remove-course-confirm-dialog/remove-course-confirm-dialog.component';
import { distinctUntilChanged } from 'rxjs/operators';

@Component({
  selector: 'cse-course-item',
  templateUrl: './course-item.component.html',
  styleUrls: ['./course-item.component.scss'],
})
export class CourseItemComponent implements OnInit {
  @Input() course: Course;
  @Input() isCurrentTerm: boolean;
  @Input() isPastTerm: boolean;
  @Input() disabled: boolean;
  @Input() type: 'saved' | 'course' | 'search';
  visibleTerms: any;
  activeTerm: any;
  status: string;
  public visibleTermCodes$: Observable<string[]>;
  public droppableTermCodes$: Observable<string[]>;

  constructor(
    private api: DegreePlannerApiService,
    public dialog: MatDialog,
    private store: Store<GlobalState>,
  ) {}

  ngOnInit() {
    switch (true) {
      case this.course.studentEnrollmentStatus === 'Enrolled' &&
        this.isCurrentTerm:
        this.status = 'Enrolled';
        break;
      case this.course.studentEnrollmentStatus === 'Waitlisted':
        this.status = 'Waitlisted';
        break;
      case !this.course.grade && this.isPastTerm:
        this.status = 'Incomplete';
        break;
      default:
        this.status = '';
    }
  }

  onMenuOpen() {
    this.droppableTermCodes$ = this.store.pipe(
      select(selectors.selectAllVisibleYears),
      utils.yearsToDroppableTermCodes(),
      distinctUntilChanged(utils.compareStringArrays),
    );
  }

  moveToSavedForLater(course) {
    this.store.dispatch(
      new AddSaveForLater({
        courseId: course.courseId,
        subjectCode: course.subjectCode,
        title: course.title,
        catalogNumber: course.catalogNumber,
        newIndex: 0,
      }),
    );
  }

  /**
   *
   *  Handle moving a course to different terms based on course type
   *
   */
  onMove(termCode: string) {
    switch (this.type) {
      case 'course':
        const { id, termCode: from } = this.course as {
          id: number;
          termCode: string;
        };
        this.store.dispatch(
          new MoveCourseBetweenTerms({ to: termCode, from, id, newIndex: 0 }),
        );
        break;

      case 'saved':
        const { subjectCode, courseId } = this.course;
        this.addToTerm(this.course, termCode);
        this.store.dispatch(new RemoveSaveForLater({ subjectCode, courseId }));
        break;

      case 'search':
        this.addToTerm(this.course, termCode);
        break;
    }
  }

  /**
   *
   *  Handle saving a course for later (This is not possible if a course is already saved)
   *
   */
  onSaveForLater() {
    const {
      courseId,
      subjectCode,
      title,
      catalogNumber,
      termCode,
    } = this.course;

    // Dispatch a save for later event
    this.store.dispatch(
      new AddSaveForLater({
        courseId: courseId,
        subjectCode: subjectCode,
        title: title,
        catalogNumber: catalogNumber,
        newIndex: 0,
      }),
    );

    // If course is in a term, we need to remove it
    if (this.type === 'course') {
      this.store.dispatch(
        new RemoveCourse({
          fromTermCode: termCode,
          recordId: this.course.id as number,
        }),
      );
    }
  }

  /**
   *
   *  Handle removing a course (This is not possible for type 'search')
   *
   */
  onRemove() {
    const dialogOptions = {
      title: 'Remove Course?',
      text: '',
      confirmText: 'Remove Course',
      confirmColor: 'accent',
    };

    switch (this.type) {
      case 'saved':
        dialogOptions.text = `This will remove "${
          this.course.title
        }" from your saved courses.`;
        break;

      default:
        dialogOptions.text = `This will remove "${
          this.course.title
        }" from your degree plan and your cart.`;
    }

    this.dialog
      .open(ConfirmDialogComponent, { data: dialogOptions })
      .afterClosed()
      .subscribe((result: { confirmed: boolean }) => {
        // If the user confirmed the removal, remove course
        if (result.confirmed) {
          switch (this.type) {
            case 'course':
              this.store.dispatch(
                new RemoveCourse({
                  fromTermCode: this.course.termCode,
                  recordId: this.course.id as number,
                }),
              );
              break;

            case 'saved':
              const { subjectCode, courseId } = this.course;
              this.store.dispatch(
                new RemoveSaveForLater({ subjectCode, courseId }),
              );
              break;
          }
        }
      });
  }

  addToTerm(course, term) {
    const { subjectCode, courseId } = course;

    const termCode = term;
    const newIndex = 0;
    this.store.dispatch(
      new AddCourse({ subjectCode, courseId, termCode, newIndex }),
    );
  }

  switchTerm(course, term) {
    const { id, termCode: from } = course;
    const to = term;
    const newIndex = 0;
    this.store.dispatch(new MoveCourseBetweenTerms({ to, from, id, newIndex }));
  }

  openCourseDetailsDialog(course) {
    this.api
      .getCourseDetails(course.subjectCode, course.courseId)
      .subscribe(courseDetails => {
        const dialogRef = this.dialog.open(CourseDetailsDialogComponent, {
          maxWidth: '800px',
          data: { courseDetails: courseDetails },
        });
      });
  }
}