package cn.superdesk.uniorder.controller.accounting.supplier;

import cn.superdesk.libs.common.json.JsonUtils;
import cn.superdesk.uniorder.common.R;
import cn.superdesk.uniorder.common.enums.order.UnifiedOrderAccountingStateEnum;
import cn.superdesk.uniorder.common.enums.accounting.AccountingOrderInvoiceStatusEnum;
import cn.superdesk.uniorder.common.enums.accounting.AccountingOrderAccountingStatusEnum;
import cn.superdesk.uniorder.controller.base.BaseController;
import cn.superdesk.uniorder.dao.entity.accounting.unified.supplier.AccountingUnifiedSupplier;
import cn.superdesk.uniorder.dao.entity.base.UnifiedOrder;
import cn.superdesk.uniorder.dto.vo.accounting.unified.supplier.AccoountingUnifiedSupplierStatementOfAccountFixVoDimGoods;
import cn.superdesk.uniorder.dto.vo.accounting.unified.supplier.AccountingUnifiedSuplierCheckAmountErrorForFixDimOrder;
import cn.superdesk.uniorder.dto.vo.accounting.unified.supplier.AccountingUnifiedSuplierHead;
import cn.superdesk.uniorder.dto.vo.unified.UnifiedSupplierStatementOfAccountVo;
import cn.superdesk.uniorder.dubbo.consumer.accounting.AccountingUnifiedSupplierDubboConsumerService;
import cn.superdesk.uniorder.dubbo.consumer.base.UnifiedOrderDubboConsumerService;
import cn.superdesk.uniorder.dubbo.consumer.unified.UnifiedSupplierDubboConsumerService;
import cn.superdesk.uniorder.utils.exception.ExceptionUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Api(value = "供应商对账(结算) - 对账单", tags = {"供应商对账(结算) - 对账单"})
@Slf4j
@RestController
//@RequestMapping("/usupplier")
@RequestMapping("/accounting/unified/supplier/statement")
public class UnifiedSupplierStatementController extends BaseController {


    @Autowired
    UnifiedOrderDubboConsumerService              unifiedOrderDubboConsumerService;
    @Autowired
    UnifiedSupplierDubboConsumerService           unifiedSupplierDubboConsumerService;
    @Autowired
    AccountingUnifiedSupplierDubboConsumerService accountingUnifiedSupplierDubboConsumerService;

