import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import * as _sodium from 'libsodium-wrappers';
import { map } from 'rxjs';
import { apiTemp, public_key, secret_key } from 'src/environments/environment.prod';

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

  constructor(
    private http: HttpClient
  ) { }

  shortEncrypt(encrypted: string){
    return this.postQuery("short-encryption", {string: encrypted}).pipe(map((data: any) => data));
  }

  private encryptOld(valor: string) {
    return (async() => {
      await _sodium.ready;
      const sodium = _sodium;
      var nonce = sodium.randombytes_buf(sodium.crypto_box_NONCEBYTES);
    
      var encoded = sodium.crypto_box_easy(
        valor,
        nonce,
        this.stringToUT8(public_key),
        this.stringToUT8(secret_key)
      );

      var data_json = JSON.stringify(encoded);
      var nonce_json = JSON.stringify(nonce);
  
      let data_base64 = window.btoa(data_json);
      let nonce_base64 = window.btoa(nonce_json);
  
      let enc = window.btoa(data_base64 + '|' + nonce_base64);
  
      return enc;
    })();
  } 

  public encrypt(value: string){
    return (async() => {
      await _sodium.ready;
      const sodium = _sodium;
      var nonce = sodium.randombytes_buf(sodium.crypto_box_NONCEBYTES);

      var encoded = sodium.crypto_box_easy(
        value,
        nonce, 
        this.stringToUT8(public_key),
        this.stringToUT8(secret_key),
      );

      var encoded_string = "";
      encoded.forEach(charCode => {
        let char = String.fromCharCode(charCode);
        encoded_string += char;
      });

      var nonce_string = "";
      nonce.forEach(charCode => {
        let char = String.fromCharCode(charCode);
        nonce_string += char;
      })

      var encoded_base64 = window.btoa(encoded_string);
      var nonce_base64 = window.btoa(nonce_string);

      let enc = window.btoa(encoded_base64 + '|' + nonce_base64);
      return enc;
    })();
  }

  private decryptOld(valor: string) {
    return (async() => {
      await _sodium.ready;
      const sodium = _sodium;

      let valor_base64 = window.atob(valor);
      
      let arrEnc = valor_base64.split('|');
      
      let nonce = window.atob(arrEnc[1]);
      let nonce_arr = JSON.parse(nonce);
      if (typeof nonce_arr == "object") nonce_arr = Object.values(nonce_arr)
      let nonce_final = Uint8Array.from(nonce_arr);
      
      let enc = window.atob(arrEnc[0]);
      let enc_arr = JSON.parse(enc);    
      if (typeof nonce_arr == "object") enc_arr = Object.values(enc_arr)
      let enc_final = Uint8Array.from(enc_arr);
      
      
      var decoded = sodium.crypto_box_open_easy(
        enc_final,
        nonce_final,
        this.stringToUT8(public_key),
        this.stringToUT8(secret_key)
      );
      
      let decoder = new TextDecoder();
      let dec = decoder.decode(decoded);

      return dec;
    })();
  }

  public decrypt(value: string){
    return(async() => {
      await _sodium.ready;
      const sodium = _sodium;

      let value_string = window.atob(value);
      let value_array = value_string.split('|');

      let encoded_string = window.atob(value_array[0]);
      let nonce_string = window.atob(value_array[1]);

      let encoded_array = [];
      for(let i = 0; i < encoded_string.length; i++){
        let char = encoded_string.charCodeAt(i);
        encoded_array.push(char);
      }

      let nonce_array = [];
      for(let i = 0; i < nonce_string.length; i++){
        let char = nonce_string.charCodeAt(i);
        nonce_array.push(char);
      }

      let encoded_utf8 = new Uint8Array(encoded_array);
      let nonce_utf8 = new Uint8Array(nonce_array);
      
      var decoded = sodium.crypto_box_open_easy(
        encoded_utf8,
        nonce_utf8,
        this.stringToUT8(public_key),
        this.stringToUT8(secret_key)
      );
      
      let decoder = new TextDecoder();
      let decoded_string = decoder.decode(decoded);
      
      return decoded_string;
    })();
  }


  private stringToUT8(key: string): Uint8Array {
    let pk_dec = window.atob(key);
    let arr_enc = [];

    for (let index = 0; index < pk_dec.length; index++) {
      arr_enc.push(pk_dec.charCodeAt(index));
    }

    var arr = new Uint8Array(arr_enc);
    return arr;
  }

  private UT8ToString(arr: Uint8Array): string {
    let dec: string = '';
    arr.forEach((element) => {
      dec += String.fromCharCode(element);
    });
    return dec;
  }

  postQuery(query: string, body: any){
    const URL = `${apiTemp}${query}`;
    return this.http.post(URL, body);
  }
}
