import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'
import { Injectable, Injector } from '@angular/core'
//import 'rxjs/add/operator/map'
import { Observable, from } from 'rxjs'
import { MermsSessionService } from './../merms-session.service';
//import * as CryptoBrowserify from 'crypto-browserify'
//import { CONFIG } from './app-config'


@Injectable({
  providedIn: 'root'
})
export class MermsServiceProviderService {


  //config = CONFIG[CONFIG.app.environment]()
  //apiKey = this.config.apiKey
  url = '';
  apiKey = 'AMEYE';
  clientId = '1010101010';


  constructor(public http: HttpClient,
    private mermsSessionService: MermsSessionService) {
      this.url="http://api.dev.mermsemr.com"
     }


  genericPostService(endpoint: string, callData: any) {
    if (this.mermsSessionService.session !== '') {
      console.log('***** GENERIC SERVICE CALLED *****')
      // Session & MemberId needed for all - pass in the header
      return this.sendPostRequest('1', '/' + endpoint, callData)
    } else {
      console.log('***** NO SESSION *****')
      return null
    }
  }

  genericGetService(endpoint: string, callData: any) {
    if (this.mermsSessionService.session !== '') {
      console.log('***** GENERIC SERVICE CALLED *****')
      // Session & MemberId needed for all - pass in the header
      return this.sendGetRequest('1', '/' + endpoint, callData)
    } else {
      console.log('***** NO SESSION *****')
      return null
    }
  }


  loginUser(loginData) {
    // this.http.post(this.url + '/userlogin', loginData);
    return this.sendPostRequest('1', '/userlogin', loginData)
  }



  sendGetRequest(grp: string, endPoint: string, sendData: any) {
    // grp - will be used to change URL
    let endpointString = ''
    console.log('GRP->' + grp)
    switch (grp) {
      case '1':
        endpointString = this.url
        break

     
    }
    const httpParams = new HttpParams()
    if (sendData) {
      for (const k in sendData) {
        if (k != null && sendData.hasOwnProperty(k)) {
          httpParams.set(k, sendData[k])
        }
      }
    }
    ;(async () => {
      // const id = Math.floor(100 * Math.random());
      const id = (Math.random() * (10000 - 1000) + 1000).toFixed(0)
      const d1 = new Date()
      console.log('[' + id + '] before semaphore: ' + d1.getTime())
      await this.semaphore(id)
      const d2 = new Date()
      console.log('[' + id + '] after semaphore: ' + d2.getTime())
    })()
    return from(
      new Promise((resolve) => {
        const httpOptions = {
          params: httpParams,
          headers: new HttpHeaders({
            'Content-Type':  'application/json',
            'Access-Control-Allow-Credentials' : 'true',
            'Access-Control-Allow-Origin': '*',
            'Access-Control-Allow-Methods': 'GET, POST, PATCH, DELETE, PUT, OPTIONS',
            'Access-Control-Allow-Headers': 'Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With',
             authorization: 'Token ' + this.apiKey,
            'client_id': this.clientId,
            'x-session-id': this.mermsSessionService.session,
            'x-devicetoken': this.mermsSessionService.access_token,
           
          }),
        }
       // alert(100);
        this.http.get(endpointString + endPoint, httpOptions).subscribe(
          (data) => {
              console.log(data);
             console.log("*************************************************");
            let payload = ''
            if (data != null && data.hasOwnProperty('payload')) {
             
              //   console.log(payload);
            } else {
              payload = JSON.stringify(data)
            }
            let res = {}
            try {
              res = JSON.parse(payload)
            } catch (e) {
              console.log(e)
            }
            if (this.queued > 0) {
              this.queued--
            }

            this.checkSessionValid(res);

            resolve(res)
          },
          (error) => {
            if (this.queued > 0) {
              this.queued--
            }
            resolve(this.getResponseError(error))
          },
          () => {
            console.log('OK!')
          }
        )
      })
    )
  }