    /***
     * 供应商结算 - 对账单
     *
     * @url: http://order.avic-s.com/#/vendorAccountStatement?id=72
     * @return
     */
    @ApiOperation(value = "供应商对账(结算) - 对账单 - 列表", notes = "")
    @PostMapping("/getStatementOfAccountList")
    @ResponseBody
    public R<List<UnifiedSupplierStatementOfAccountVo>> getStatementOfAccountList() {

        R<List<UnifiedSupplierStatementOfAccountVo>> result = new R<>();

        try {
            Map<String, Object> params = new HashMap<>();

            // 组合的 下拉选择的
            params.put("accountingOrderSn", getString("accountingOrderSn"));

            params.put("orderSn", getString("orderSn"));

            // 供应商名称
            params.put("supplierId", getLong("supplierId"));
            params.put("supplierName", getString("supplierName"));


            // 对账单状态
            params.put("accountingStatus", getString("accountingStatus"));

            // 开票状态
            params.put("invoiceStatus", getString("invoiceStatus"));

            // 对账时间
            params.put("startTime", getString("startTime"));
            params.put("endTime", getString("endTime"));

            log.info("供应商结算 - 对账单 : \n{}", JsonUtils.toJson(params));

            // 前端 列表数据
            result = accountingUnifiedSupplierDubboConsumerService.getStatementOfAccountList(getToken(), params, getPageNum(), getPageSize());

            // 修正显示
            for (UnifiedSupplierStatementOfAccountVo vo : result.getData()) {

                vo.setAccountingStatusName(AccountingOrderAccountingStatusEnum.getDesc(vo.getAccountingStatus()));
                vo.setInvoiceStatusName(AccountingOrderInvoiceStatusEnum.getDesc(vo.getInvoiceStatus()));

                if (vo.getDimCreateBy().equals(0)) {
                    fixDimOrder(vo);
                } else if (vo.getDimCreateBy().equals(1)) {
                    fixDimGoods(vo);
                }


                // TODO 修正
//				private BigDecimal amount;
//				private BigDecimal costAmount;
//
//
////<!--		auso.amount_with_freight,-->
////<!--		auso.cost_amount_with_freight,-->
////<result column="amount_with_freight" property="amountWithFreight" jdbcType="DECIMAL"/>
////<result column="cost_amount_with_freight" property="costAmountWithFreight" jdbcType="DECIMAL"/>
//
//				private BigDecimal amountWithFreight;
//				private BigDecimal costAmountWithFreight;
//
//				/**
//				 * 退单的 商品 销售金额累加
//				 */
//				private BigDecimal refundAmount;
//				/**
//				 * 退单的 商品 成本金额累加
//				 */
//				private BigDecimal refundCostAmount;
            }


            // 前端 头部 对账单数：1 订单数：3 成本金额：¥ 10312.92
            AccountingUnifiedSuplierHead accountingUnifiedSuplierHead = accountingUnifiedSupplierDubboConsumerService.getStatementOfAccountHeadSum(getToken(), params);

            Map<String, Object> headData = new HashMap<>();
            headData.put("amount", accountingUnifiedSuplierHead.getAmount());
            headData.put("costAmount", accountingUnifiedSuplierHead.getCostAmount());
            headData.put("total", accountingUnifiedSuplierHead.getTotal());
            headData.put("orderTotal", accountingUnifiedSuplierHead.getOrderTotal());

            result.setHeadData(headData);

        } catch (Exception e) {

            result.setCode(String.valueOf(e.hashCode()));
            result.setSuccess(false);
            result.setMessage(e.getMessage());

            log.error(ExceptionUtils.getMessage(e));
            e.printStackTrace();

        }

        return result;
    }

    /**
     * 修正列表数据显示
     *
     * @param unifiedSupplierStatementOfAccountVo
     */
    private void fixDimOrder(UnifiedSupplierStatementOfAccountVo unifiedSupplierStatementOfAccountVo) {


        // 得到 accountingOrderSn
        Map<String, Object> params = new HashMap<>();
        params.put("accountingOrderSn", unifiedSupplierStatementOfAccountVo.getAccountingOrderSn());
        List<AccountingUnifiedSuplierCheckAmountErrorForFixDimOrder> orderDimList = accountingUnifiedSupplierDubboConsumerService.checkAmountErrorForFixDimOrder(params);

        BigDecimal orderCostAmount = orderDimList
                .stream()
                .map(item -> item.getOrderCostAmount() == null ? BigDecimal.ZERO : item.getOrderCostAmount())
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal orderTransportAmount = orderDimList
                .stream()
                .map(item -> item.getOrderTransportAmount() == null ? BigDecimal.ZERO : item.getOrderTransportAmount())
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal goodsCostAmount = orderDimList
                .stream()
                .map(item -> item.getGoodsCostAmount() == null ? BigDecimal.ZERO : item.getGoodsCostAmount())
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal goodsRefundCostAmount = orderDimList
                .stream()
                .map(item -> item.getGoodsRefundCostAmount() == null ? BigDecimal.ZERO : item.getGoodsRefundCostAmount())
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal goodsTransportAmount = orderDimList
                .stream()
                .map(item -> item.getGoodsTransportAmount() == null ? BigDecimal.ZERO : item.getGoodsTransportAmount())
                .reduce(BigDecimal.ZERO, BigDecimal::add);


        BigDecimal newAmount            = goodsCostAmount.add(goodsRefundCostAmount);
        BigDecimal newAmountWithFreight = newAmount.add(goodsTransportAmount);

        log.info("核算 : \norderCostAmount: {}\norderTransportAmount: {}\ngoodsCostAmount: {}\ngoodsRefundCostAmount: {}\ngoodsTransportAmount: {}\nnewAmount: {}\nnewAmountWithFreight: {}",
                orderCostAmount, orderTransportAmount, goodsCostAmount, goodsRefundCostAmount, goodsTransportAmount, newAmount, newAmountWithFreight);

        // 商品成本 - 商品退成本
        unifiedSupplierStatementOfAccountVo.setCostAmount(newAmount);
        // 商品成本 - 商品退成本 + 运费
        unifiedSupplierStatementOfAccountVo.setCostAmountWithFreight(newAmountWithFreight);

        unifiedSupplierStatementOfAccountVo.setOrderCostAmount(orderCostAmount);
        unifiedSupplierStatementOfAccountVo.setOrderTransportAmount(orderTransportAmount);

        unifiedSupplierStatementOfAccountVo.setGoodsCostAmount(goodsCostAmount);
        unifiedSupplierStatementOfAccountVo.setGoodsRefundCostAmount(goodsRefundCostAmount);
        unifiedSupplierStatementOfAccountVo.setGoodsTransportAmount(goodsTransportAmount);

    }

