package cn.superdesk.uniorder.controller.invoice.customer.state;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.superdesk.uniorder.common.bizScene.invoice.common.InvoiceTypeScene;
import cn.superdesk.uniorder.common.bizScene.invoice.customer.InvoiceApplyCustomerScene;
import cn.superdesk.uniorder.common.constants.ResponseMsgConstants;
import cn.superdesk.uniorder.common.enums.accounting.AccountingOrderTypeDimEnum;
import cn.superdesk.uniorder.common.enums.invoice.customer.InvoiceApplyCustomerInvoiceProgressingStatusEnum;
import cn.superdesk.uniorder.common.enums.invoice.customer.InvoiceApplyCustomerMakeInvoiceStatusEnum;
import cn.superdesk.uniorder.common.enums.invoice.customer.InvoiceApplyCustomerReceiveInvoiceStatusEnum;
import cn.superdesk.uniorder.common.exception.utils.ExceptionUtils;
import cn.superdesk.uniorder.common.lamda.AnLamdaUtils;
import cn.superdesk.uniorder.common.rest.response.R;
import cn.superdesk.uniorder.common.rest.response.ResponseResultOuterUtils;
import cn.superdesk.uniorder.controller.base.BaseController;
import cn.superdesk.uniorder.dao.entity.invoice.customer.InvoiceApply;
import cn.superdesk.uniorder.dto.param.invoice.customer.InvoiceApplyCustomerQueryCriteriaV2_1;
import cn.superdesk.uniorder.dto.param.invoice.customer.status.InvoiceApplyCustomerOpReceiveInvoiceStatusForm;
import cn.superdesk.uniorder.dto.param.invoice.customer.status.InvoiceApplyCustomerOpReceiveInvoiceStatusFormInnerListItem;
import cn.superdesk.uniorder.dto.param.invoice.customer.status.OpChangeStatusBaseItem;
import cn.superdesk.uniorder.dto.vo.accounting.score.customer.AccountingOrderScoreCustomerListItemVo;
import cn.superdesk.uniorder.dto.vo.invoice.customer.InvoiceApplyCustomerPageVo;
import cn.superdesk.uniorder.dto.vo.invoice.customer.receiveInvoiceStatus.InvoiceManagerCustomerOpReceiveInvoiceStatusPageVo;
import cn.superdesk.uniorder.dubbo.consumer.accounting.customer.AccountingScoreCustomerDubboConsumerService;
import cn.superdesk.uniorder.dubbo.consumer.invoice.customer.InvoiceApplyCustomerDubboConsumerService;
import cn.superdesk.uniorder.dubbo.consumer.invoice.customer.state.InvoiceApplyFieldReceiveInvoiceStatusDubboConsumerService;
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.*;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description: 运营领票部分 - 简易状态机 星型结构
 * @Author: linjinyu
 * @CreateDate: 10/12/20 4:28 PM
 * @UpdateUser: linjinyu
 * @UpdateDate: 10/12/20 4:28 PM
 * @UpdateRemark: 修改内容
 * @Version: 1.0
 */
@Api(value = "积分结算-发票单-运营领票部分-InvoiceApply-ReceiveInvoiceStatus", tags = {"积分结算-发票单-运营领票部分-InvoiceApply-ReceiveInvoiceStatus"})
@Slf4j
@RestController
@RequestMapping("/invoice/apply/customer/score/state/receiveInvoiceStatus")
public class InvoiceApplyCustomerScoreFieldReceiveInvoiceStatusController extends BaseController {

    @Autowired
    private InvoiceApplyCustomerDubboConsumerService                  invoiceApplyCustomerDubboConsumerService;
    @Autowired
    private InvoiceApplyFieldReceiveInvoiceStatusDubboConsumerService invoiceApplyFieldReceiveInvoiceStatusDubboConsumerService;

    @Autowired
    private AccountingScoreCustomerDubboConsumerService accountingScoreCustomerDubboConsumerService;

