import { Model, routerRedux } from "dva";
import _ from 'lodash';
import { PageState, CoinDrawn, FundBasic } from '@/types/common';
import { getCoins, retrieveBalance, calcFee, withdraw } from './service';
import { getFundBasic } from '@/services/common';
import { message, Modal } from 'antd';
import { formatMessage } from 'umi-plugin-locale';
import BigNumber from 'bignumber.js';
import { dispatch } from '@/utils/utils';

export interface DrawModelState {
  coins: CoinDrawn[];
  pageState: PageState;
  coin: CoinDrawn | null;

  basic: FundBasic | null,
  balance: string;
  address: string;
  amount: string;
  fee: string; // 转账费用
  actual: string; // 实际到账

  confirmVisible: boolean;
  password: string;
  confirmLoading: boolean;
}

const initState: DrawModelState = {
  coins: [],
  coin: null,
  pageState: PageState.Pending,

  basic: null,
  balance: '',
  address: '',
  amount: '',
  fee: '',
  actual: '',

  confirmVisible: false,
  password: '',
  confirmLoading: false,
};

const model: Model = {
  namespace: 'draw',

  state: initState,

  effects: {
    *load(_, { put, call, all }) {
      yield put({ type: 'onUpdateState', pageState: PageState.Pending });
      try {
        const [coins, basic]: [CoinDrawn[], FundBasic] = yield all([
          call(getCoins),
          call(getFundBasic),
        ]);
        const coin = coins[0];
        yield put({
          type: 'onUpdateState',
          pageState: PageState.Success,
          coins,
          coin,
          basic,
          balance: retrieveBalance(basic, coin),
          address: '',
          amount: '',
          password: '',
        });
      } catch (e) {
        yield put({
          type: 'onUpdateState',
          pageState: PageState.Failure,
        });
      }
    },

    *selectCoin({ payload: id }, { put, select }) {
      const { coins, basic } = yield select((state: any) => state.draw);
      const coin = _.find(coins, ['id', id]);
      yield put({
        type: 'onUpdateState',
        coin,
        balance: retrieveBalance(basic, coin),
      });
    },

    *changeAddress({ payload }, { put }) {
      if (!/^[\da-zA-Z]*$/.test(payload)) return;
      yield put({
        type: 'onUpdateState',
        address: payload,
      })
    },

    *changeAmount({ payload }, { put, select }) {
      if (isNaN(payload)) return;
      const { coin } = (yield select((state: any) => state.draw)) as DrawModelState;
      if (!coin) return;
      const { fee, actual } = calcFee(coin, payload);
      yield put({
        type: 'onUpdateState',
        amount: payload,
        fee,
        actual,
      });
    },

    *performDraw(_, { put, select }) {
      const {
        coin,
        amount,
        address,
        balance,
      } = (yield select((state: any) => state.draw)) as DrawModelState;
      if (!coin) return message.warn(formatMessage({ id: 'draw.coin' }));
      if (!address) return message.warn(formatMessage({ id: 'draw.targetPrompt' }));
      const inputAmount = new BigNumber(amount || 0);
      if (inputAmount.gt(balance || 0)) return message.warn(formatMessage({ id: 'draw.amountGt' }));
      yield put({
        type: 'onUpdateState',
        confirmVisible: true,
        confirmLoading: false,
        password: '',
      });
    },

    *draw(_, { put, select, call }) {
      const {
        coin,
        amount,
        address,
        password,
      } = (yield select((state: any) => state.draw)) as DrawModelState;
      if (!coin) return;
      if (!address) return message.warn(formatMessage({ id: 'draw.targetPrompt' }));
      if (!password) return;
      yield put({ type: 'onUpdateState', confirmLoading: true });
      try {
        yield call(withdraw, coin, address, amount, password);
        yield put({
          type: 'onUpdateState',
          confirmVisible: false,
        });
        Modal.success({
          title: formatMessage({ id: 'common.prompt' }),
          content: formatMessage({ id: 'draw.success' }),
          okText: formatMessage({ id: 'common.ok' }),
          cancelText: formatMessage({ id: 'common.cancel' }),
          maskClosable: false,
          onOk: () => dispatch(routerRedux.goBack()),
        });
      } catch (e) {
        message.error(e.message);
      } finally {
        yield put({ type: 'onUpdateState', confirmLoading: false });
      }
    }
  },

  reducers: {
    onUpdateState(state, payload) {
      return {
        ...state,
        ...payload,
      };
    },
  },
};

export default model;