    private void fixDimGoods(UnifiedSupplierStatementOfAccountVo unifiedSupplierStatementOfAccountVo) {

        // 得到 accountingOrderSn
        Map<String, Object> params = new HashMap<>();
        params.put("accountingOrderSn", unifiedSupplierStatementOfAccountVo.getAccountingOrderSn());
        AccoountingUnifiedSupplierStatementOfAccountFixVoDimGoods fixVoDimGoods = accountingUnifiedSupplierDubboConsumerService.checkAmountErrorForFixDimGoods(params);


        BigDecimal newAmount            = fixVoDimGoods.getGoodsCostAmount().add(fixVoDimGoods.getGoodsRefundCostAmount());
        BigDecimal newAmountWithFreight = newAmount.add(fixVoDimGoods.getGoodsTransportAmount());


        // 商品成本 - 商品退成本
        unifiedSupplierStatementOfAccountVo.setCostAmount(newAmount);
        // 商品成本 - 商品退成本 + 运费
        unifiedSupplierStatementOfAccountVo.setCostAmountWithFreight(newAmountWithFreight);

        unifiedSupplierStatementOfAccountVo.setOrderCostAmount(fixVoDimGoods.getOrderCostAmount());
        unifiedSupplierStatementOfAccountVo.setOrderTransportAmount(fixVoDimGoods.getOrderTransportAmount());

        unifiedSupplierStatementOfAccountVo.setGoodsCostAmount(fixVoDimGoods.getGoodsCostAmount());
        unifiedSupplierStatementOfAccountVo.setGoodsRefundCostAmount(fixVoDimGoods.getGoodsRefundCostAmount());
        unifiedSupplierStatementOfAccountVo.setGoodsTransportAmount(fixVoDimGoods.getGoodsTransportAmount());

    }


    @ApiOperation(value = "供应商对账(结算) - 对账单 - opt提交对账 - 维度兼容未整改", notes = "")
    @PostMapping("/opSubmitAccounting")
    @ResponseBody
    public R<AccountingUnifiedSupplier> opSubmitAccounting() {

        R<AccountingUnifiedSupplier> result = new R<>();

        try {

            Long accountingOrderId = getLong("id");

            AccountingUnifiedSupplier statementOfAccount4Check = accountingUnifiedSupplierDubboConsumerService.findById(accountingOrderId);

            // TODO 写死
            if (statementOfAccount4Check.getInvoiceStatus() == 1) {
                result.setCode(400);
                result.setSuccess(false);
                result.setMessage("已开票对账单不可继续操作！");
                return result;
            }

            accountingUnifiedSupplierDubboConsumerService.opSubmit(accountingOrderId, getToken());

            result.setData(statementOfAccount4Check);

        } catch (Exception e) {

            result.setCode(String.valueOf(e.hashCode()));
            result.setSuccess(false);
            result.setMessage(e.getMessage());

            log.error(ExceptionUtils.getMessage(e));
            e.printStackTrace();
        }

        return result;

    }


