// @ts-nocheck
import axios from "axios";
import { GetRequiredSecrets, ReplaceAllOccurrences } from "../tool.js";
import { UP, DOWN, DEGRADED, REALTIME, TIMEOUT, ERROR, MANUAL } from "../constants.js";
import * as cheerio from "cheerio";

const defaultEval = `(async function (statusCode, responseTime, responseData) {
	let statusCodeShort = Math.floor(statusCode/100);
    if(statusCode == 429 || (statusCodeShort >=2 && statusCodeShort <= 3)) {
        return {
			status: 'UP',
			latency: responseTime,
        }
    } 
	return {
		status: 'DOWN',
		latency: responseTime,
	}
})`;

class ApiCall {
  monitor;
  envSecrets;

  constructor(monitor) {
    this.monitor = monitor;
    this.envSecrets = GetRequiredSecrets(
      `${monitor.type_data.url} ${monitor.type_data.body} ${JSON.stringify(monitor.type_data.headers)}`,
    );
  }

  async execute() {
    let axiosHeaders = {};
    axiosHeaders["User-Agent"] = "Kener/" + "3.1.0";
    axiosHeaders["Accept"] = "*/*";

    let body = this.monitor.type_data.body;
    let url = this.monitor.type_data.url;

    //headers to string
    let headers = "";
    if (!!this.monitor.type_data.headers) {
      headers = JSON.stringify(this.monitor.type_data.headers);
    }

    let method = this.monitor.type_data.method;
    let timeout = this.monitor.type_data.timeout || 5000;
    let tag = this.monitor.tag;
    let monitorEval = !!this.monitor.type_data.monitorEval ? this.monitor.type_data.monitorEval : defaultEval;

    for (let i = 0; i < this.envSecrets.length; i++) {
      const secret = this.envSecrets[i];
      if (!!body) {
        body = ReplaceAllOccurrences(body, secret.find, secret.replace);
      }
      if (!!url) {
        url = ReplaceAllOccurrences(url, secret.find, secret.replace);
      }
      if (!!headers) {
        headers = ReplaceAllOccurrences(headers, secret.find, secret.replace);
      }
    }

    if (!!headers) {
      try {
        headers = JSON.parse(headers);
        headers = headers.reduce((acc, header) => {
          acc[header.key] = header.value;
          return acc;
        }, {});
        axiosHeaders = { ...axiosHeaders, ...headers };
      } catch (e) {
        console.log(e);
      }
    }

    const options = {
      method: method,
      headers: axiosHeaders,
      timeout: timeout,
      transformResponse: (r) => r,
    };

    if (!!body) {
      options.data = body;
    }
    let statusCode = 500;
    let latency = 0;
    let resp = "";
    let timeoutError = false;
    const start = Date.now();
    try {
      let data = await axios(url, options);
      statusCode = data.status;
      resp = data.data;
    } catch (err) {
      console.log(`Error in apiCall ${tag}`, err.message);
      if (err.message.startsWith("timeout of") && err.message.endsWith("exceeded")) {
        timeoutError = true;
      }
      if (err.response !== undefined && err.response.status !== undefined) {
        statusCode = err.response.status;
      }
      if (err.response !== undefined && err.response.data !== undefined) {
        resp = err.response.data;
      } else {
        resp = JSON.stringify(resp);
      }
    } finally {
      const end = Date.now();
      latency = end - start;
      if (resp === undefined || resp === null) {
        resp = "";
      }
    }

    resp = Buffer.from(resp).toString("base64");

    let evalResp = undefined;

    try {
      evalResp = await eval(monitorEval + `(${statusCode}, ${latency}, "${resp}")`);
    } catch (error) {
      console.log(`Error in monitorEval for ${tag}`, error.message);
    }

    if (evalResp === undefined || evalResp === null) {
      evalResp = {
        status: DOWN,
        latency: latency,
        type: ERROR,
      };
    } else if (
      evalResp.status === undefined ||
      evalResp.status === null ||
      [UP, DOWN, DEGRADED].indexOf(evalResp.status) === -1
    ) {
      evalResp = {
        status: DOWN,
        latency: latency,
        type: ERROR,
      };
    } else {
      evalResp.type = REALTIME;
    }

    let toWrite = {
      status: DOWN,
      latency: latency,
      type: ERROR,
    };
    if (evalResp.status !== undefined && evalResp.status !== null) {
      toWrite.status = evalResp.status;
    }
    if (evalResp.latency !== undefined && evalResp.latency !== null) {
      toWrite.latency = evalResp.latency;
    }
    if (evalResp.type !== undefined && evalResp.type !== null) {
      toWrite.type = evalResp.type;
    }
    if (timeoutError) {
      toWrite.type = TIMEOUT;
    }

    return toWrite;
  }
}

export default ApiCall;
