import { isPlatformBrowser } from '@angular/common';
import {
  AfterViewInit,
  Component,
  ElementRef,
  HostListener,
  Inject,
  PLATFORM_ID,
  ViewChild
} from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Router } from '@angular/router';
import {
  AbstractControl,
  FormBuilder,
  Validators,
  ValidationErrors
} from '@angular/forms';
import { StorageMap } from '@ngx-pwa/local-storage';
import { Apollo, gql } from 'apollo-angular';
import { switchMap, tap } from 'rxjs/operators';

import { FlashMessageService } from '../../flash-message/flash-message.service';
import { Level } from '../../flash-message/level';
import { UserService } from '../../user/user.service';

@Component({
  selector: 'app-authentication-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.scss']
})
export class LoginComponent implements AfterViewInit {
  @ViewChild('container', { static: false }) container!: ElementRef;

  public loginForm = this.$fb.group({
    email: ['', Validators.required, Validators.email],
    password: ['', Validators.required, Validators.minLength(8)],
    rememberMe: [false]
  });

  public registerForm = this.$fb.group(
    {
      email: ['', Validators.required, Validators.email],
      firstName: ['', Validators.required],
      lastName: ['', Validators.required],
      phoneNumber: [
        '',
        Validators.required,
        Validators.maxLength(13),
        Validators.pattern(/\d{3}-\d{3}-\d{4}/)
      ],
      password: [
        '',
        Validators.required,
        Validators.minLength(8),
        Validators.pattern(
          /^(?=.*?[A-Z])(?=(.*[a-z])+)(?=(.*\W)+)(?!.*\s).{8,}$/
        )
      ],
      passwordConfirm: [
        '',
        Validators.required,
        Validators.minLength(8),
        Validators.pattern(
          /^(?=.*?[A-Z])(?=(.*[a-z])+)(?=(.*\W)+)(?!.*\s).{8,}$/
        )
      ]
    },
    {
      validators: this.checkPasswords
    }
  );

  public tabIndex = 0;

  constructor(
    @Inject(PLATFORM_ID) private readonly $platformId: any,
    private readonly $router: Router,
    private readonly $fb: FormBuilder,
    private readonly $http: HttpClient,
    private readonly $apollo: Apollo,
    private readonly $storage: StorageMap,
    private readonly $flashMessage: FlashMessageService,
    private readonly $userService: UserService
  ) {}

  @HostListener('window:resize', ['$event'])
  public stretchContainer() {
    if (isPlatformBrowser(this.$platformId)) {
      const navHeight = 49.75;
      const footerHeight = 157.5;
      const windowHeight = window.innerHeight;
      this.container.nativeElement.style = `height: ${
        windowHeight - navHeight - footerHeight
      }px;`;
    }
  }

  public ngAfterViewInit() {
    this.stretchContainer();
  }

  public toggleTabIndex(idx: number) {
    this.tabIndex = idx;
  }

  public submitLoginForm() {
    this.$http
      .post<{ accessToken: string }>(
        '/api/authentication/login',
        this.loginForm.value
      )
      .pipe(
        tap((data) => {
          this.$storage
            .set('accessToken', data.accessToken)
            .subscribe(() => {});
        }),
        switchMap(() => {
          return this.$apollo.query({
            query: gql(`
            {
              user {
                id
                email
                firstName
                lastName
                role
              }
            }
            `)
          });
        }),
        tap(({ data }) => {
          this.$storage.set('user', (data as any).user).subscribe(() => {});
          return this.$userService.update((data as any).user);
        })
      )
      .subscribe({
        next: ({ loading }) => {
          if (!loading) {
            this.$router.navigateByUrl('/');
          }
        },
        error: (error: any) => {
          this.$flashMessage.add(error.message, Level.Danger);
        }
      });
  }

  public submitRegisterForm() {
    this.$http
      .post<{ accessToken: string }>(
        '/api/authentication/register',
        this.registerForm.value
      )
      .pipe(
        tap((data) => {
          this.$storage
            .set('accessToken', data.accessToken)
            .subscribe(() => {});
        }),
        switchMap(() => {
          return this.$apollo.query({
            query: gql(`
              {
                user {
                  id
                  email
                  firstName
                  lastName
                }
              }
            `)
          });
        }),
        tap(({ data }) => {
          this.$storage.set('user', (data as any).user).subscribe(() => {});
          return this.$userService.update((data as any).user);
        })
      )
      .subscribe({
        next: ({ loading }) => {
          if (!loading) {
            this.$router.navigateByUrl('/');
          }
        },
        error: (error: any) => {
          this.$flashMessage.add(error.message, Level.Danger);
        }
      });
  }

  private checkPasswords(group: AbstractControl): ValidationErrors | null {
    const pass = group.get('password')?.value;
    const confirmPass = group.get('passwordConfirm')?.value;

    return pass === confirmPass ? null : { notSame: true };
  }
}