    @ApiOperation(value = "供应商对账(结算) - 对账单 - opt确认对账 - 维度兼容未整改", notes = "")
    @PostMapping("/opConfirmAccounting")
    @ResponseBody
    public R<AccountingUnifiedSupplier> opConfirmAccounting() {

        R<AccountingUnifiedSupplier> result = new R<>();

        try {

            Long accountingOrderId = getLong("id");

            AccountingUnifiedSupplier statementOfAccount4Check = accountingUnifiedSupplierDubboConsumerService.findById(accountingOrderId);

            // TODO 写死
            if (statementOfAccount4Check.getInvoiceStatus() == 1) {
                result.setCode(400);
                result.setSuccess(false);
                result.setMessage("已开票对账单不可继续操作！");
                return result;
            }

            accountingUnifiedSupplierDubboConsumerService.opConfirm(accountingOrderId, getToken());

            result.setData(statementOfAccount4Check);

        } catch (Exception e) {

            result.setCode(String.valueOf(e.hashCode()));
            result.setSuccess(false);
            result.setMessage(e.getMessage());

            log.error(ExceptionUtils.getMessage(e));
            e.printStackTrace();
        }

        return result;

    }


    /**
     * 供应商结算 - 对账单 - opt编辑对帐
     *
     * @return
     */
    @ApiOperation(value = "供应商对账(结算) - 对账单 - opt编辑对帐(目前能适用以订单创建的对账单)", notes = "以商品维度创建的对账单 编辑对账不用做 mark at  20201102 10:30 确认人为: 张雪")
    @PostMapping("/opEditAccounting")
    @ResponseBody
    public R<Object> opEditAccounting() {

        R<Object> result = new R<>();

        try {
            // 对账单Id
            Long id = getLong("id");
            // 订单 orderSn
            String orderSn = getString("orderSn");
            // 是否新增 默认为 0
            String add = getString("add");

            AccountingUnifiedSupplier statementOfAccount = accountingUnifiedSupplierDubboConsumerService.findById(id);

            if (null == statementOfAccount) {
                result.setCode(400);
                result.setSuccess(false);
                result.setMessage("对账单 查找不到? 给错参数? 正确的参数为[id]");
                result.setData(statementOfAccount);
                return result;
            }

            // TODO 写死
            if (statementOfAccount.getInvoiceStatus() == 1) {
                result.setCode(400);
                result.setSuccess(false);
                result.setMessage("已开票 对账单 不可继续操作！");
                result.setData(statementOfAccount);
                return result;
            }

            UnifiedOrder unifiedOrder = unifiedOrderDubboConsumerService.findBySn(orderSn);

            if (null == unifiedOrder) {
                result.setCode(400);
                result.setSuccess(false);
                result.setMessage("订单 查找不到? 给错参数? 正确的参数为[orderSn]");
                result.setData(unifiedOrder);
                return result;
            }

            if (null == statementOfAccount.getSaleId()) {
                result.setCode(400);
                result.setSuccess(false);
                result.setMessage("对账单 没有 设定供应商? 请联系管理员! 异常对账单Id:" + id);
                result.setData(unifiedOrder);
                return result;
            }

            if (null == unifiedOrder.getSaleId()) {
                result.setCode(400);
                result.setSuccess(false);
                result.setMessage("要添加的订单 没有 设定供应商? 请联系管理员! 异常订单,订单Sn:" + orderSn);
                result.setData(unifiedOrder);
                return result;
            }

            if (!statementOfAccount.getSaleId().equals(unifiedOrder.getSaleId())) {
                result.setCode(400);
                result.setSuccess(false);
                result.setMessage("订单 的供应商 与 对账单 的供应商 不一样!");
                result.setData(unifiedOrder);
                return result;
            }

            if (add.equals("1") && unifiedOrder.getAccountingStateSupplier().equals(UnifiedOrderAccountingStateEnum.已对账.getKey())) {
                result.setCode(400);
                result.setSuccess(false);
                result.setMessage("该订单已对账，不可继续操作！");
                result.setData(unifiedOrder);
                return result;
            }

            accountingUnifiedSupplierDubboConsumerService.opEditAccounting(getToken(), statementOfAccount, unifiedOrder, add);

            result.setSuccess(true);

        } catch (Exception e) {

            result.setCode(String.valueOf(e.hashCode()));
            result.setSuccess(false);
            result.setMessage(e.getMessage());

            log.error(ExceptionUtils.getMessage(e));
            e.printStackTrace();
        }

        return result;
    }

