import {Alert, DeviceEventEmitter, Platform} from 'react-native';
import CRYPTO from 'crypto-js';
import DeviceInfo from 'react-native-device-info';
// import AsyncStorage from '@react-native-async-storage/async-storage';

// import ASYNC_STORAGE from '../constants/asyncstorage';
import {checkStringTypeOf} from '../helpers/common';
import constants from '../constants';

const POST = 'post';
const GET = 'get';
const PUT = 'put';
const PATCH = 'patch';
const DELETE = 'delete';
const DEFAULT_ERROR = 'Something went wrong, Please try again later';

let isHandlingSessionExpiration = false;
const SESSION_EXPIRATION_COOLDOWN = 1000; // 1 second cooldown

export const getEncryptedText = (data: any, environment: string) => {
  var truncHexKey = CRYPTO.SHA256(environment.toUpperCase() === 'PROD' ? constants.PROD_ENC_KEY : constants.STAG_ENC_KEY ?? '')
    .toString()
    .substr(0, 32); // hex encode and truncate

  var key = CRYPTO.enc.Utf8.parse(truncHexKey);

  var iv = CRYPTO.enc.Utf8.parse(environment.toUpperCase() === 'PROD' ? constants.PROD_ENC_IV : constants.STAGE_ENC_IV ?? '');

  var ciphertext = CRYPTO.AES.encrypt(JSON.stringify(data), key, {
    iv: iv,
    mode: CRYPTO.mode.CBC,
  });

  return ciphertext.toString();
};

export const getDecryptedData = (cipher: string, environment: string) => {
  var truncHexKey = CRYPTO.SHA256(environment.toUpperCase() === 'PROD' ? constants.PROD_ENC_KEY : constants.STAG_ENC_KEY ?? '')
    .toString()
    .substr(0, 32); // hex encode and truncate

  var key = CRYPTO.enc.Utf8.parse(truncHexKey);

  var iv = CRYPTO.enc.Utf8.parse(environment.toUpperCase() === 'PROD' ? constants.PROD_ENC_IV : constants.STAGE_ENC_IV ?? '');

  var decryptedData = CRYPTO.AES.decrypt(cipher, key, {
    iv: iv,
    mode: CRYPTO.mode.CBC,
  });

  return decryptedData.toString(CRYPTO.enc.Utf8);
};

export const getToken = async () => {
  // try {
  //   const token = await AsyncStorage.getItem(ASYNC_STORAGE?.ACCESS_TOKEN);
  //   if (token !== null) {
  //     // token previously stored
  //     return token;
  //   }
  // } catch (e) {
  //   throw new Error('Token not found or could not be retrieved');
  // }
};

export const handleResponse = async (response: any, isEncrypted: boolean, environment: string) => {
  const contentType = response.headers.get('Content-Type');

  if (contentType) {
    let resp: any = null;
    if (contentType.indexOf('application/json') !== -1) {
      resp = await response.json();
    } else if (contentType && contentType.indexOf('text/html') !== -1) {
      resp = await response.text();
    }

    if (!isEncrypted) return resp;

    const parsed = await JSON.parse(getDecryptedData(resp, environment));
    // const {Auth} = Store.getState();

    if (Number(parsed?.code) == 1) {
      return parsed;
    } else if (parsed?.code == -1) {
      DeviceEventEmitter.emit('session_expired');
      return parsed;
    } else {
      return parsed;
    }
  } else {
    return response.text();
  }
};

const request: any = async (
  route: string,
  {
    baseURL = constants.STAGE_BASE_URL,
    environment = 'uat',
    method = GET,
    payload = null,
    formData = null,
    headers = {} as any,
    json = true,
    priv = true,
    isEncrypted = true,
    content_type = null,
    isVisitEncrypted = false,
  },
) => {
  baseURL = environment.toUpperCase() === 'PROD' ? constants.PROD_BASE_URL : constants.STAGE_BASE_URL
  const activeVersion = DeviceInfo.getVersion(); // return "0.0.2"
  const activeBuildNumber = DeviceInfo.getBuildNumber(); // return 2
  const appVersion = `${Platform.OS} ${activeVersion}-${activeBuildNumber}`;

  console.log("baseee urlss", baseURL)

  let init = {
    method: method,
    headers: {
      'api-key': environment.toUpperCase() === 'PROD' ? constants.PROD_API_KEY : constants.STAGE_API_KEY,
      userFrom: 'GoodFlip', // This has to be set to "PSP" incase of user is from PSP. This will be sent from register API.
      source: 'GoodFlip',
      appVersion: appVersion,
      platform: 'app',
      ...headers,
    },
    body: '',
  };

//   const {Auth} = Store.getState();

  if (formData) {
    init = {
      ...init,
      headers: {
        ...init.headers,
        'content-type': 'multipart/form-data',
      },
      body: formData,
    };
  }

  if (payload) {
    init = {
      ...init,
      headers: {
        ...init.headers,
      },
      body: getEncryptedText(payload, environment),
    };
  }
  if (content_type) init.headers['Content-Type'] = content_type;

//   if (priv && Auth.user.data?.token) {
//     init.headers = {
//       ...init.headers,
//       token: Auth.user.data?.token,
//     };
//   }

  return fetch(`${baseURL}${route}`, init)
    .then(async res => {
      if (res.status === 401) {
        handleSessionExpired();
        throw new Error('Unauthorized');
      }

      if (!json) {
        return res;
      }

      res = await handleResponse(res, isVisitEncrypted ? false : isEncrypted, environment);
      return res;
    })
    .catch(async error => {
      // Remove decryption attempt on error as it may not be encrypted
      if (error.message === 'Unauthorized') {
        // Reject the promise for 401 errors
        throw error;
      }
      throw error; // Re-throw other errors to be handled by the caller
    });
};

const handleError = (error: any, msg = DEFAULT_ERROR) => {
  let errMsg = msg;

  // exception string error
  if (typeof msg === 'string') {
    Alert.alert('Alert', checkStringTypeOf(msg));
    return {
      status: error?.status || 500,
      message: errMsg,
    };
  }

  switch (error?.status) {
    default:
      errMsg = DEFAULT_ERROR;
  }

  Alert.alert('Alert', JSON.stringify(errMsg));
  return {
    status: error?.status,
    message: errMsg,
  };
};

const handleSessionExpired = () => {
  if (isHandlingSessionExpiration) {
    return {
      code: -1,
      message: 'Session expired',
    };
  }

  isHandlingSessionExpiration = true;

  // Use setTimeout to ensure state updates complete before navigation
  setTimeout(() => {
    DeviceEventEmitter.emit('session_expired');
  }, 0);

  // Reset the flag after cooldown period
  setTimeout(() => {
    isHandlingSessionExpiration = false;
  }, SESSION_EXPIRATION_COOLDOWN);

  return {
    code: -1,
    message: 'Session expired',
  };
};


export default {
  POST,
  PUT,
  PATCH,
  GET,
  DELETE,
  request,
  handleResponse,
  handleError,
  getToken,
};
