import axios, { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
import { WHITE_LIST_URLS } from '@/shared/api/urls';
import { StorageKeys } from '@/shared/constants/local-storage';
import { 
  checkIsAxiosError, 
  getLocalStorage, 
  setLocalStorage
} from '@/shared/lib';
import { appBridge } from '@/utils/appBridge';
import { LoginResponse } from '@/entities/user/model/types';
import { getHeaderUserAgent } from '@/shared/constants/url';
import { useAppBridge } from '@/hooks';
import { useUserInfo } from '@/entities/user/lib/use-user-info';
import { useStore } from '@/shared/model/store';
import { login } from '@/entities/user/api/use-login-mutation';
import { useNavigate } from '@/shared/lib/hooks';

const finalizeConfig = (config: InternalAxiosRequestConfig) => {
  const { params, data } = config;
  return {
    ...config,
    params,
    data,
  };
};

const onRequestFulfilled = (config: InternalAxiosRequestConfig) => {
  config.headers['Content-Type'] = 'application/json;charset=UTF-8';
  
  if(!config.headers['X-User-Agent']){
    config.headers['X-User-Agent'] = getHeaderUserAgent();
  }

  if(WHITE_LIST_URLS.includes(config?.url ?? '')){
    if(config.headers.hasOwnProperty('Authorization')){
      delete config.headers.Authorization;
    }
  }
  else{
    const accessToken = getLocalStorage(StorageKeys.AccessToken);
    const tokenType = getLocalStorage(StorageKeys.TokenType);
    config.headers.Authorization = `${tokenType} ${accessToken}`;
  }
  return finalizeConfig(config);
};

const onRequestRejected = (error: any) => {
  console.log('onRequestRejected --> ', error);
  return Promise.reject(error);
};

const onResponseFulfilled = (response: AxiosResponse) => {
  return {
    ...response,
    data: response.data.data || response.data,
  };
};

const onResponseRejected = (error: AxiosError) => {
  console.log('onResponseRejected --> ', error);
  if(error?.status === 401){
    if(appBridge.isNativeEnvironment()){
      return appBridge.safeCall(() => appBridge.requestRefreshToken()).then((token: LoginResponse) => {
        setLocalStorage(StorageKeys.TokenType, token.tokenType);
        setLocalStorage(StorageKeys.AccessToken, token.accessToken);
        setLocalStorage(StorageKeys.RefreshToken, token.refreshToken);
        setLocalStorage(StorageKeys.AccessTokenExpiresIn, token.accessTokenExpiresIn);
        setLocalStorage(StorageKeys.RefreshTokenExpiresIn, token.refreshTokenExpiresIn);
        setLocalStorage(StorageKeys.MenuGrants, token.menuGrants);
        setLocalStorage(StorageKeys.ClientAddressIP, token.clientAddressIP);
        setLocalStorage(StorageKeys.Requires2FA, token.requires2FA);
        setLocalStorage(StorageKeys.Usrid, token.usrid);
      
        if(appBridge.isNativeEnvironment()){
          setLocalStorage(StorageKeys.DeviceId, token.deviceId);
          setLocalStorage(StorageKeys.AppVersion, token.appVersion);
        }
      
        useStore.getState().UserStore.setUserInfo({
          ...token
        });
        return error.config? axios.request(error.config): null;
      });
    }
    else{
      let params = {
        // id: 'woowahan5',
        id: 'nictest00',
        password: 'nictest00'
      };
      return login(params).then((result: LoginResponse) => {
        setLocalStorage(StorageKeys.TokenType, result.tokenType);
        setLocalStorage(StorageKeys.AccessToken, result.accessToken);
        setLocalStorage(StorageKeys.RefreshToken, result.refreshToken);
        setLocalStorage(StorageKeys.AccessTokenExpiresIn, result.accessTokenExpiresIn);
        setLocalStorage(StorageKeys.RefreshTokenExpiresIn, result.refreshTokenExpiresIn);
        setLocalStorage(StorageKeys.MenuGrants, result.menuGrants);
        setLocalStorage(StorageKeys.ClientAddressIP, result.clientAddressIP);
        setLocalStorage(StorageKeys.Requires2FA, result.requires2FA);
        setLocalStorage(StorageKeys.Usrid, params.id);
      
        if(appBridge.isNativeEnvironment()){
          setLocalStorage(StorageKeys.DeviceId, result.deviceId);
          setLocalStorage(StorageKeys.AppVersion, result.appVersion);
        }
      
        useStore.getState().UserStore.setUserInfo({
          ...result
        }); 
        return error.config? axios.request(error.config): null;
      });
      
    }
    
  }
  
  return new Promise((_resolve, reject) => {
    if(checkIsAxiosError(error)){
      // iOS의 경우 window에서 unload event가 일어날때 네트워크 에러가 발생하곤 해서 이런 케이스를 방지하기 위해 지연시킴
      // location.href, location.reload 등으로 unload event가 일어나면 자바스크립트 런타임이 초기화되므로 settimeout으로 인한 네트워크 에러가 트리거 x
      setTimeout(() => {
        reject(error);
      }, 300);
    }
    else{
      reject(error);
    }
  });
};

export const initAxios = () => {
  axios.defaults.withCredentials = false;
  axios.defaults.timeout = 60000;
  axios.defaults.transitional = {
    clarifyTimeoutError: true,
    forcedJSONParsing: true,
    silentJSONParsing: true,
  };
  axios.interceptors.request.use(onRequestFulfilled, onRequestRejected);
  axios.interceptors.response.use(onResponseFulfilled, onResponseRejected);
};
