import { putSettings } from "../types";
import axios from "axios";
import dotenv from "dotenv";
import factory from "../factory";
import { generateRequestId, handleError, wait } from "../helpers";

dotenv.config();

declare let process: any;

let axiosInstance = axios.create({
  headers: {
    "X-Knack-Application-Id": process.env.KNACK_APP_ID,
    "X-Knack-REST-API-Key": process.env.KNACK_API_KEY,
  },
});

const put = async (settings: putSettings): Promise<any> => {
  const { objectKey, recordId, payload, debug, attempts, host } = settings;

  if (!settings.requestId) settings.requestId = generateRequestId(8);

  const requestId = settings.requestId;

  let state = factory.getState(requestId);

  if (!state) state = factory.initialize(requestId);

  // if a number of attempts was sent in, this will set the number of retries to the attempts. If not, it will set the number of retries to the default 3
  // if it has failed before, it won't update the number of attempts again so that it will decrease properly
  const hasFailed = state.failed;
  hasFailed && attempts && factory.setAttempts(requestId, attempts);

  settings.method = "put";

  factory.setObjectKey(requestId, objectKey);

  recordId && factory.setRecordId(requestId, recordId);

  // if client sends in settings.debug as true, this will tell them the request url
  if (debug)
    console.warn(
      "Request ID:",
      requestId,
      "Request URL:",
      factory.getUrl(requestId, host)
    );

  try {
    axiosInstance.defaults.headers.put["Content-Type"] = "application/json";
    const response = await axiosInstance.put(
      factory.getUrl(requestId, host),
      JSON.stringify(payload)
    );

    factory.remove(requestId);
    return response.data;
  } catch (error) {
    const errorRsp = handleError(factory, requestId, error);
    if (errorRsp?.retry) {
      const waitTime = factory.incrementWaitTime(requestId);
      settings.debug &&
        console.warn(
          "Request ID:",
          requestId,
          `Waiting ${waitTime} milliseconds`
        );
      await wait(waitTime);
      return await put(settings);
    }
    factory.remove(requestId);
    return errorRsp;
  }
};

export default put;
