import message from 'components/message';
import { redirectToLogin } from './utils';
import { generateId } from 'utils/utils';
const isPreview = () => /\/(shareScreen|insert)/i.test(window.location.pathname);

// 请求头携带参数
function defaultHeader(): { 'x-request-id': string } {
  const _h = {
    'x-request-id': generateId(),
  };
  return _h;
}

function checkStatus(response) {
  if (response.status === 200) {
    return response.json().then((data) => {
      let _headers = null;
      const hs = response.headers.get('access-control-expose-headers');
      if (hs) {
        _headers = hs
          .replace(/\s/g, '')
          .toLowerCase()
          .split(',')
          .reduce((acc, key) => {
            acc[key] = response.headers.get(key);
            return acc;
          }, {});
      }
      return _headers ? { ...data, _headers } : data;
    });
  } else if (response.status === 400) {
    return response.json();
  } else if (response.status === 419) {
    // 没有产品权限的时候会引导用户到落地页sku页面，引导购买
    window.location.href = window.appConfig.HOME_URL + '/overdue' + window.location.search;
    return;
  } else if (response.status === 401) {
    return response.json().then((data) => {
      // 登录但未选择租户
      if (data && data.message === 'E_TENANT_NOT_FOUND') {
        return data;
      } else {
        redirectToLogin();
        return;
      }
    });
  } else if (response.status === 426) {
    message.error('license已到期');
    window.location.href = BASENAME + '/active';
    return;
  } else if (response.status === 404) {
    console.error('接口未找到');
    // !isPreview() && message.error('接口未找到');
    return;
  } else if (response.status === 503) {
    return;
  } else if (response.status === 504) {
    console.error('接口超时');
    // !isPreview() && message.error('接口超时');
    return;
  } else if (response.status === 420) {
    // offlineNotify => 离线通知
    const event = new CustomEvent('offlineNotify', { detail: response });
    document.dispatchEvent(event);
  } else if (response.status === 418) {
    linkLogin();
  } else {
    return Promise.reject({ message: '网络错误或服务器异常，请稍后再试' });
  }
}

function handleSuccess(response, error) {
  if (response) {
    if (response.success) {
      return Promise.resolve(response._headers ? response : response.data || true);
    } else if (response.code === -1) {
      // 大屏分享需要密码
      return Promise.resolve(-1);
    } else if (response.code === -2) {
      // 大屏分享需要token
      return Promise.resolve(-2);
    } else if (response.message === '大屏未发布' || response.message === '大屏不存在') {
      // 大屏不存在或者取消发布状态(目前无code，用message来判断)
      return Promise.resolve(-404);
    } else if (response.code === 404) {
      // 大屏不存在或者取消发布状态(目前该状态未返回404)
      return Promise.resolve(404);
    } else if (response.data?.code === -10) {
      // 用户切换版本锁定状态
      window.location.href = BASENAME + '/userLock';
      return;
    } else {
      if (error) {
        error(response);
        return;
      } else {
        return Promise.reject({ message: response.message });
      }
    }
  }
}

function handleError(error, hideError) {
  if (error && error.name === 'AbortError') {
    return;
  } else {
    if (!hideError) {
      if (isPreview()) {
        // console.error(error.message);
      } else {
        message.destroy();
        message.error(error.message || '服务错误');
      }
    }
    return;
  }
}

export function request(
  url: string,
  params = {},
  query = {},
  body: string | FormData | undefined = undefined,
  options: any = {},
) {
  let [method, path] = url.split(' ');
  method = method.toUpperCase();
  const { headers = {}, credentials = 'include', signal, hideError, error } = options;
  Object.keys(params).map((key) => {
    path = path.replace(`:${key}`, params[key]);
  });

  const queryString = Object.keys(query)
    .map(
      (key) =>
        `${key}=${encodeURIComponent(
          typeof query[key] === 'string' ? query[key] : JSON.stringify(query[key]),
        )}`,
    )
    .join('&');

  let requestUrl = path;
  if (queryString) requestUrl += `?${queryString}`;

  return fetch(requestUrl, {
    method,
    credentials,
    headers: {
      ...((method === 'POST' || method === 'PATCH' || method === 'PUT' || method === 'DELETE') &&
      typeof body === 'string'
        ? { 'content-type': 'application/json' }
        : {}),
      ...headers,
      ...defaultHeader(),
    },
    ...(body ? { body } : {}),
    signal,
  })
    .then(checkStatus)
    .then((response) => handleSuccess(response, error))
    .catch((error) => handleError(error, hideError));
}

export interface RequestOptions {
  headers?: any;
  signal?: AbortSignal;
  hideError?: boolean;
  error?: (msg) => void;
  res?: boolean;
  queue?: boolean;
}

export default {
  get<T>(
    url: string,
    queryData: { [k: string]: any } = {},
    options: RequestOptions = {},
  ): Promise<T> {
    const { signal, hideError, error } = options;
    const queryString = Object.entries(queryData).reduce(
      (all: any, item) => (
        all.push(
          item[0] +
            '=' +
            (typeof item[1] === 'object' && item[1] !== null ? JSON.stringify(item[1]) : item[1]),
        ),
        all
      ),
      [],
    );
    url = queryString.length ? (url += '?' + queryString.join('&')) : url;

    return fetch(url, {
      method: 'GET',
      credentials: 'include',
      headers: {
        ...defaultHeader(),
      },
      signal,
    })
      .then(checkStatus)
      .then((response) => handleSuccess(response, error))
      .catch((err) => handleError(err, hideError));
  },
  post<T>(url: string, postData: { [k: string]: any }, options: RequestOptions = {}): Promise<T> {
    const { signal, hideError, error, headers } = options;
    return fetch(url, {
      method: 'POST',
      credentials: 'include',
      headers: {
        'content-type': 'application/json',
        ...defaultHeader(),
        ...headers,
      },
      body: JSON.stringify(postData),
      signal,
    })
      .then(checkStatus)
      .then((response) => handleSuccess(response, error))
      .catch((error) => handleError(error, hideError));
  },
  upload<T>(url: string, formData: FormData, options: RequestOptions = {}): Promise<T> {
    const { signal, hideError, error } = options;
    return fetch(url, {
      method: 'POST',
      credentials: 'include',
      body: formData,
      headers: {
        ...defaultHeader(),
      },
      signal,
    })
      .then(checkStatus)
      .then((response) => handleSuccess(response, error))
      .catch((error) => handleError(error, hideError));
  },
};

export function linkLogin() {
  const redirectUrl = window.location.href;
  window.location.href = `/login?return_to=${redirectUrl}`;
}
