import axios from 'axios';
import { Logging } from 'homebridge';
import { AxiosRequestConfig, Method, ResponseType } from 'axios';

const API_TIMEOUT_SECONDS = 10;

/**
 * Handle an axios error
 * @param {Logging} log     The log object to output error
 * @param {any} error       The error thrown
 * @param {string} message  The message to add to the log output
 */
export function handleError(log: Logging | undefined, error: any, message: string, debug = false): void {
  const addendum = 'Troubleshoot here: https://git.io/Jtxww';
  if (error.response) {
    const status = parseInt(error.response.status);
    const errMsg = `${message}: ${status}`;
    if (status >= 500 || status === 404) {
      log?.debug(`${errMsg}\n${addendum}`);
    } else {
      debug ? log?.debug(`${errMsg}\n${addendum}`) : log?.error(`${errMsg}\n${addendum}`);
    }
  } else if (error.code) {
    const errMsg = `${message}: ${error.code}`;
    if (error.code === 'ECONNRESET' || error.code === 'EAI_AGAIN') {
      log?.debug(`${errMsg}\n${addendum}`);
    } else {
      debug ? log?.debug(`${errMsg}\n${addendum}`) : log?.error(`${errMsg}\n${addendum}`);
    }
  } else {
    log?.error(error);
  }
}

/**
 * Class used to communicate with Nest
 * @param {boolean} fieldTestMode Whether or not the account is a field tester
 */
export class NestEndpoints {
  public static USER_AGENT_STRING =
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36';

  public NEST_API_HOSTNAME = 'https://home.nest.com';
  public CAMERA_API_HOSTNAME = 'https://webapi.camera.home.nest.com';
  public CAMERA_AUTH_COOKIE = 'website_2';

  constructor(fieldTestMode: boolean | undefined) {
    if (fieldTestMode) {
      this.NEST_API_HOSTNAME = 'https://home.ft.nest.com';
      this.CAMERA_API_HOSTNAME = 'https://webapi.camera.home.ft.nest.com';
      this.CAMERA_AUTH_COOKIE = 'website_ft';
    }
  }

  /**
   * Send a generic api request
   * @param {string} accessToken  The token used to authenticate request
   * @param {string} hostname     The base uri to send the request
   * @param {string} endpoint     The endpoint to send the request
   * @param {Method} method       Usually 'GET' or 'POST'
   * @param {ResponseType} type   The type of return object (Usually 'json')
   * @param {string} contentType  The content type of the request
   * @param {boolean} timeout     Whether the request should timeout or not
   * @param {any} data            The body of the request or null if a 'GET'
   */
  async sendRequest(
    accessToken: string | undefined,
    hostname: string,
    endpoint: string,
    method: Method,
    type: ResponseType = 'json',
    contentType = '',
    timeout = true,
    data?: any,
  ): Promise<any> {
    const headers: any = {
      'User-Agent': NestEndpoints.USER_AGENT_STRING,
      Referer: this.NEST_API_HOSTNAME,
    };

    if (contentType) {
      headers['Content-Type'] = contentType;
    }

    if (accessToken) {
      headers.Authorization = `Basic ${accessToken}`;
    }

    const url = hostname + endpoint;
    const req: AxiosRequestConfig = {
      method,
      url,
      data,
      headers,
      responseType: type,
      timeout: timeout ? API_TIMEOUT_SECONDS * 1000 : undefined,
    };

    return (await axios(req)).data;
  }
}