//import { CliTerseError } from '@alwaysai/alwayscli';
import {
  SystemInformationShadowUpdate,
  validateSystemInformationShadowUpdate,
  getReportedFromMessage
} from '@alwaysai/device-agent-schemas';
import { v4 as uuidv4 } from 'uuid';
import { CliAuthenticationClient } from '../infrastructure/authentication-client';
import { serviceEndpointBuilder } from '../infrastructure/urls';
import { logger } from './';

export interface SecureTunnelPorts {
  enabled: boolean;
  type: string;
  port: number;
  ip: string;
}

interface Shadow {
  txId: string;
  responseType: string;
  payload: {
    code?: number;
    message?: string;
    state?: {
      desired?: { st_ports?: SecureTunnelPorts[] };
      reported?: { st_ports?: SecureTunnelPorts[] };
    };
    version?: number;
    timestamp?: number;
  };
}

export enum HttpStatusCode {
  OK = 200,
  FORBIDDEN = 403
}

export const getShadow = async (thingId: string) => {
  const idTokenAuthorizationHeader =
    await CliAuthenticationClient().getIdAuthorizationHeader();
  const requestURL = serviceEndpointBuilder('device-shadow', 'GetThingShadow');
  const body = {
    deviceUuid: thingId,
    shadowName: 'secure-tunnel',
    txId: uuidv4()
  };

  logger.debug('getShadow body: ', body);

  const response = await fetch(requestURL, {
    method: 'post',
    body: JSON.stringify(body),
    headers: {
      ...idTokenAuthorizationHeader,
      'Content-Type': 'application/json'
    }
  });

  if (!response) {
    const errorMsg = 'Error: Receiving response from server';
    logger.error(errorMsg);
    throw new Error(errorMsg);
  }

  // if (response.status !== HttpStatusCode.OK) {
  //   const errorMsg = `Error, response.status = ${response.status}`;
  //   logger.error(errorMsg);
  //   throw new Error(errorMsg);
  // }

  const readerStream = Buffer.from(await response.arrayBuffer());
  const parsedJson = JSON.parse(readerStream.toString());

  return parsedJson as Shadow;
};

interface UpdateThingShadow {
  txtId: string;
  responseType: string;
  payload: {
    state: any;
    version: number;
    timestamp: number;
  };
}

export const updateShadow = async (thingId: string, payload) => {
  const idTokenAuthorizationHeader =
    await CliAuthenticationClient().getIdAuthorizationHeader();
  const requestURL = serviceEndpointBuilder(
    'device-shadow',
    'UpdateThingShadow'
  );
  const body = {
    deviceUuid: thingId,
    shadowName: 'secure-tunnel',
    txId: uuidv4(),
    payload
  };

  logger.debug('updateShadow body: ', body);

  const response = await fetch(requestURL, {
    method: 'post',
    body: JSON.stringify(body),
    headers: {
      ...idTokenAuthorizationHeader,
      'Content-Type': 'application/json'
    }
  });

  if (!response) {
    const errorMsg = 'Error: Receiving response from server';
    logger.error(errorMsg);
    throw new Error(errorMsg);
  }

  if (response.status !== HttpStatusCode.OK) {
    const errorMsg = `Error, response.status = ${response.status}`;
    logger.error(errorMsg);
    throw new Error(errorMsg);
  }

  const readerStream = Buffer.from(await response.arrayBuffer());
  const parsedJson = JSON.parse(readerStream.toString());

  return parsedJson as UpdateThingShadow;
};

export async function getSystemInfoShadow(
  thingId: string
): Promise<SystemInformationShadowUpdate> {
  const idTokenAuthorizationHeader =
    await CliAuthenticationClient().getIdAuthorizationHeader();
  const requestURL = serviceEndpointBuilder('device-shadow', 'GetThingShadow');
  const body = {
    deviceUuid: thingId,
    shadowName: 'system-info',
    txId: uuidv4()
  };

  const response = await fetch(requestURL, {
    method: 'post',
    body: JSON.stringify(body),
    headers: {
      ...idTokenAuthorizationHeader,
      'Content-Type': 'application/json'
    }
  });

  if (!response) {
    const errorMsg = 'Error: Receiving response from server';
    logger.error(errorMsg);
    throw new Error(errorMsg);
  }

  if (response.status !== HttpStatusCode.OK) {
    const errorMsg = `Error, response.status = ${response.status}`;
    logger.error(errorMsg);
    throw new Error(errorMsg);
  }

  const readerStream = Buffer.from(await response.arrayBuffer());
  const parsedJson = JSON.parse(readerStream.toString());
  const reported = getReportedFromMessage(parsedJson.payload);
  const valid = validateSystemInformationShadowUpdate(reported);

  if (!valid) {
    const errorMsg = 'Invalid system info shadow';
    logger.error(errorMsg);
    logger.error(JSON.stringify(validateSystemInformationShadowUpdate.errors));
    // FIXME: Skip validation until disk size provided as string issue is fixed
    //throw new CliTerseError(errorMsg);
  }

  return reported;
}
