import { fetchWebapi, formDataType, useReducer } from '@/utils';

type URLFn = (opts: any) => string;
type URL = string | URLFn;
export interface UseFetchOpts {
  formdata?: boolean;
  url: URL;
  method: string;
  body?: any;
  extraOpts?: object;
  initialData?: any;
}

export interface RequsetParams {
  body: object;
  URLOptions: object;
}
interface CreateRequstOpts {
  url: URL;
  body: any;
  params: object | RequsetParams;
}
export interface UseBaseFetchOpts extends UseFetchOpts {
  fetch: any;
}
const initialState = {
  loading: false,
  error: {},
  isFinally: false,
  response: {},
  isSuccess: false,
  isError: false
};

function reducer(state: any, action: any) {
  switch (action.type) {
    case 'start':
      return {
        ...state,
        loading: true,
        isFinally: false,
        isSuccess: false,
        isError: false
      };
    case 'error':
      return {
        ...state,
        error: action.error,
        loading: false,
        isFinally: true,
        isSuccess: false,
        isError: true
      };
    case 'success':
      return {
        ...state,
        response: action.data,
        loading: false,
        isFinally: true,
        isSuccess: true,
        isError: false
      };
    default:
      return state;
  }
}

export function useFetch(args: UseFetchOpts) {
  return useBaseFetch({
    ...args,
    fetch: fetchWebapi
  });
}

const createRequst = ({ url, body, params }: CreateRequstOpts) => {
  if (typeof url === 'function') {
    url = url((params as RequsetParams).URLOptions);
    body = (params as RequsetParams).body || body;
  } else {
    url = url;
    body = params || body;
  }
  return {
    url,
    body
  };
};

export function useBaseFetch({
  initialData = {},
  url,
  method,
  body,
  fetch,
  formdata = false, // 是否为formdata请求
  extraOpts = {} // 额外的头部设置
}: UseBaseFetchOpts) {
  const [
    { loading, error, isFinally, isSuccess, isError, response },
    dispatch
  ] = useReducer(reducer, initialState, (s: any) => ({
    ...s,
    response: initialData
  }));
  async function requestData(params?: any): Promise<any> {
    try {
      dispatch({ type: 'start' });
      const { url: requestURL, body: requestBody } = createRequst({
        url,
        body,
        params
      });
      const { data } = await fetch(requestURL, {
        method,
        body: requestBody,
        headersType: formdata ? formDataType : undefined,
        ...extraOpts
      });
      dispatch({ type: 'success', data });
      return data;
    } catch (error) {
      dispatch({ type: 'error', error });
      throw error;
    }
  }

  return {
    loading,
    error,
    response,
    doFetch: requestData,
    isFinally,
    isSuccess,
    isError
  };
}