    @Deprecated
    @ApiOperation(value = "InvoiceApply-ReceiveInvoiceStatus-op 未领票 0")
    @RequestMapping(value = "/opInit/{id}", method = RequestMethod.POST)
    @ResponseBody
    public R<?> opInit(@PathVariable("id") Long id) {

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

        try {
            InvoiceApply entity = invoiceApplyCustomerDubboConsumerService.findById(id);
            invoiceApplyFieldReceiveInvoiceStatusDubboConsumerService.opInit(getToken(), entity);
            result.setSuccess(true);

        } catch (Exception e) {

            result.setSuccess(false);
            result.setMessage(ResponseMsgConstants.ERROR_UNKNOW);
            log.error(ExceptionUtils.getMessage(e));
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 积分结算 > 发票管理 > 运营领票 > op运营领票 页面初始化
     *
     * @param accountingOrderSn
     * @return
     */
    @ApiOperation(value = "op运营领票-页面初始化 v2.2", notes = "积分结算v2.2-20220509")
    @RequestMapping(value = "/opInit/loading/pageData/{accountingOrderSn}", method = RequestMethod.POST)
    @ResponseBody
    public R<InvoiceManagerCustomerOpReceiveInvoiceStatusPageVo> opInitLoadingPageData(@PathVariable("accountingOrderSn") String accountingOrderSn) {

        try {

            List<InvoiceApplyCustomerPageVo> pageVoList = invoiceApplyCustomerDubboConsumerService.findInvoiceListFocusScoreV2_1(
                    InvoiceApplyCustomerQueryCriteriaV2_1
                            .builder()
                            .invoiceProgressingStatusSelected(Arrays.asList(
                                    InvoiceApplyCustomerInvoiceProgressingStatusEnum.待开票.getKey(),
                                    InvoiceApplyCustomerInvoiceProgressingStatusEnum.待领票.getKey(),
                                    InvoiceApplyCustomerInvoiceProgressingStatusEnum.待寄票.getKey(),
                                    InvoiceApplyCustomerInvoiceProgressingStatusEnum.待回款.getKey(),
                                    InvoiceApplyCustomerInvoiceProgressingStatusEnum.已完成.getKey()
                            ))
                            .accountingOrderSn(accountingOrderSn)
                            .build(),
                    getToken()
            );

            AccountingOrderScoreCustomerListItemVo accountingOrderScoreCustomerVo = accountingScoreCustomerDubboConsumerService.getAccountingOrderListByAccountingOrderSn(accountingOrderSn, getToken());

            return ResponseResultOuterUtils.createSuccesResult(
                    "init",
                    InvoiceManagerCustomerOpReceiveInvoiceStatusPageVo
                            .builder()
                            .pageVoList(pageVoList)
                            .accountingOrder(accountingOrderScoreCustomerVo)
                            .build()
            );

        } catch (Exception e) {

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

            return ResponseResultOuterUtils.createErrorResult("500", ResponseMsgConstants.ERROR_UNKNOW);
        }

    }

    @Deprecated
    @ApiOperation(value = "op运营领票-单个开票申请 已领票 1")
    @RequestMapping(value = "/opReceive/{id}", method = RequestMethod.POST)
    @ResponseBody
    public R<?> opReceive(@PathVariable("id") Long id) {

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

        try {

            InvoiceApply entity = invoiceApplyCustomerDubboConsumerService.findById(id);
            invoiceApplyFieldReceiveInvoiceStatusDubboConsumerService.opReceive(getToken(), entity);
            result.setSuccess(true);

        } catch (Exception e) {

            result.setSuccess(false);
            result.setMessage(ResponseMsgConstants.ERROR_UNKNOW);
            log.error(ExceptionUtils.getMessage(e));
            e.printStackTrace();
        }

        return result;
    }


    @ApiOperation(value = "op运营领票-对账单维度 已领票 1")
    @RequestMapping(value = "/opReceive/dim/accountingOrder", method = RequestMethod.POST)
    @ResponseBody
    public R<?> opReceiveDimAccountingOrder(@RequestBody InvoiceApplyCustomerOpReceiveInvoiceStatusForm form) { // 以对账单维度自动补全 - 20220111

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

        // TODO 简单验证

        if (CollUtil.isEmpty(form.getSubmitList())) {
            return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常");
        }


        try {

            /****************************************** 对账单维度 - 基于对账单编号 start ******************************************/

            List<String> accountingOrders = form.getSubmitList()
                    .stream()
                    .filter(AnLamdaUtils.distinctByKey(o -> o.getAccountingOrderSn()))
                    .map(OpChangeStatusBaseItem::getAccountingOrderSn)
                    .collect(Collectors.toList());

            if (CollUtil.isEmpty(accountingOrders)) {
                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常");
            }

            if (accountingOrders.size() > 1) {
                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常");
            }

            /****************************************** 对账单维度 - 基于对账单编号   end ******************************************/

            /****************************************** 开票申请维度 - 基于对账单编号 查数据库中存在的发票单 start ******************************************/

            List<InvoiceApply> entitysExistDb = invoiceApplyCustomerDubboConsumerService.findByAccountingOrderSn(accountingOrders.get(0), AccountingOrderTypeDimEnum.积分订单);

            if (CollUtil.isEmpty(entitysExistDb)) {
                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常");
            }

            /****************************************** 开票申请维度 - 基于对账单编号 查数据库中存在的发票单   end ******************************************/

            /****************************************** 开票申请 - 前端提交 start ******************************************/

            List<Long> invoiceApplyIds = form.getSubmitList()
                    .stream()
                    .map(InvoiceApplyCustomerOpReceiveInvoiceStatusFormInnerListItem::getInvoiceApplyId)
                    .collect(Collectors.toList());

            List<InvoiceApply> entitysQueryBySubmit = invoiceApplyCustomerDubboConsumerService.findByIds(invoiceApplyIds);
            List<InvoiceApply> entitysNeedOpReceive = entitysQueryBySubmit
                    .stream()
                    .filter(o -> ArrayUtil.contains(InvoiceTypeScene.modesV2_1_Array_SceneNeedOpReceive(), o.getInvoiceMode()))
                    .collect(Collectors.toList());

            if (CollUtil.isEmpty(invoiceApplyIds)) {
                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常[发票单001]");
            }
            if (CollUtil.isEmpty(entitysQueryBySubmit)) {
                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常[发票单002]");
            }
            if (invoiceApplyIds.size() != entitysQueryBySubmit.size()) {
                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常[发票单003]");
            }

            //  【【结算中心-测试环境】积分结算-发票管理-CAA2022050622485248【运营领票】后，部分航信纸质发票“申请状态”仍为“待领票”】
            //  https://www.tapd.cn/33003868/bugtrace/bugs/view?bug_id=1133003868001005067
            // 加此逻辑是因为这个问题，为了解决这个问题，就是分页问题，不传pageSize的话默认为10, 而数据为11条 mark by linjinyu at 20220509
            // 1. 加了 opInitLoadingPageData 接口
            // 2. 下边的逻辑
            if (entitysExistDb.size() != entitysQueryBySubmit.size()) {
                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据 [完整性] 异常");
            }


            /**************************************** 申请状态 start ****************************************/

            List<Integer> invoiceProgressingStatusExistDb = entitysExistDb
                    .stream()
                    .filter(AnLamdaUtils.distinctByKey(o -> o.getInvoiceStatus()))
                    .map(InvoiceApply::getInvoiceStatus)
                    .collect(Collectors.toList());

            /**************************************** 开票状态 start ****************************************/

            List<Integer> makeInvoiceStatusExistDb = entitysExistDb
                    .stream()
                    .filter(AnLamdaUtils.distinctByKey(o -> o.getMakeInvoiceStatus()))
                    .map(InvoiceApply::getMakeInvoiceStatus)
                    .collect(Collectors.toList());


            /**************************************** 领票登记状态 start ****************************************/

            List<Integer> receiveInvoiceStatusExistDb = entitysExistDb
                    .stream()
                    .filter(AnLamdaUtils.distinctByKey(o -> o.getReceiveInvoiceStatus()))
                    .map(InvoiceApply::getReceiveInvoiceStatus)
                    .collect(Collectors.toList());
            List<Integer> receiveInvoiceStatusQueryBySubmit = entitysQueryBySubmit
                    .stream()
                    .filter(AnLamdaUtils.distinctByKey(o -> o.getReceiveInvoiceStatus()))
                    .map(InvoiceApply::getReceiveInvoiceStatus)
                    .collect(Collectors.toList());
            List<Integer> receiveInvoiceStatusNeedOpReceive = entitysNeedOpReceive
                    .stream()
                    .filter(AnLamdaUtils.distinctByKey(o -> o.getReceiveInvoiceStatus()))
                    .map(InvoiceApply::getReceiveInvoiceStatus)
                    .collect(Collectors.toList());


            /**
             * 混合时冲突
             * superdesk-uniorder/superdesk-uniorder-web/src/main/java/cn/superdesk/uniorder/controller/invoice/customer/doc/op运营领票/混合_深圳航信电子发票_线下开票
             */

//            if (CollUtil.isEmpty(receiveInvoiceStatusExistDb)) {
//                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常");
//            }
//
//            if (receiveInvoiceStatusExistDb.size() > 1) {
//                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常");
//            }

            /**************************************** op确认领票 - 改逻辑 20220510 start ****************************************/


//            InvoiceApplyCustomerReceiveInvoiceStatusEnum invoiceApplyCustomerReceiveInvoiceStatusExistDb       = InvoiceApplyCustomerReceiveInvoiceStatusEnum.get(receiveInvoiceStatusExistDb.get(0));
//            InvoiceApplyCustomerReceiveInvoiceStatusEnum invoiceApplyCustomerReceiveInvoiceStatusNeedOpReceive = InvoiceApplyCustomerReceiveInvoiceStatusEnum.get(receiveInvoiceStatusNeedOpReceive.get(0));
//
////            if (invoiceApplyCustomerReceiveInvoiceStatusExistDb != InvoiceApplyCustomerReceiveInvoiceStatusEnum.未领票) {
////                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常,要求状态为[未领票]");
////            }
//            if (invoiceApplyCustomerReceiveInvoiceStatusNeedOpReceive != InvoiceApplyCustomerReceiveInvoiceStatusEnum.未领票) {
//                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常,要求状态为[未领票]");
//            }

//            https://docs.qq.com/doc/DYUZOREhreVhiVlZL
//            ·该对账单下所有开票申请的开票状态均为“已开票”，否则不允许确认领票，1.5s提示“该对账单所有开票申请的开票状态存在部分未开票”；【20220510新增】
//            ·该对账单下所有有效的开票申请的领票状态存在全部/部分为“未领票”，否则不允许确认领票，1.5提示“该对账单所有开票申请的领票状态全部已领票，无需领票”；【20220510新增】
//            ·该对账单下所有开票申请的申请状态为“待领票/待回款”，否则不允许确认领票，1.5s提示“该对账单的开票申请数据发生变更，请返回检查”；【20220510去掉此判断】---


            // 逻辑 ·该对账单下所有开票申请的开票状态均为“已开票”，否则不允许确认领票，1.5s提示“该对账单所有开票申请的开票状态存在部分未开票”；【20220510新增】 start

            if (CollUtil.isEmpty(makeInvoiceStatusExistDb)) {
                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常[开票状态] 未知");
            } else if (makeInvoiceStatusExistDb.size() == 1) {

                // 开票状态 唯一的情况
                InvoiceApplyCustomerMakeInvoiceStatusEnum invoiceApplyCustomerMakeInvoiceStatusEnumExistDb = InvoiceApplyCustomerMakeInvoiceStatusEnum.get(makeInvoiceStatusExistDb.get(0));

                // 意思是 如果这个唯一情况 的开票状态 为 待开票 开票中
                if (ArrayUtil.contains(
                        InvoiceApplyCustomerScene.statusV2_1_Array_MakeInvoiceSceneOpReceiveStateCheck(),
                        invoiceApplyCustomerMakeInvoiceStatusEnumExistDb.getKey())
                ) {
                    return ResponseResultOuterUtils.createErrorResult("500", "该对账单所有开票申请的开票状态存在部分未开票");
                }

            } else if (makeInvoiceStatusExistDb.size() > 1) {
                // 意思是 不唯一情况 是不可能 达到 该对账单下所有开票申请的开票状态均为 已开票
                return ResponseResultOuterUtils.createErrorResult("500", "该对账单所有开票申请的开票状态存在部分未开票");
            } else {
            }

            // 逻辑 ·该对账单下所有开票申请的开票状态均为“已开票”，否则不允许确认领票，1.5s提示“该对账单所有开票申请的开票状态存在部分未开票”；【20220510新增】 start


            // 逻辑 该对账单下所有有效的开票申请的领票状态存在全部/部分为“未领票”，否则不允许确认领票，1.5提示“该对账单所有开票申请的领票状态全部已领票，无需领票”；【20220510新增】start

            if (CollUtil.isEmpty(receiveInvoiceStatusExistDb)) {
                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常[领票状态] 未知");
            } else if (receiveInvoiceStatusExistDb.size() == 1) {

                // 领票状态 唯一的情况
                InvoiceApplyCustomerReceiveInvoiceStatusEnum invoiceApplyCustomerReceiveInvoiceStatusExistDb = InvoiceApplyCustomerReceiveInvoiceStatusEnum.get(receiveInvoiceStatusExistDb.get(0));

                if (invoiceApplyCustomerReceiveInvoiceStatusExistDb == InvoiceApplyCustomerReceiveInvoiceStatusEnum.已领票) {
                    return ResponseResultOuterUtils.createErrorResult("500", "该对账单所有开票申请的领票状态全部已领票，无需领票");
                }

            } else if (receiveInvoiceStatusExistDb.size() > 1) {

                // 领票状态 不唯一的情况 好像不用做了 ---- 前置条件 开票状态均为-已开票

            } else {

            }

            // 逻辑 该对账单下所有有效的开票申请的领票状态存在全部/部分为“未领票”，否则不允许确认领票，1.5提示“该对账单所有开票申请的领票状态全部已领票，无需领票”；【20220510新增】  end


            /**************************************** op确认领票 - 改逻辑 20220510 start ****************************************/

            invoiceApplyFieldReceiveInvoiceStatusDubboConsumerService.opReceive(entitysQueryBySubmit, form, getToken());

            result.setSuccess(true);

        } catch (Exception e) {

            result.setSuccess(false);
            result.setMessage(ResponseMsgConstants.ERROR_UNKNOW);
            log.error(ExceptionUtils.getMessage(e));
            e.printStackTrace();
        }
        return result;
    }


}
