import { Inject, Logger, Provide } from '@midwayjs/decorator';
import { BaseService } from '@cool-midway/core';
import { WithdrawEntity } from '../entity/withdraw';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
import { ILogger } from '@midwayjs/logger';
import { WalletService } from './wallet';
import { DispatchService } from './channels/dispatch';
import { WithdrawNotifyService } from './withdrawNotify';
import { WithdrawChannelService } from './withdrawChannel';

@Provide()
export class WithdrawStateService extends BaseService {
    @InjectEntityModel(WithdrawEntity)
    withdrawEntity: Repository<WithdrawEntity>;

    @Inject()
    withdrawNotifyService: WithdrawNotifyService;

    @Inject()
    walletService: WalletService;

    @Inject()
    dispatchService: DispatchService;

    @Inject()
    withdrawChannelService: WithdrawChannelService;

    @Logger()
    logger: ILogger;

    STATUS = {
        SUCCESS: 8,
        FAIL: 3,
        ACCEPT: 1,
        PROCESSIONG: 2
    };
    EVENT = {
        TO_SUCCESS: 'toSuccess',
        FAIL_TO_SUCCESS: 'failToSuccess',
        TO_FAIL: 'toFail',
        SUCCESS_TO_FAIL: 'successToFail',
        ACCEPT_TO_PROCESSIONG: 'acceptToProcessiong',
        FAIL_TO_WAIT: 'failToWait',
        SUCCESS_TO_WAIT: 'successToWait'
    };
    async stateTo(oldStatus, newStatus, withdraw: WithdrawEntity) {
        this.logger.info(withdraw.orderNo, `from ${oldStatus} to ${newStatus}`);
        withdraw.status = +newStatus;
        withdraw.updateTime = new Date();
        switch (+oldStatus) {
            case this.STATUS.ACCEPT: {
                if (+newStatus === this.STATUS.PROCESSIONG) {
                    return await this.dispatch(this.EVENT.ACCEPT_TO_PROCESSIONG, withdraw);
                } else if (+newStatus === this.STATUS.FAIL) {
                    return await this.dispatch(this.EVENT.TO_FAIL, withdraw);
                } else if (+newStatus === this.STATUS.SUCCESS) {
                    return await this.dispatch(this.EVENT.TO_SUCCESS, withdraw);
                }
                break;
            }
            case this.STATUS.PROCESSIONG: {
                if (+newStatus === this.STATUS.FAIL) {
                    return await this.dispatch(this.EVENT.TO_FAIL, withdraw);
                } else if (+newStatus === this.STATUS.SUCCESS) {
                    return await this.dispatch(this.EVENT.TO_SUCCESS, withdraw);
                }
                break;
            }
            case this.STATUS.FAIL: {
                if (+newStatus === this.STATUS.SUCCESS) {
                    return await this.dispatch(this.EVENT.FAIL_TO_SUCCESS, withdraw);
                } else if (+newStatus === this.STATUS.ACCEPT || +newStatus === this.STATUS.PROCESSIONG) {
                    return await this.dispatch(this.EVENT.FAIL_TO_WAIT, withdraw);
                }
                break;
            }
            case this.STATUS.SUCCESS: {
                if (+newStatus === this.STATUS.FAIL) {
                    return await this.dispatch(this.EVENT.SUCCESS_TO_FAIL, withdraw);
                } else if (+newStatus === this.STATUS.ACCEPT || +newStatus === this.STATUS.PROCESSIONG) {
                    return await this.dispatch(this.EVENT.SUCCESS_TO_WAIT, withdraw);
                }
                break;
            }
        }
        await this.withdrawEntity.update(withdraw.id, withdraw);
    }
    async dispatch(event: string, withdraw: WithdrawEntity) {
        return await this[event](withdraw);
    }

    // 订单成功
    async toSuccess(withdraw) {
        await this.walletService.updateBalance({
            orderNo: withdraw.orderNo,
            mchId: withdraw.mchId,
            type: 2,
            amount: -(+withdraw.amount + +withdraw.charge),
            freeze: -(+withdraw.amount + +withdraw.charge),
            currency: withdraw.currency
        });
        await this.withdrawEntity.update(withdraw.id, withdraw);
        this.withdrawNotifyService.notify(withdraw);

    }

    // 订单失败=>成功
    async failToSuccess(withdraw) {
        await this.walletService.updateBalance({
            orderNo: withdraw.orderNo,
            mchId: withdraw.mchId,
            type: 2,
            amount: -(+withdraw.amount + +withdraw.charge),
            freeze: 0,
            currency: withdraw.currency
        });
        await this.withdrawEntity.update(withdraw.id, withdraw);
        this.withdrawNotifyService.notify(withdraw);
    }

    // 订单失败
    async toFail(withdraw) {
        await this.walletService.updateBalance({
            orderNo: withdraw.orderNo,
            mchId: withdraw.mchId,
            type: 2,
            amount: 0,
            freeze: -(+withdraw.amount + +withdraw.charge),
            currency: withdraw.currency
        });
        await this.withdrawEntity.update(withdraw.id, withdraw);
        this.withdrawNotifyService.notify(withdraw);
        return withdraw.status;
    }

    // 订单成功=》失败
    async successToFail(withdraw) {
        await this.walletService.updateBalance({
            orderNo: withdraw.orderNo,
            mchId: withdraw.mchId,
            type: 3,
            amount: +withdraw.amount + +withdraw.charge,
            freeze: 0,
            currency: withdraw.currency
        });
        await this.withdrawEntity.update(withdraw.id, withdraw);
        this.withdrawNotifyService.notify(withdraw);
    }

    // 发起代付：已受理=》银行处理中
    async acceptToProcessiong(withdraw) {
        try {
            const channel = await this.withdrawChannelService.queryByCode(withdraw.code);
            let channelCharge = (+withdraw.amount * +channel.rate) / 100 + +channel.basicFee;
            if (channelCharge < channel.feeMin) {
                channelCharge = channel.feeMin;
            }
            withdraw.channelCharge = channelCharge;
            const { status, traceNo, message } = await this.dispatchService.withdraw(withdraw);
            if (+status === 3) {
                this.logger.info(withdraw.orderNo, `------------发起代付失败-------------`);
                withdraw.remark = message;
                withdraw.status = await this.stateTo(withdraw.status, this.STATUS.FAIL, withdraw);
            } else {
                withdraw.traceNo = traceNo;
            }
        } catch (err) {
            withdraw.remark = err.message;
        }
        await this.withdrawEntity.update(withdraw.id, withdraw);
        return withdraw.status;
    }

    // 重新发起：失败 =》等待
    async failToWait(withdraw) {
        await this.walletService.updateBalance({
            orderNo: withdraw.orderNo,
            mchId: withdraw.mchId,
            type: 2,
            amount: 0,
            freeze: +withdraw.amount + +withdraw.charge,
            currency: withdraw.currency
        });
        await this.withdrawEntity.update(withdraw.id, withdraw);
    }


    // 重新发起：成功 =》等待
    async successToWait(withdraw) {
        await this.walletService.updateBalance({
            orderNo: withdraw.orderNo,
            mchId: withdraw.mchId,
            type: 3,
            amount: +withdraw.amount + +withdraw.charge,
            freeze: +withdraw.amount + +withdraw.charge,
            currency: withdraw.currency
        });
        await this.withdrawEntity.update(withdraw.id, withdraw);
    }
}
