import { HTTPSTATUS } from '@/constants';
import { API_PATH_REFRESH_TOKEN } from '@/constants/api';
import { ROUTE_LOGIN } from '@/constants/routes';
import { apiRefreshToken } from '@/services/master/AuthController';
import { checkRefreshTokenExpired } from '@/utils/jwt';
import {
  clearAllData,
  getAccessToken,
  getRefreshToken,
  setAccessToken,
} from '@/utils/storage';
import { history, request, RequestConfig } from '@umijs/max';
import { message } from 'antd';

// Trạng thái dùng chung cho cơ chế refresh token + hàng đợi
let refreshingTokenPromise: Promise<string | null> | null = null;

async function getValidAccessToken(): Promise<string | null> {
  const refreshToken = getRefreshToken();

  if (!refreshToken || checkRefreshTokenExpired(refreshToken)) {
    return null;
  }

  if (!refreshingTokenPromise) {
    refreshingTokenPromise = apiRefreshToken({ refresh_token: refreshToken })
      .then((resp) => {
        if (resp?.access_token) {
          setAccessToken(resp.access_token);
          return resp.access_token;
        }
        return null;
      })
      .catch((err) => {
        // eslint-disable-next-line no-console
        console.error('Refresh token failed:', err);
        return null;
      })
      .finally(() => {
        refreshingTokenPromise = null;
      });
  }

  return refreshingTokenPromise;
}

// Runtime configuration
export const handleRequestConfig: RequestConfig = {
  // Unified request settings
  timeout: 20000,
  validateStatus: (status) => {
    return (
      (status >= 200 && status < 300) ||
      status === HTTPSTATUS.HTTP_NOTFOUND ||
      status === HTTPSTATUS.HTTP_UNAUTHORIZED
    );
  },
  headers: { 'X-Requested-With': 'XMLHttpRequest' },
  // Error handling: umi@3's error handling scheme.
  errorConfig: {
    // Error throwing
    errorThrower: (res: any) => {
      // console.log('Response from backend:', res);
      const { success, data, errorCode, errorMessage, showType } = res;
      if (!success) {
        const error: any = new Error(errorMessage);
        error.name = 'BizError';
        error.info = { errorCode, errorMessage, showType, data };
        throw error; // Throw custom error
      }
    },
    // Error catching and handling
    errorHandler: (error: any) => {
      if (error.response) {
        const { status } = error.response;

        // Ưu tiên: codeMessage → backend message → statusText
        // const errMsg =
        //   codeMessage[status as keyof typeof codeMessage] ||
        //   data?.message ||
        //   statusText ||
        //   'Unknown error';

        if (status === HTTPSTATUS.HTTP_UNAUTHORIZED) {
          // 401 đã được xử lý trong responseInterceptors (refresh token + redirect nếu cần)
          return;
        } else if (status === HTTPSTATUS.HTTP_SERVERERROR) {
          // message.error('💥 Internal server error!');
        } else {
          message.error(`❌ ${status}: ${error.message || 'Error'}`);
        }
      } else if (error.request) {
        message.error('🚨 No response from server!');
      } else {
        message.error(`⚠️ Request setup error: ${error.message}`);
      }
    },
  },

  // Request interceptors
  requestInterceptors: [
    (url: string, options: any) => {
      // console.log('URL Request:', url, options);

      // Chỉ cần thêm token, proxy sẽ xử lý việc redirect đến đúng port
      // URL sẽ bắt đầu với /api và proxy sẽ chuyển đến hostname:81/api
      const token = getAccessToken();
      return {
        url: url,
        options: {
          ...options,
          headers: {
            ...options.headers,
            ...(token && !options.headers.Authorization
              ? { Authorization: `${token}` }
              : {}),
          },
        },
      };
    },
  ],

  // Unwrap data from backend response
  responseInterceptors: [
    async (response: any, options: any) => {
      const isRefreshRequest = response.url?.includes(API_PATH_REFRESH_TOKEN);
      const alreadyRetried = options?.skipAuthRefresh === true;

      // Xử lý 401: đưa request vào hàng đợi, gọi refresh token, rồi gọi lại
      if (
        response.status === HTTPSTATUS.HTTP_UNAUTHORIZED &&
        // Không tự refresh cho chính API refresh token để tránh vòng lặp vô hạn
        !isRefreshRequest &&
        !alreadyRetried
      ) {
        const newToken = await getValidAccessToken();

        // Không refresh được => xoá dữ liệu, điều hướng về trang login
        if (!newToken) {
          const { pathname } = history.location;
          clearAllData();
          if (pathname !== ROUTE_LOGIN) {
            history.push(`${ROUTE_LOGIN}?redirect=${pathname}`);
          } else {
            history.push(ROUTE_LOGIN);
          }
          return Promise.reject(
            new Error('Unauthorized and refresh token is invalid'),
          );
        }

        // Rebuild request options from config
        const originalConfig = response.config;
        const newOptions = {
          method: originalConfig.method,
          headers: {
            ...(originalConfig.headers || {}),
            Authorization: `${newToken}`,
          },
          data: originalConfig.data,
          params: originalConfig.params,
          skipAuthRefresh: true,
        };

        // Gọi lại request gốc với accessToken mới
        return request(originalConfig.url, newOptions);
      }

      if (
        response.status === HTTPSTATUS.HTTP_UNAUTHORIZED &&
        (isRefreshRequest || alreadyRetried)
      ) {
        clearAllData();
        history.push(ROUTE_LOGIN);
        return Promise.reject(new Error('Unauthorized'));
      }

      // console.log('Response from server: ', response);

      return {
        status: response.status,
        statusText: response.statusText,
        headers: response.headers,
        config: response.config,
        data: response.data,
      };
    },
  ] as any,
};
