import axios from 'axios';

import Spotlight from '@enact/spotlight';
import { useDispatch } from 'react-redux';
import { useState } from 'react';
import { fetchCurrentUserHomeTermsSafe } from '../actions/homeActions';

import { types } from '../actions/actionTypes';
import {
  changeAppStatus,
  changeLocalSettings,
  setShowPopup,
  setSystemNotice,
  setSystemTermination,
  showError,
} from '../actions/commonActions';
import {
  getAuthenticationCode,
  getReAuthenticationCode,
} from '../actions/deviceActions';
import {
  pushPanel,
  resetPanels,
} from '../actions/panelActions';
import * as Config from '../utils/Config';
import { ACTIVE_POPUP } from '../utils/Config';
import * as HelperMethods from '../utils/helperMethods';
import {
  getUrl,
  URLS,
} from './apiConfig';

let tokenRefreshing = false;
const axiosQueue = [];

export const setTokenRefreshing = (value) => {
  console.log("TAxios setTokenRefreshing ", value);
  tokenRefreshing = value;
};
export const runDelayedAction = (dispatch, getState) => {
  console.log("runDelayedAction axiosQueue size", axiosQueue.length);
  while (axiosQueue.length > 0) {
    const requestConfig = axiosQueue.shift(); // queue에서 요청을 하나씩 shift
    TAxios(
      dispatch,
      getState,
      requestConfig.type,
      requestConfig.baseUrl,
      requestConfig.urlParams,
      requestConfig.params,
      requestConfig.onSuccess,
      requestConfig.onFail
    );
  }
};
export const TAxios = (
  dispatch,
  getState,
  type,
  baseUrl,
  urlParams = {},
  params = {},
  onSuccess,
  onFail,
  noTokenRefresh = false
) => {
  const pushQueue = () => {
    if (!noTokenRefresh) {
      axiosQueue.push({ type, baseUrl, urlParams, params, onSuccess, onFail });
    }
  };

  const decodeMessage = (apiSysMessage) => {
    try {
      const decodedBase64 = atob(apiSysMessage);
      const decodedText = new TextDecoder("utf-8").decode(
        new Uint8Array(decodedBase64.split("").map((c) => c.charCodeAt(0)))
      );
      return decodedText;
    } catch (error) {
      console.error("Decoding error:", error);
      return apiSysMessage;
    }
  };

  const executeRequest = (accessToken) => {
    const httpHeader = getState().common.httpHeader;
    const { mbr_no, deviceId } = getState().common.appStatus;
    const refreshToken = getState().localSettings.refreshToken;
    const AUTHORIZATION = { headers: { ...httpHeader } };

    if (accessToken) {
      AUTHORIZATION.headers["lgsp_auth"] = accessToken;
    }
    AUTHORIZATION.headers["dvc_id"] = deviceId;
    AUTHORIZATION.headers["refresh_token"] = refreshToken;

    if (typeof window === "object") {
      let url = Array.isArray(baseUrl)
        ? getUrl(getState, baseUrl[0])
        : getUrl(getState, baseUrl);

      if (!url) {
        //todo error page
        return;
      }
      if (type === "get") {
        const _urlparams = HelperMethods.createQueryString(urlParams);
        url += _urlparams ? `?${_urlparams}` : "";
      }

      let axiosInstance;
      switch (type) {
        case "get":
          axiosInstance = axios.get(url, AUTHORIZATION);
          break;
        case "post":
          axiosInstance = axios.post(url, params, AUTHORIZATION);
          break;
        // TODO: 다른 HTTP 메소드 있다면 처리 (chw)
      }

      if (axiosInstance) {
        axiosInstance
          .then((res) => {
            console.log("TAxios response", url, res);

            const apiSysStatus = res.headers["api-sys-status"];
            const apiSysMessage = res.headers["api-sys-message"];

            const { systemNotice, systemTermination, appStatus } =
              getState().common;
            const isInitialLoad = !appStatus.loadingComplete;

            if (apiSysStatus === "800" && !systemNotice) {
              dispatch(setSystemNotice());
            } else if (apiSysStatus === "900" && !systemTermination) {
              const decodedMessage = decodeMessage(apiSysMessage);

              dispatch(setSystemTermination(isInitialLoad));
              dispatch(resetPanels());
              dispatch(
                pushPanel({
                  name: Config.panel_names.ERROR_PANEL,
                  panelInfo: {
                    apiSysMessage: decodedMessage,
                  },
                })
              );
            } else if (apiSysStatus === "901" && !systemTermination) {
              const decodedMessage = decodeMessage(apiSysMessage);

              dispatch(setSystemTermination(isInitialLoad));
              dispatch(resetPanels());
              dispatch(
                pushPanel({
                  name: Config.panel_names.ERROR_PANEL,
                  panelInfo: {
                    apiSysMessage: decodedMessage,
                  },
                })
              );
            }

            if (baseUrl === URLS.GET_AUTHENTICATION_CODE) {
              if (res?.data?.retCode !== 0) {
                console.error("accessToken failed", res.data.retCode);
                dispatch(
                  showError(
                    res.data.retCode,
                    res.data.retMsg,
                    false,
                    res.data.retDetailCode
                  )
                );
                return;
              }
            }

            // if(res?.data?.retCode === 501){
            //   //약관 비동의
            //   dispatch(changeLocalSettings({accessToken: null}));
            //   dispatch({type: types.GET_TERMS_AGREE_YN, payload: {}});
            //   return;
            // }

            // AccessToken 만료
            if (res?.data?.retCode === 401) {
              if (!tokenRefreshing) {
                dispatch(getReAuthenticationCode());
              }
              pushQueue();
              if (onFail) onFail(res);
              return;
            }

            // RefreshToken 만료
            if (res?.data?.retCode === 402 || res?.data?.retCode === 501) {
              if (baseUrl === URLS.GET_RE_AUTHENTICATION_CODE) {
                dispatch(getAuthenticationCode());
              } else {
                if (!tokenRefreshing) {
                  dispatch(getAuthenticationCode());
                }
                pushQueue();
              }
              if (onFail) onFail(res);
              return;
            }
            // 602 요청 국가 불일치
            if (res?.data?.retCode === 602) {
              dispatch(
                setShowPopup(ACTIVE_POPUP.changeCountyPopup, {
                  data: res.data.retCode,
                })
              );
              return;
            }
            // 603 서비스 국가 아님
            if (res?.data?.retCode === 603) {
              dispatch(
                setShowPopup(ACTIVE_POPUP.unSupportedCountryPopup, {
                  data: res.data.retCode,
                })
              );
              return;
            }

            if (res?.data?.retCode === 604) {
              //todo "NotServiceLanguage"
              return;
            }

            if (onSuccess) onSuccess(res);
          })
          .catch((error) => {
            console.error("TAxios ", url, error);
            if (onFail) onFail(error);
          });
      }
    }
  };

  const accessToken = getState().localSettings.accessToken;
  if (noTokenRefresh || (!tokenRefreshing && accessToken)) {
    executeRequest(accessToken);
  } else {
    if (!accessToken && !tokenRefreshing) {
      dispatch(getAuthenticationCode());
    }
    pushQueue();
  }
};