  sendPostRequest(grp: string, endPoint: string, sendData: any) {
    // grp - will be used to change URL
    let endpointString = ''
    console.log('GRP->' + grp)
    switch (grp) {
      case '1':
        endpointString = this.url
        break
    }
    ; (async () => {
      // const id = Math.floor(100 * Math.random());
      const id = (Math.random() * (10000 - 1000) + 1000).toFixed(0)
      const d1 = new Date()
      console.log('[' + id + '] before semaphore: ' + d1.getTime())
      await this.semaphore(id)
      const d2 = new Date()
      console.log('[' + id + '] after semaphore: ' + d2.getTime())
    })()
    return from(
      new Promise((resolve) => {
        // this.locationTrackerProvider = this.injector.get(LocationTrackerProvider);
        const httpOptions = {
          headers: new HttpHeaders({
            authorization: 'Token ' + this.apiKey,
            'client_id': this.clientId,
            'x-session-id': this.mermsSessionService.session,
            'x-devicetoken': this.mermsSessionService.access_token,

          }),
        }

        this.http
          .post(endpointString + endPoint, sendData, httpOptions)
          .subscribe(
            (data) => {
              // console.log(data);
              // console.log("*************************************************");
              let payload = ''
              if (data != null && data.hasOwnProperty('payload')) {
                payload = data['payload'];
                //   console.log(payload);
              } else {
                payload = JSON.stringify(data)
              }
              let res = {}
              try {
                res = JSON.parse(payload)
              } catch (e) {
                console.log(e)
              }
              if (this.queued > 0) {
                this.queued--
              }

              this.checkSessionValid(res);

              resolve(res)
            },
            (error) => {
              if (this.queued > 0) {
                this.queued--
              }
              resolve(this.getResponseError(error))
            },
            () => {
              console.log('OK!')
            }
          )
      })
    )
  }


  getResponseError(error) {
    // console.log("Error:" + JSON.stringify(error));
    console.log(error)
    let data = error['error']
    let result = data
    if (data != null && data.hasOwnProperty('payload')) {

    }
    return result
  }

  authUser(authData) {
    return this.sendPostRequest('4', '/auth', authData)
  }
  /*
    encrypt(iv: string, text: string, password: string) {
      const cipher = CryptoBrowserify.createCipheriv('aes-256-ctr', password, iv)
      let crypted = cipher.update(text, 'utf8', 'hex')
      crypted += cipher.final('hex')
      return crypted
    }
  
    decrypt(iv: string, text: string, password: string) {
      const decipher = CryptoBrowserify.createDecipheriv(
        'aes-256-ctr',
        password,
        iv
      )
      let dec = decipher.update(text, 'hex', 'utf8')
      dec += decipher.final('utf8')
      return dec
    }
    */
  /**
 *  Checks if the response from the server returns invalid session error
 * 
 * @param response_data response from the server
 */
  checkSessionValid(response_data: any) {

    if ("session_valid" in response_data) {
      if (response_data['session_valid'] === "INVALID_SESSION") {
        return this.doLogout();
      }
    }

    return true;
  }

  doLogout() {
    // this.floatEventsService.publish('DoLogout', {});
  }


  queued = 0
  lastQueued = 0

  async semaphore(marker: string) {
    console.log('[' + marker + '] inside semaphore: start')
    const cd = new Date()
    const sec = cd.getTime()
    if (this.queued < 0 || sec - this.lastQueued > 10) {
      this.queued = 0
    }
    if (this.lastQueued === 0 || sec - this.lastQueued > 1000) {
      this.lastQueued = sec
      console.log(
        '[' +
        marker +
        '] inside semaphore: wait (queued: ' +
        this.queued +
        ', lastQueued: ' +
        this.lastQueued +
        ')'
      )
      await this.delay(1000)
      console.log(
        '[' +
        marker +
        '] inside semaphore: done (queued: ' +
        this.queued +
        ', lastQueued: ' +
        this.lastQueued +
        ')'
      )
      return
    }
    this.lastQueued = sec
    this.queued++
    console.log(
      '[' +
      marker +
      '] inside semaphore: wait (queued: ' +
      this.queued +
      ', lastQueued: ' +
      this.lastQueued +
      ')'
    )
    await this.delay(1000 + 1000 * this.queued)
    console.log(
      '[' +
      marker +
      '] inside semaphore: done (queued: ' +
      this.queued +
      ', lastQueued: ' +
      this.lastQueued +
      ')'
    )
  }

  delay(ms: number) {
    return new Promise((resolve) => setTimeout(resolve, ms))
  }
}