    /***
     * 供应商结算 - 对账单 - opt重新对账
     *
     * @return
     */
    @ApiOperation(value = "供应商对账(结算) - 对账单 - opt重新对账 - 维度兼容未整改", notes = "")
    @PostMapping("/opAgainAccounting")
    @ResponseBody
    public R<AccountingUnifiedSupplier> opAgainAccounting() {

        R<AccountingUnifiedSupplier> result = new R<>();

        try {

            Long accountingOrderId = getLong("id");

            // -1-已取消;0-已提交(未确认);1-已确认;2-已拒绝;3-待提交(创建对账单 初始 状态)
            AccountingUnifiedSupplier statementOfAccount = accountingUnifiedSupplierDubboConsumerService.findById(accountingOrderId);

            // TODO 写死
            if (statementOfAccount.getInvoiceStatus() == 1) {
                result.setCode(400);
                result.setSuccess(false);
                result.setMessage("已开票对账单不可继续操作！");
                return result;
            }

//            accountingUnifiedSupplierDubboConsumerService.opAgainAccounting(getToken(), statementOfAccount);

            accountingUnifiedSupplierDubboConsumerService.opAgain(accountingOrderId, getToken());


            result.setData(statementOfAccount);

        } catch (Exception e) {

            result.setCode(String.valueOf(e.hashCode()));
            result.setSuccess(false);
            result.setMessage(e.getMessage());

            log.error(ExceptionUtils.getMessage(e));
            e.printStackTrace();
        }

        return result;
    }


    @ApiOperation(value = "供应商对账(结算) - 对账单 - opt拒绝对账(申诉操作) - 维度兼容不需整改 (供应商申诉就是拒绝对账的，外加一个申诉申请)", notes = "")
    @PostMapping("/opRejectAccounting")
    @ResponseBody
    public R<AccountingUnifiedSupplier> opRejectAccounting() {

        R<AccountingUnifiedSupplier> result = new R<>();

        try {

            Long accountingOrderId = getLong("id");

            // -1-已取消;0-已提交(未确认);1-已确认;2-已拒绝;3-待提交(创建对账单 初始 状态)
            AccountingUnifiedSupplier statementOfAccount = accountingUnifiedSupplierDubboConsumerService.findById(accountingOrderId);

            // TODO 写死
            if (statementOfAccount.getInvoiceStatus() == 1) {
                result.setCode(400);
                result.setSuccess(false);
                result.setMessage("已开票对账单不可继续操作！");
                return result;
            }

//            statementOfAccount.setAccountingStatus(AccountingOrderAccountingStatusEnum.已拒绝.getKey());
//            statementOfAccount.setUpdateTime(new Date());
//            accountingUnifiedSupplierDubboConsumerService.opRejectAccounting(getToken(), statementOfAccount);
            accountingUnifiedSupplierDubboConsumerService.opAppeal(accountingOrderId, getToken());

            result.setData(statementOfAccount);

        } catch (Exception e) {

            result.setCode(String.valueOf(e.hashCode()));
            result.setSuccess(false);
            result.setMessage(e.getMessage());

            log.error(ExceptionUtils.getMessage(e));
            e.printStackTrace();
        }

        return result;
    }