// 안전한 에러 처리를 위한 TAxiosPromise
export const TAxiosPromise = (
  dispatch,
  getState,
  type,
  baseUrl,
  urlParams = {},
  params = {},
  noTokenRefresh = false
) => {
  return new Promise((resolve, reject) => {
    TAxios(
      dispatch,
      getState,
      type,
      baseUrl,
      urlParams,
      params,
      // onSuccess - 항상 성공 객체로 반환
      (response) => {
        resolve({
          success: true,
          data: response.data,
          response: response,
          error: null
        });
      },
      // onFail - 에러도 resolve로 처리하여 throw 방지
      (error) => {
        console.error(`TAxiosPromise failed for ${baseUrl}:`, error);
        resolve({
          success: false,
          data: null,
          response: null,
          error: error
        });
      },
      noTokenRefresh
    );
  });
};

// 더 세밀한 제어를 위한 확장된 Promise 버전
export const TAxiosAdvancedPromise = (
  dispatch,
  getState,
  type,
  baseUrl,
  urlParams = {},
  params = {},
  options = {}
) => {
  const {
    noTokenRefresh = false,
    timeout = 30000,
    retries = 0,
    retryDelay = 1000,
    throwOnError = false, // 개발자가 명시적으로 원할 때만 throw
  } = options;

  return new Promise((resolve, reject) => {
    let attempts = 0;
    const maxAttempts = retries + 1;

    const attemptRequest = () => {
      attempts++;
      console.log(`TAxiosPromise attempt ${attempts}/${maxAttempts} for ${baseUrl}`);

      const timeoutId = setTimeout(() => {
        const timeoutError = new Error(`Request timeout after ${timeout}ms for ${baseUrl}`);
        if (throwOnError) {
          reject(timeoutError);
        } else {
          resolve({
            success: false,
            data: null,
            response: null,
            error: timeoutError
          });
        }
      }, timeout);

      TAxios(
        dispatch,
        getState,
        type,
        baseUrl,
        urlParams,
        params,
        // onSuccess
        (response) => {
          clearTimeout(timeoutId);
          console.log(`TAxiosPromise success on attempt ${attempts} for ${baseUrl}`);
          resolve({
            success: true,
            data: response.data,
            response: response,
            error: null
          });
        },
        // onFail
        (error) => {
          clearTimeout(timeoutId);
          console.error(`TAxiosPromise error on attempt ${attempts} for ${baseUrl}:`, error);
          
          // 재시도 로직
          if (attempts < maxAttempts) {
            console.log(`Retrying in ${retryDelay}ms... (${attempts}/${maxAttempts})`);
            setTimeout(() => {
              attemptRequest();
            }, retryDelay);
          } else {
            // 최종 실패 시에도 resolve로 처리 (throwOnError가 false인 경우)
            if (throwOnError) {
              reject(error);
            } else {
              resolve({
                success: false,
                data: null,
                response: null,
                error: error
              });
            }
          }
        },
        noTokenRefresh
      );
    };

    attemptRequest();
  });
};

