import { map } from 'rxjs/operators';
import { BehaviorSubject, Observable } from 'rxjs';
import { Injectable, EventEmitter, inject } from '@angular/core';

import { Api } from '../api/api';
import { FunctionService } from '../../app/components/models/function.service';
import { UserModel, LoginEmitter, TaskStatusEmitter, NotificationEmitter } from '../../app/components/models/user.model';

@Injectable({ providedIn: 'root' })
export class AuthenticationService
{
  public currentUser: Observable<UserModel>;
  public sessionEvent: EventEmitter<LoginEmitter>;
  public taskStatusEvent: EventEmitter<TaskStatusEmitter>;
  public notificationEvent: EventEmitter<NotificationEmitter>;
  public atnNotificationEvent: EventEmitter<NotificationEmitter>;
  private readonly currentUserSubject: BehaviorSubject<UserModel>;

  private readonly api = inject(Api);
  private readonly functionService = inject(FunctionService);

  constructor()
  {
    this.sessionEvent = new EventEmitter();
    this.taskStatusEvent = new EventEmitter();
    this.notificationEvent = new EventEmitter();
    this.atnNotificationEvent = new EventEmitter();

    try
    {
      let decString: string = localStorage.getItem('OnlineSalesAutoCrop.currentUser');
      if (decString)
      {
        decString = this.functionService.decrypt(decString);
        this.currentUserSubject = new BehaviorSubject<UserModel>(JSON.parse(decString))
      }
      else
      {
        this.currentUserSubject = new BehaviorSubject<UserModel>(null);
      }
      this.currentUser = this.currentUserSubject.asObservable();
    }
    catch
    {
      localStorage.removeItem('OnlineSalesAutoCrop.currentUser');
    }
  }

  public get currentUserValue(): UserModel
  {
    return this.currentUserSubject?.value;
  }

  public login(params: any)
  {
    try
    {
      return this.api.postAsync<any>('v1/users/login', params)
        .pipe(map(user =>
        {
          user.moduleIds = JSON.parse(this.functionService.decipherData(user.idsValue));
          user.idsValue = '';
          const encString: string = this.functionService.encrypt(JSON.stringify(user));
          localStorage.setItem('OnlineSalesAutoCrop.currentUser', encString);

          this.currentUserSubject.next(user);
          return user;
        }));
    }
    catch
    {
      localStorage.removeItem('OnlineSalesAutoCrop.currentUser');
    }
  }

  public refreshToken()
  {
    try
    {
      const params: any = {};
      return this.api.post('v1/antiForgery/refreshToken', params);      
    }
    catch
    {
      localStorage.removeItem('OnlineSalesAutoCrop.currentUser');
    }
  }

  public loggedIn(resp: any, emit: boolean = true)
  {
    if (emit && resp!.id != 0)
    {
      this.sessionEvent.emit({ userId: resp.id, loggedIn: emit });
    }
  }

  public logout(attendanceLogout: boolean = false, ipAddress: string = '', macAddress: string = '', hostName: string = '', logoutRemarks: string = '')
  {
    try
    {
      if (!this.currentUserValue?.logId)
      {
        localStorage.removeItem('OnlineSalesAutoCrop.currentUser');
        return;
      }

      const params: any = { logId: this.currentUserValue.logId, attendanceLogout: attendanceLogout, ipAddress: ipAddress, macAddress: macAddress, hostName: hostName, logoutRemarks: logoutRemarks };
      return this.api.postAsync<any>('v1/users/logout', params)
        .pipe(map(value =>
        {
          localStorage.removeItem('OnlineSalesAutoCrop.currentUser');
          this.currentUserSubject.next(null);
          return value;
        }));
    }
    catch
    {
      localStorage.removeItem('OnlineSalesAutoCrop.currentUser');
    }
  }

  public loggedout(emit: boolean = true)
  {
    try
    {
      localStorage.removeItem('OnlineSalesAutoCrop.currentUser');
      this.currentUserSubject.next(null);
      Api.clearTmpValue();
      if (emit)
      {
        this.sessionEvent.emit({ userId: 0, loggedIn: false });
      }
    }
    catch
    {
      localStorage.removeItem('OnlineSalesAutoCrop.currentUser');
    }
  }

  public sessionExpired()
  {
    try
    {
      const params: any = { logId: this.currentUserValue.logId };
      return this.api.postAsync<any>('v1/users/sessionExpired', params)
        .pipe(map(value =>
        {
          localStorage.removeItem('OnlineSalesAutoCrop.currentUser');
          this.currentUserSubject.next(null);
          return value;
        }));
    }
    catch
    {
      localStorage.removeItem('OnlineSalesAutoCrop.currentUser');
    }
  }

  public raiseLoginEvent(userId: number, emit: boolean)
  {
    this.sessionEvent.emit({ userId: userId, loggedIn: emit });
  }

  public raiseAtnLoginEvent(raised: boolean)
  {
    this.atnNotificationEvent.emit({ raised: raised });
  }

  public raiseTaskStatusEvent(userId: number, taskStatus: number, teamSpaceId: number)
  {
    this.taskStatusEvent.emit({ userId: userId, taskStatus: taskStatus, teamSpaceId: teamSpaceId });
  } 

  public raiseNotificationEvent(raised: boolean)
  {
    this.notificationEvent.emit({ raised: raised });
  }

  public loadNotificationCount(userId: number)
  {
    const params: any = { userId: userId };
    return this.api.post('v1/users/loadNotificationCount', params);
  }

  public getLoginRemarks(autId: string)
  {
    const params: any = { "authenticationId": autId };
    return this.api.post('v1/paramTypes/getLoginRemarks', params);
  }

  public getLogoutRemarks()
  {
    const params: any = { lookupType:14, excludeItemId: -1};
    return this.api.post('v1/paramTypes/getLookupData', params);
  }
}