    /***
     * 供应商结算 - 对账单 - opt取消对账
     *
     * @return
     */
    @ApiOperation(value = "供应商对账(结算) - 对账单 - opt取消对账 - 维度兼容不需整改 (供应商申诉就是拒绝对账的，外加一个申诉申请)", notes = "")
    @PostMapping("/opCancelAccounting")
    @ResponseBody
    public R<AccountingUnifiedSupplier> opCancelAccounting() {

        R<AccountingUnifiedSupplier> result = new R<>();

        try {

            Long accountingOrderId = getLong("id");

            // -1-已取消;0-已提交(未确认);1-已确认;2-已拒绝;3-待提交(创建对账单 初始 状态)
            AccountingUnifiedSupplier statementOfAccount = accountingUnifiedSupplierDubboConsumerService.findById(accountingOrderId);

            // TODO 写死
            if (statementOfAccount.getInvoiceStatus() == 1) {
                result.setCode(400);
                result.setSuccess(false);
                result.setMessage("已开票对账单不可继续操作！");
                return result;
            }

//            statementOfAccount.setAccountingStatus(AccountingOrderAccountingStatusEnum.已拒绝.getKey());
//            statementOfAccount.setUpdateTime(new Date());
//            accountingUnifiedSupplierDubboConsumerService.opCancelAccounting(getToken(), statementOfAccount);

            accountingUnifiedSupplierDubboConsumerService.opCancel(accountingOrderId, getToken());

            result.setData(statementOfAccount);

        } catch (Exception e) {

            result.setCode(String.valueOf(e.hashCode()));
            result.setSuccess(false);
            result.setMessage(e.getMessage());

            log.error(ExceptionUtils.getMessage(e));
            e.printStackTrace();
        }

        return result;
    }


    /***
     * 供应商结算 - 对账单 - opt更新状态
     * opt 提交对账 state 0
     * opt 确认对账 state 1
     *
     * /accounting/unified/supplier/statement/updatestate
     * @return
     */
    @Deprecated
    @ApiOperation(value = "(弃用)供应商对账(结算) - 对账单 - opt更新状态 | opt 提交对账 state 0 | opt 确认对账 state 1", notes = "-1-已取消;0-已提交(未确认);1-已确认;2-已拒绝;3-待提交(创建对账单 初始 状态)")
    @PostMapping("/updatestate")
    @ResponseBody
    public R<AccountingUnifiedSupplier> updateState() {

        R<AccountingUnifiedSupplier> result = new R<>();

        try {

            Long id = getLong("id");

            // -1-已取消;0-已提交(未确认);1-已确认;2-已拒绝;3-待提交(创建对账单 初始 状态)
            Integer state = getInteger("state");

            AccountingUnifiedSupplier statementOfAccount4Check = accountingUnifiedSupplierDubboConsumerService.findById(id);

            // TODO 写死
            if (statementOfAccount4Check.getInvoiceStatus() == 1) {
                result.setCode(400);
                result.setSuccess(false);
                result.setMessage("已开票对账单不可继续操作！");
                return result;
            }

            AccountingUnifiedSupplier statementOfAccount4Update = new AccountingUnifiedSupplier();

            statementOfAccount4Update.setAccountingStatus(state);
            statementOfAccount4Update.setId(statementOfAccount4Check.getId());
            statementOfAccount4Update.setUpdateTime(new Date());
            accountingUnifiedSupplierDubboConsumerService.updateObj(getToken(), statementOfAccount4Update);

            result.setData(statementOfAccount4Update);

        } catch (Exception e) {

            result.setCode(String.valueOf(e.hashCode()));
            result.setSuccess(false);
            result.setMessage(e.getMessage());

            log.error(ExceptionUtils.getMessage(e));
            e.printStackTrace();
        }

        return result;
    }
}