// HTTP 메소드별 편의 함수들 (안전한 버전)
export const TAxiosGet = async (dispatch, getState, baseUrl, urlParams = {}, options = {}) => {
  return await TAxiosPromise(dispatch, getState, 'get', baseUrl, urlParams, {}, options.noTokenRefresh);
};

export const TAxiosPost = async (dispatch, getState, baseUrl, params = {}, options = {}) => {
  return await TAxiosPromise(dispatch, getState, 'post', baseUrl, {}, params, options.noTokenRefresh);
};

// 안전한 다중 요청 처리
export const TAxiosAll = async (requests) => {
  try {
    const results = await Promise.all(requests);
    
    // 모든 결과를 안전하게 처리
    const successResults = [];
    const failedResults = [];
    
    results.forEach((result, index) => {
      if (result.success) {
        successResults.push({ index, result: result.data });
      } else {
        failedResults.push({ index, error: result.error });
      }
    });
    
    return {
      success: failedResults.length === 0,
      successResults,
      failedResults,
      allResults: results
    };
  } catch (error) {
    console.error('TAxiosAll unexpected error:', error);
    return {
      success: false,
      successResults: [],
      failedResults: [{ index: -1, error }],
      allResults: []
    };
  }
};

// 순차 요청 처리 (안전 버전)
export const TAxiosSequential = async (requests) => {
  const results = [];
  const errors = [];
  
  for (let i = 0; i < requests.length; i++) {
    try {
      const result = await requests[i];
      if (result.success) {
        results.push({ index: i, data: result.data });
      } else {
        errors.push({ index: i, error: result.error });
        console.error(`TAxiosSequential failed at request ${i}:`, result.error);
      }
    } catch (error) {
      errors.push({ index: i, error });
      console.error(`TAxiosSequential unexpected error at request ${i}:`, error);
    }
  }
  
  return {
    success: errors.length === 0,
    results,
    errors
  };
};

