import {
  Component,
  OnInit,
  Input,
  ChangeDetectorRef,
  ChangeDetectionStrategy,
  Output,
  EventEmitter,
  OnDestroy,
  ViewRef,
} from '@angular/core';
import { FormGroup, FormBuilder, Validators, AbstractControl } from '@angular/forms';
import { Select, Store } from '@ngxs/store';
import { take, takeUntil } from 'rxjs/operators';
import { BehaviorSubject, Observable, Subject } from 'rxjs';
import { SetUserDetails } from '../../../../core/store/actions/customer.actions';
import { CustomValidators } from '../../../../shared/validation/custom-validation';
import { SharedSelectors } from '../../../../core/store/selectors/shared.selectors';
import { User } from '../../../../core/models/user.model';

import { ProcessSelectors } from 'apps/sales/src/app/core/store/selectors/process.selectors';
import { SetCustomerNotificationFlag } from 'apps/sales/src/app/core/store/actions/process.actions';

@Component({
  selector: 'app-notification-settings',
  templateUrl: './notification-settings.component.html',
  styleUrls: ['./notification-settings.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class NotificationSettingsComponent implements OnInit, OnDestroy {
  notificationForm: FormGroup;
  editMode = false;
  customer: User;
  _isDelivery: boolean;
  serverErrors$ = new BehaviorSubject(null);
  submitted$ = new BehaviorSubject(null);
  private destroy$ = new Subject();

  @Select(SharedSelectors.currentCustomer) customer$: Observable<User>;

  @Input() set isDelivery(isDelivery: boolean) {
    this._isDelivery = isDelivery;
    this.notificationForm = this.buildNotificationForm(this.fb);
    this.notificationForm.disable();
    this.processData();

    // When delivery item in cart, email is required
    if (isDelivery) {
      this.setEmailNotification();
    }

    this.detectChanges();
  }

  get isDelivery() {
    return this._isDelivery;
  }

  @Output() notificationInEditMode = new EventEmitter<boolean>();

  constructor(private fb: FormBuilder, private store: Store, private cdr: ChangeDetectorRef) {}

  ngOnInit() {
    if (this.customer) {
      const updateUserData = { ...this.customer };
      const customerFlag = this.store.selectSnapshot(ProcessSelectors.getCurrentProcessCustomerNotificationFlag);
      if (!customerFlag) {
        updateUserData.notificationSms = false;
        updateUserData.notificationEmail = false;
        if (this.customer.email) {
          this.notificationForm.get('email.selected').setValue(true);
          updateUserData.notificationEmail = true;
        } else {
          this.notificationForm.get('email.selected').setValue(false);
          updateUserData.notificationEmail = this.isDelivery;
        }
        if (this.customer.mobile_number) {
          this.notificationForm.get('sms.selected').setValue(true);
          updateUserData.notificationSms = true;
        } else {
          this.notificationForm.get('sms.selected').setValue(false);
          updateUserData.notificationSms = false;
        }
        if (
          this.customer.notificationSms !== updateUserData.notificationSms ||
          this.customer.notificationEmail !== updateUserData.notificationEmail
        ) {
          this.store.dispatch(new SetUserDetails(updateUserData, false));
        }
        this.store.dispatch(new SetCustomerNotificationFlag(true));
      } else {
        this.notificationForm.get('email.selected').setValue(this.customer.notificationEmail);
        this.notificationForm.get('sms.selected').setValue(this.customer.notificationSms);
      }
      this.detectChanges();
    }
  }

  ngOnDestroy(): void {
    this.destroy$.next();
  }

  edit() {
    if (this.customer) {
      this.notificationForm.enable();
      this.setEditMode(true);
    }
  }

  save() {
    if (!this.customer) {
      return;
    }
    // If valid update, else cancel editing
    const sms = this.selected('sms');
    const email = this.selected('email');
    if ((this.notificationForm.get('sms.telephone').valid || !sms) && (this.notificationForm.get('email.email').valid || !email)) {
      const updateUserData = { ...this.customer };
      updateUserData.notificationSms = sms;
      updateUserData.notificationEmail = email || this.isDelivery;
      this.store
        .dispatch(new SetUserDetails(updateUserData, false))
        .pipe(take(1))
        .subscribe(() => {
          if (this.customer.error) {
            return;
          }
          this.patchVariable(this.submitted$, { email: false, phone: false });
          this.setEditMode(false);
        });
    }
  }

  savePhone() {
    if (!this.customer) {
      return;
    }
    const phoneField = this.notificationForm.get('sms.telephone');

    if (phoneField.valid) {
      const c = {
        ...this.customer,
        mobile_number: phoneField.value,
        notificationSms: this.selected('sms'),
      };
      this.store
        .dispatch(new SetUserDetails(c, false))
        .pipe(take(1))
        .subscribe(() => {
          this.patchVariable(this.serverErrors$, {
            phone: this.customer.error
              ? this.customer.error.error.message || this.customer.error.error.invalidProperties.PhoneNumber || this.customer.error.message
              : null,
          });
          if (this.customer.error) {
            return;
          }
          this.patchVariable(this.submitted$, { phone: false });
        });
    } else {
      this.patchVariable(this.submitted$, { phone: true });
    }
  }

  saveEmail() {
    if (!this.customer) {
      return;
    }
    const emailField = this.notificationForm.get('email.email');

    if (emailField.valid) {
      const c = {
        ...this.customer,
        email: emailField.value,
        notificationEmail: this.selected('email') || this.isDelivery,
      };
      this.store
        .dispatch(new SetUserDetails(c, false))
        .pipe(take(1))
        .subscribe(() => {
          this.patchVariable(this.serverErrors$, {
            email: this.customer.error
              ? this.customer.error.error.message || this.customer.error.error.invalidProperties.Email || this.customer.error.message
              : null,
          });
          if (this.customer.error) {
            return;
          }
          this.patchVariable(this.submitted$, { email: false });
        });
    } else {
      this.patchVariable(this.submitted$, { email: true });
    }
  }

  onInputChange(value: string, type: string) {
    if (!value) {
      this.patchVariable(this.submitted$, { [type]: false });
    }
    this.patchVariable(this.serverErrors$, { [type]: null });
  }

  buttonDisabled(typeField: string, typeServerError: string) {
    return !this.notificationForm.get(typeField).valid || (this.serverErrors$.value && this.serverErrors$.value[typeServerError]);
  }

  validSms(control: AbstractControl) {
    if (control.value && control.value.selected && !control.get('telephone').valid) {
      return { invalidSms: true };
    }
    return null;
  }

  displayed(type: string) {
    return this.editMode || this.selected(type);
  }

  selected(type: string) {
    return this.notificationForm.get(type + '.selected').value;
  }

  update(val, type: string) {
    if (!val) {
      this.patchVariable(this.submitted$, { [type === 'email' ? type : 'phone']: false });
    }

    this.notificationForm.get(type + '.selected').setValue(val);
  }

  setEmailNotification() {
    if (this.customer) {
      // If delivery type, then email is mandatory
      const updateUserData = { ...this.customer };
      updateUserData.notificationEmail = true;
      this.store.dispatch(new SetUserDetails(updateUserData, false));
    }
  }

  private buildNotificationForm(fb: FormBuilder) {
    return fb.group({
      sms: fb.group(
        {
          selected: false,
          telephone: fb.control('', { validators: [Validators.required, CustomValidators.validateTelephone] }),
        },
        { validators: this.validSms }
      ),
      email: fb.group({
        selected: this.isDelivery,
        email: fb.control('', { validators: [Validators.required, CustomValidators.validateEmail] }),
      }),
    });
  }

  private processData() {
    this.customer$.pipe(takeUntil(this.destroy$)).subscribe((c: User) => {
      const first = !this.customer;
      this.customer = c;
      if (!c || !first) {
        return;
      }
      if (c.email && c.notificationEmail) {
        this.notificationForm.get('email.selected').setValue(true);
        this.notificationForm.get('email').disable();
      } else {
        this.notificationForm.get('email.selected').setValue(false);
      }
      if (c.mobile_number && c.notificationSms) {
        this.notificationForm.get('sms.selected').setValue(true);
        this.notificationForm.get('sms').disable();
      } else {
        this.notificationForm.get('sms.selected').setValue(false);
      }
      this.notificationForm.get('sms.telephone').setValue(this.customer.mobile_number ? this.customer.mobile_number : '');
      this.notificationForm.get('email.email').setValue(this.customer.email ? this.customer.email : '');
    });
  }

  private patchVariable(item: BehaviorSubject<{}>, patch: {}) {
    if (!item || !patch) {
      return;
    }
    item.next({
      ...item.value,
      ...patch,
    });
  }

  private setEditMode(mode: boolean) {
    this.editMode = mode;
    this.notificationInEditMode.emit(mode);
  }

  detectChanges() {
    setTimeout(() => {
      if (this.cdr !== null && this.cdr !== undefined && !(this.cdr as ViewRef).destroyed) {
        this.cdr.detectChanges();
      }
    }, 0);
  }
}
