/**
 * 该文件可自行根据业务逻辑进行调整
 */
import type { RequestClientOptions } from '@vben/request';

import { useAppConfig } from '@vben/hooks';
import { preferences } from '@vben/preferences';
import {
  authenticateResponseInterceptor,
  defaultResponseInterceptor,
  errorMessageResponseInterceptor,
  RequestClient,
} from '@vben/request';
import { useAccessStore } from '@vben/stores';

import { message } from 'ant-design-vue';

import { useAuthStore } from '#/store';

import { refreshTokenApi } from './core';

const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
const TENANT_ID_HEADER_KEY = 'X-Tenant-Id';
const TENANT_CODE_HEADER_KEY = 'X-Tenant-Code';
const TENANT_STORAGE_KEY = 'sys-tenant-id';
const DEV_TENANT_ID = import.meta.env.DEV ? import.meta.env.VITE_TENANT_ID : '';

interface TenantHeaderPayload {
  tenantCode?: string;
  tenantId?: string;
}

function getHeaderValue(headers: any, key: string) {
  if (!headers) {
    return '';
  }

  if (typeof headers.get === 'function') {
    return headers.get(key) || headers.get(key.toLowerCase()) || '';
  }

  return headers[key] || headers[key.toLowerCase()] || '';
}

function setHeaderValue(headers: any, key: string, value: string) {
  if (!headers) {
    return;
  }

  if (typeof headers.set === 'function') {
    headers.set(key, value);
    return;
  }

  headers[key] = value;
}

function resolveTenantHeaderPayload(): TenantHeaderPayload {
  const hostname = window.location.hostname;
  const hostnameParts = hostname.split('.').filter(Boolean);
  const isIpAddress = /^\d+\.\d+\.\d+\.\d+$/.test(hostname);
  const subdomainTenant =
    hostnameParts.length > 2 && !isIpAddress ? hostnameParts[0] : '';

  if (subdomainTenant) {
    if (/^\d+$/.test(subdomainTenant)) {
      return { tenantId: subdomainTenant };
    }

    return { tenantCode: subdomainTenant };
  }

  const storageTenantId = localStorage.getItem(TENANT_STORAGE_KEY) || '';
  if (storageTenantId) {
    return { tenantId: storageTenantId };
  }

  if (DEV_TENANT_ID) {
    return { tenantId: DEV_TENANT_ID };
  }

  return {};
}

function createRequestClient(baseURL: string, options?: RequestClientOptions) {
  const client = new RequestClient({
    ...options,
    baseURL,
  });

  /**
   * 重新认证逻辑
   */
  async function doReAuthenticate() {
    console.warn('Access token or refresh token is invalid or expired. ');
    const accessStore = useAccessStore();
    const authStore = useAuthStore();
    accessStore.setAccessToken(null);
    if (
      preferences.app.loginExpiredMode === 'modal' &&
      accessStore.isAccessChecked
    ) {
      accessStore.setLoginExpired(true);
    } else {
      await authStore.logout();
    }
  }

  /**
   * 刷新token逻辑
   */
  async function doRefreshToken() {
    const accessStore = useAccessStore();
    const currentRefreshToken = accessStore.refreshToken;

    if (!currentRefreshToken) {
      throw new Error('refresh token is required');
    }

    const headers: Record<string, string> = {
      'Accept-Language': preferences.app.locale,
    };
    const { tenantCode, tenantId } = resolveTenantHeaderPayload();
    if (tenantCode) {
      headers[TENANT_CODE_HEADER_KEY] = tenantCode;
    } else if (tenantId) {
      headers[TENANT_ID_HEADER_KEY] = tenantId;
    }

    const resp = await refreshTokenApi(
      {
        refreshToken: currentRefreshToken,
      },
      {
        headers,
      },
    );

    const responseBody = (resp as any)?.data ?? resp;
    const tokenData =
      responseBody?.accessToken || responseBody?.refreshToken
        ? responseBody
        : responseBody?.data;
    const newAccessToken = tokenData?.accessToken;
    const newRefreshToken = tokenData?.refreshToken ?? currentRefreshToken;

    if (!newAccessToken) {
      throw new Error('access token is missing in refresh response');
    }

    accessStore.setAccessToken(newAccessToken);
    accessStore.setRefreshToken(newRefreshToken);
    return newAccessToken;
  }

  function formatToken(token: null | string) {
    return token ? `Bearer ${token}` : null;
  }

  // 请求头处理
  client.addRequestInterceptor({
    fulfilled: async (config) => {
      const accessStore = useAccessStore();

      const authorization = formatToken(accessStore.accessToken);
      if (authorization) {
        setHeaderValue(config.headers, 'Authorization', authorization);
      }
      setHeaderValue(config.headers, 'Accept-Language', preferences.app.locale);

      const headerTenantId = getHeaderValue(
        config.headers,
        TENANT_ID_HEADER_KEY,
      );
      const headerTenantCode = getHeaderValue(
        config.headers,
        TENANT_CODE_HEADER_KEY,
      );
      if (!headerTenantId && !headerTenantCode) {
        const { tenantCode, tenantId } = resolveTenantHeaderPayload();
        if (tenantCode) {
          setHeaderValue(config.headers, TENANT_CODE_HEADER_KEY, tenantCode);
        } else if (tenantId) {
          setHeaderValue(config.headers, TENANT_ID_HEADER_KEY, tenantId);
        }
      }

      return config;
    },
  });

  // 处理返回的响应数据格式
  client.addResponseInterceptor(
    defaultResponseInterceptor({
      codeField: 'code',
      dataField: 'data',
      successCode: 200,
    }),
  );

  // token过期的处理
  client.addResponseInterceptor(
    authenticateResponseInterceptor({
      client,
      doReAuthenticate,
      doRefreshToken,
      enableRefreshToken: preferences.app.enableRefreshToken,
      formatToken,
    }),
  );

  // 通用的错误处理,如果没有进入上面的错误处理逻辑，就会进入这里
  client.addResponseInterceptor(
    errorMessageResponseInterceptor((msg: string, error) => {
      // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理，根据不同的 code 做不同的提示，而不是直接使用 message.error 提示 msg
      // 当前mock接口返回的错误字段是 error 或者 message
      const responseData = error?.response?.data ?? {};
      const errorMessage = responseData?.error ?? responseData?.message ?? '';
      // 如果没有错误信息，则会根据状态码进行提示
      message.error(errorMessage || msg);
    }),
  );

  return client;
}

export const requestClient = createRequestClient(apiURL, {
  responseReturn: 'data',
});

export const baseRequestClient = new RequestClient({ baseURL: apiURL });