// 안전한 Redux Thunk 헬퍼
export const createSafeApiThunk = (apiCall) => {
  return (...args) => async (dispatch, getState) => {
    try {
      const result = await apiCall(dispatch, getState, ...args);
      return result; // 이미 안전한 형태로 반환됨
    } catch (error) {
      console.error('API thunk unexpected error:', error);
      return {
        success: false,
        data: null,
        response: null,
        error
      };
    }
  };
};

// 실제 사용 예시들 (안전한 버전)
export const safeUsageExamples = {
  // 1. 기본 안전한 사용법
  basicSafeUsage: async (dispatch, getState) => {
    const result = await TAxiosPromise(
      dispatch,
      getState,
      'get',
      URLS.GET_HOME_TERMS,
      { trmsTpCdList: "MST00401, MST00402", mbrNo: "12345" }
    );
    
    if (result.success) {
      console.log('Success:', result.data);
      return result.data;
    } else {
      console.error('API call failed:', result.error);
      // 에러를 throw하지 않고 기본값 반환하거나 사용자에게 안내
      return null;
    }
  },

  // 2. retCode 체크를 포함한 안전한 처리
  safeWithRetCodeCheck: async (dispatch, getState) => {
    const result = await TAxiosGet(
      dispatch,
      getState,
      URLS.GET_HOME_TERMS,
      { trmsTpCdList: "MST00401, MST00402", mbrNo: "12345" }
    );
    
    if (!result.success) {
      console.error('Network error:', result.error);
      return { success: false, message: '네트워크 오류가 발생했습니다.' };
    }
    
    if (result.data.retCode !== 0) {
      console.error('API error:', result.data.retCode, result.data.retMsg);
      return { 
        success: false, 
        message: result.data.retMsg || 'API 오류가 발생했습니다.' 
      };
    }
    
    return { success: true, data: result.data };
  },

  // 3. 여러 요청의 안전한 처리
  safeParallelRequests: async (dispatch, getState) => {
    const requests = [
      TAxiosGet(dispatch, getState, URLS.GET_HOME_TERMS, { mbrNo: "12345" }),
      TAxiosGet(dispatch, getState, URLS.GET_USER_INFO, { mbrNo: "12345" }),
      TAxiosPost(dispatch, getState, URLS.UPDATE_SETTINGS, { setting: "value" })
    ];
    
    const result = await TAxiosAll(requests);
    
    if (result.success) {
      console.log('All requests succeeded');
      return result.successResults.map(item => item.result);
    } else {
      console.error('Some requests failed:', result.failedResults);
      // 부분적 성공도 처리 가능
      return {
        successData: result.successResults.map(item => item.result),
        errors: result.failedResults
      };
    }
  }
};


// 컴포넌트에서의 안전한 사용법
export const ComponentUsageExample = () => {
  const dispatch = useDispatch();
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  
  const handleFetchTerms = async () => {
    setLoading(true);
    setError(null);
    
    const result = await dispatch(fetchCurrentUserHomeTermsSafe());
    
    setLoading(false);
    
    if (result.success) {
      console.log("Terms fetched successfully");
      // 성공 처리 (예: 성공 토스트 표시)
    } else {
      console.error("Failed to fetch terms:", result.message);
      setError(result.message);
      // 에러 처리 (예: 에러 토스트 표시)
    }
  };
  
  return (
    <div>
      <button onClick={handleFetchTerms} disabled={loading}>
        {loading ? '로딩 중...' : '약관 정보 가져오기'}
      </button>
      {error && <div className="error-message">{error}</div>}
    </div>
  );
};