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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.superdesk.uniorder.common.constants.ResponseMsgConstants;
import cn.superdesk.uniorder.common.enums.invoice.common.InvoiceTypeMoudelXModeEnum;
import cn.superdesk.uniorder.common.enums.invoice.customer.InvoiceApplyCustomerInvoiceProgressingStatusEnum;
import cn.superdesk.uniorder.common.enums.accounting.AccountingOrderInvoiceApplyStatusEnum;
import cn.superdesk.uniorder.common.enums.accounting.AccountingOrderTypeDimEnum;
import cn.superdesk.uniorder.common.enums.accounting.customer.AccountingOrderCustomerAccountingStatusEnum;
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.accounting.score.customer.AccountingScoreCustomer;
import cn.superdesk.uniorder.dao.entity.invoice.customer.InvoiceApply;
import cn.superdesk.uniorder.dto.param.invoice.customer.status.OpChangeStatusBaseItem;
import cn.superdesk.uniorder.dto.param.invoice.customer.status.OpMailTickStatusFormV2_1;
import cn.superdesk.uniorder.dto.param.invoice.customer.status.OpMailTickStatusFormInnerListItemV2_1;
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.InvoiceApplyFieldMailTickStatusDubboConsumerService;
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.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 = "积分结算v2.1-发票单-寄票登记部分-InvoiceApply-MailTickStatus", tags = {"积分结算v2.1-发票单-寄票登记部分-InvoiceApply-MailTickStatus"})
@Slf4j
@RestController
@RequestMapping("/invoice/apply/customer/score/state/mailTickStatus")
public class InvoiceApplyCustomerScoreFieldMailTickStatusV2_1Controller extends BaseController {

    @Autowired
    private InvoiceApplyCustomerDubboConsumerService            invoiceApplyCustomerDubboConsumerService;
    @Autowired
    private InvoiceApplyFieldMailTickStatusDubboConsumerService invoiceApplyFieldMailTickStatusDubboConsumerService;

    @Autowired
    private AccountingScoreCustomerDubboConsumerService accountingScoreCustomerDubboConsumerService;

    /**
     * 积分结算 > 发票管理 > 寄票登记 > op寄票登记|op修改寄票 页面初始化
     *
     * @param id
     * @return
     */
    @Deprecated
    @ApiOperation(value = "op寄票登记|op修改寄票-页面初始化 InvoiceApply-MailTickStatus-op 未邮寄 0")
    @RequestMapping(value = "/opInit/{id}", method = RequestMethod.POST)
    @ResponseBody
    public R<?> opInit(@PathVariable("id") Long id) {

        try {

            InvoiceApply entity = invoiceApplyCustomerDubboConsumerService.findById(id);
            invoiceApplyFieldMailTickStatusDubboConsumerService.opInit(entity, getToken());

            return ResponseResultOuterUtils.createSuccesResult();

        } catch (Exception e) {

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

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

    }

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

        try {

            InvoiceApply entity = invoiceApplyCustomerDubboConsumerService.findById(id);
            invoiceApplyFieldMailTickStatusDubboConsumerService.opComplete(entity, getToken());

            return ResponseResultOuterUtils.createSuccesResult();

        } catch (Exception e) {

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

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

    }

    /**
     * op寄票登记 -> op确认寄票
     * 只适用于v2.1逻辑 v2.2逻辑变更
     * v2.1 逻辑为 发票文件 与 快递信息 都是挂在 发票单上
     * v2.2 逻辑为 发票文件 与 快递信息 都是挂在 对账单上
     * mark by linjinyu at 20220429
     *
     * @param form
     * @return
     */
    @Deprecated
    @ApiOperation(value = "op寄票登记-op确认寄票 v2.1 InvoiceApply-MailTickStatus-op 已邮寄 1 - 对账单维度", notes = "积分结算v2.1 - 20220111")
    @RequestMapping(value = "/opComplete/dim/accountingOrder", method = RequestMethod.POST)
    @ResponseBody
    public R<?> opCompleteDimAccountingOrder(@RequestBody OpMailTickStatusFormV2_1 form) { // 以对账单维度自动补全 - 20220111

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

        // TODO 简单验证

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

        try {

            /****************************************** 对账单编号 start ******************************************/

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

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

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

            /**************************************** 对账单 start ****************************************/

            String accountingOrderSn = accountingOrderSns.get(0);

            AccountingScoreCustomer accountingScoreCustomer = accountingScoreCustomerDubboConsumerService.findByAccountingOrderSn(accountingOrderSn);

            if (ObjectUtil.isNull(accountingScoreCustomer)) {
                return ResponseResultOuterUtils.createErrorResult("500", "对账单数据异常");
            }

            if (accountingScoreCustomer.getAccountingStatus().compareTo(AccountingOrderCustomerAccountingStatusEnum.已确认.getKey()) != 0) {
                return ResponseResultOuterUtils.createErrorResult("500", "该对账单状态发生变更，请检查");
            }

            if (accountingScoreCustomer.getInvoiceStatus().compareTo(AccountingOrderInvoiceApplyStatusEnum.全部申请.getKey()) != 0) {
                return ResponseResultOuterUtils.createErrorResult("500", "该对账单申请状态未全部申请，请返回检查");
            }


            /**************************************** 对账单 start ****************************************/

//（2）服务端需判断：
//·该对账单状态为“已确认”，否则不允许确认寄票，1.5s提示“该对账单状态发生变更，请检查”；
//·该对账单的申请状态为“全部申请”，否则不允许确认寄票，1.5s提示“该对账单申请状态未全部申请，请返回检查”；
//·该对账单下所有开票申请均存在且有效，否则不允许确认寄票，1.5s提示“该对账单的开票申请数据发生变更，请返回检查”；
//·该对账单下所有开票申请的申请状态为“待寄票/待回款”，否则不允许确认寄票，1.5s提示“该对账单的开票申请数据发生变更，请返回检查”；
//满足以上保存条件，即确认寄票成功： // mark by linjinyu at 202203312209 需求文本有误 确认领票 -> 确认寄票
//①开票方式为“深圳航信电子发票”的开票申请：其相关快递公司/快递单号/寄票人/寄票时间等数据及状态，不作任何更新改动，仍为原数据；
//②开票方式为“线下开票”的开票申请：
//·对应开票申请的申请状态变更为“待回款”；
//·对应开票申请的寄票状态变更为“已寄票”；
//·快递公司&快递单号写入到对应的开票申请中，快递公司以ID关联存储，可能未来存在快递公司名称修改；
//·对应开票申请的寄票人姓名和时间记录为当前操作人姓名和时间；
//·注：当前页面无“已红冲/已作废”的开票申请，因此“已红冲/已作废”的开票申请的状态和数据不作任何变动；
//③1.5s提示“寄票成功”，关闭当前页签，自动跳转到“发票管理”列表页面，列表数据重新获取；


            /****************************************** 开票申请 - 数据库 start ******************************************/

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

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

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

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

            List<InvoiceApply> entitysSubmit      = invoiceApplyCustomerDubboConsumerService.findByIds(invoiceApplyIds);
            List<InvoiceApply> entitysOnlyOffLine = entitysSubmit.stream().filter(o -> o.getInvoiceMode().equals(InvoiceTypeMoudelXModeEnum.线下开票.getKey())).collect(Collectors.toList());

            if (CollUtil.isEmpty(invoiceApplyIds)) {
                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常，[001]");
            }
            if (CollUtil.isEmpty(entitysSubmit)) {
                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常，[002]");
            }
            // 前端没有因为有一个是线上而少传一个，所以这里不能用过滤后只有线下的
            if (invoiceApplyIds.size() != entitysSubmit.size()) {
                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常，[003]");
            }


            /**************************************** 只处理线下开票情况 start ****************************************/

            /**************************************** |---- 检查 申请状态 start ****************************************/

            // 错误 在混合的情况下是错的
//            List<Integer> mailTickStatus = entitysExistDb.stream()
            // 在混合的情况是下是排除 线上开票方式
            List<Integer> invoiceProgressingStatus = entitysOnlyOffLine.stream()
                    // 排除线上
                    .filter(AnLamdaUtils.distinctByKey(o -> o.getInvoiceStatus())).map(InvoiceApply::getInvoiceStatus).collect(Collectors.toList());

            if (CollUtil.isEmpty(invoiceProgressingStatus)) {
                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常，[申请状态]");
            }
            if (invoiceProgressingStatus.size() > 1) {
                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常，[申请状态] ");
            }

            //·该对账单下所有开票申请的申请状态为“待寄票/待回款”，否则不允许确认寄票，1.5s提示“该对账单的开票申请数据发生变更，请返回检查”；
            InvoiceApplyCustomerInvoiceProgressingStatusEnum invoiceApplyCustomerInvoiceProgressingStatusEnum = InvoiceApplyCustomerInvoiceProgressingStatusEnum.get(invoiceProgressingStatus.get(0));


            Integer[] invoiceProgressingStatusNeed = {InvoiceApplyCustomerInvoiceProgressingStatusEnum.待寄票.getKey(), InvoiceApplyCustomerInvoiceProgressingStatusEnum.待回款.getKey()};
            if (!ArrayUtil.contains(invoiceProgressingStatusNeed, invoiceApplyCustomerInvoiceProgressingStatusEnum.getKey())) {
                return ResponseResultOuterUtils.createErrorResult("500", "该对账单的开票申请数据发生变更，请返回检查");
            }

            /**************************************** |---- 检查 申请状态   end ****************************************/


            /**************************************** |---- 检查 寄票状态 start ****************************************/

//            // 错误 在混合的情况下是错的
////            List<Integer> mailTickStatus = entitysExistDb.stream()
//            // 在混合的情况是下是排除 线上开票方式
//            List<Integer> mailTickStatus = entitysOnlyOffLine.stream()
//                    // 排除线上
////                    .filter(o -> o.getInvoiceMode().equals(InvoiceTypeMoudelXModeEnum.线下开票.getKey()))
//                    .filter(AnLamdaUtils.distinctByKey(o -> o.getMailTickStatus())).map(InvoiceApply::getMailTickStatus).collect(Collectors.toList());
//
//            if (CollUtil.isEmpty(mailTickStatus)) {
//                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常，[寄票状态]");
//            }
//            if (mailTickStatus.size() > 1) {
//                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常，[寄票状态]");
//            }
//
//            InvoiceApplyCustomerMailTickStatusEnum invoiceApplyCustomerMailTickStatusEnum = InvoiceApplyCustomerMailTickStatusEnum.get(mailTickStatus.get(0));
//
//            if (invoiceApplyCustomerMailTickStatusEnum != InvoiceApplyCustomerMailTickStatusEnum.未邮寄) {
////				return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常,要求状态为[未邮寄]");
//                return ResponseResultOuterUtils.createErrorResult("500", "该对账单的开票申请数据发生变更，请返回检查");
//            }

            /**************************************** |---- 检查 寄票状态   end ****************************************/


            /**************************************** 只处理线下开票情况   end ****************************************/


            // 错误 在混合的情况下是错的
//            invoiceApplyFieldMailTickStatusDubboConsumerService.opComplete(getToken(), entitysExistDb, form);
            // 在混合的情况是下是排除 线上开票方式
            invoiceApplyFieldMailTickStatusDubboConsumerService.opCompleteV2_1(entitysOnlyOffLine, 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;
    }


    /**
     * op修改寄票 -> op确认修改
     *
     * @param form
     * @return
     */
    @Deprecated
    @ApiOperation(value = "op修改寄票-op确认修改 v2.1 InvoiceApply-MailTickStatus-op 已邮寄 1 - 对账单维度", notes = "积分结算v2.1 - 20220111")
    @RequestMapping(value = "/opEdit/dim/accountingOrder", method = RequestMethod.POST)
    @ResponseBody
    public R<?> opEditDimAccountingOrder(@RequestBody OpMailTickStatusFormV2_1 form) { // 以对账单维度自动补全 - 20220111

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

        // TODO 简单验证

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

        try {

            /****************************************** 对账单编号 start ******************************************/

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

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

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

            /**************************************** 对账单 start ****************************************/

            String accountingOrderSn = accountingOrderSns.get(0);

            AccountingScoreCustomer accountingScoreCustomer = accountingScoreCustomerDubboConsumerService.findByAccountingOrderSn(accountingOrderSn);

            if (ObjectUtil.isNull(accountingScoreCustomer)) {
                return ResponseResultOuterUtils.createErrorResult("500", "对账单数据异常");
            }

            if (accountingScoreCustomer.getAccountingStatus().compareTo(AccountingOrderCustomerAccountingStatusEnum.已确认.getKey()) != 0) {
                return ResponseResultOuterUtils.createErrorResult("500", "该对账单状态发生变更，请检查");
            }

            if (accountingScoreCustomer.getInvoiceStatus().compareTo(AccountingOrderInvoiceApplyStatusEnum.全部申请.getKey()) != 0) {
                return ResponseResultOuterUtils.createErrorResult("500", "该对账单申请状态未全部申请，请返回检查");
            }


            /**************************************** 对账单 start ****************************************/

//（2）服务端需判断：
//·该对账单状态为“已确认”，否则不允许确认修改，1.5s提示“该对账单状态发生变更，请检查”；
//·该对账单的申请状态为“全部申请”，否则不允许确认修改，1.5s提示“该对账单申请状态未全部申请，请返回检查”；
//·该对账单下所有开票申请均存在且有效，否则不允许确认修改，1.5s提示“该对账单的开票申请数据发生变更，请返回检查”；
//·该对账单下所有开票申请的申请状态均为“待回款”，否则不允许确认修改，1.5s提示“该对账单的开票申请数据发生变更，请返回检查”；
//满足以上保存条件，即确认修改成功：
//①开票方式为“深圳航信电子发票”的开票申请：其相关快递公司/快递单号/寄票人/寄票时间等数据及状态，不作任何更新改动，仍为原数据；
//②开票方式为“线下开票”的开票申请：
//·更新开票申请中的“快递公司/快递单号/上传文件”数据；
//·更新寄票人姓名和时间记录为当前操作人姓名和时间；
//·更新该开票申请修改人和时间记录为当前操作人姓名和时间；
//·注：当前页面无“已红冲/已作废”的开票申请，因此“已红冲/已作废”的开票申请的状态和数据不作任何变动；
//·申请状态/寄票状态保持原有状态不变；
//·其他数据不作更新
//③1.5s提示“修改寄票成功”，关闭当前页签，自动跳转到“发票管理”列表页面，列表数据重新获取；

            /****************************************** 开票申请 - 数据库 start ******************************************/

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

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

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

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

            List<InvoiceApply> entitys            = invoiceApplyCustomerDubboConsumerService.findByIds(invoiceApplyIds);
            List<InvoiceApply> entitysOnlyOffLine = entitys.stream().filter(o -> o.getInvoiceMode().equals(InvoiceTypeMoudelXModeEnum.线下开票.getKey())).collect(Collectors.toList());

            if (CollUtil.isEmpty(invoiceApplyIds)) {
                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常，[001]");
            }
            if (CollUtil.isEmpty(entitys)) {
                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常，[002]");
            }
            // 前端没有因为有一个是线上而少传一个，所以这里不能用过滤后只有线下的
            if (invoiceApplyIds.size() != entitys.size()) {
                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常，[003]");
            }


            /**************************************** 只处理线下开票情况 start ****************************************/

            /**************************************** |---- 检查 申请状态 start ****************************************/

            // 错误 在混合的情况下是错的
//            List<Integer> mailTickStatus = entitysExistDb.stream()
            // 在混合的情况是下是排除 线上开票方式
            List<Integer> invoiceProgressingStatus = entitysOnlyOffLine.stream()
                    // 排除线上
                    .filter(AnLamdaUtils.distinctByKey(o -> o.getInvoiceStatus())).map(InvoiceApply::getInvoiceStatus).collect(Collectors.toList());

            if (CollUtil.isEmpty(invoiceProgressingStatus)) {
                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常，[申请状态]");
            }
            if (invoiceProgressingStatus.size() > 1) {
                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常，[申请状态] ");
            }

            InvoiceApplyCustomerInvoiceProgressingStatusEnum invoiceApplyCustomerInvoiceProgressingStatusEnum = InvoiceApplyCustomerInvoiceProgressingStatusEnum.get(invoiceProgressingStatus.get(0));

            if (invoiceApplyCustomerInvoiceProgressingStatusEnum != InvoiceApplyCustomerInvoiceProgressingStatusEnum.待回款) {
                return ResponseResultOuterUtils.createErrorResult("500", "该对账单的开票申请数据发生变更，请返回检查");
            }

            /**************************************** |---- 检查 申请状态   end ****************************************/


            /**************************************** |---- 检查 寄票状态 start ****************************************/

//            // 错误 在混合的情况下是错的
////            List<Integer> mailTickStatus = entitysExistDb.stream()
//            // 在混合的情况是下是排除 线上开票方式
//            List<Integer> mailTickStatus = entitysOnlyOffLine.stream()
//                    // 排除线上
////                    .filter(o -> o.getInvoiceMode().equals(InvoiceTypeMoudelXModeEnum.线下开票.getKey()))
//                    .filter(AnLamdaUtils.distinctByKey(o -> o.getMailTickStatus())).map(InvoiceApply::getMailTickStatus).collect(Collectors.toList());
//
//            if (CollUtil.isEmpty(mailTickStatus)) {
//                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常，[寄票状态]");
//            }
//            if (mailTickStatus.size() > 1) {
//                return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常，[寄票状态] ");
//            }
//
//            InvoiceApplyCustomerMailTickStatusEnum invoiceApplyCustomerMailTickStatusEnum = InvoiceApplyCustomerMailTickStatusEnum.get(mailTickStatus.get(0));
//
//            if (invoiceApplyCustomerMailTickStatusEnum != InvoiceApplyCustomerMailTickStatusEnum.未邮寄) {
////				return ResponseResultOuterUtils.createErrorResult("500", "提交的数据异常,要求状态为[未邮寄]");
//                return ResponseResultOuterUtils.createErrorResult("500", "该对账单的开票申请数据发生变更，请返回检查");
//            }

            /**************************************** |---- 检查 寄票状态   end ****************************************/


            /**************************************** 只处理线下开票情况   end ****************************************/


            // 错误 在混合的情况下是错的
//            invoiceApplyFieldMailTickStatusDubboConsumerService.opComplete(getToken(), entitysExistDb, form);
            // 在混合的情况是下是排除 线上开票方式
            invoiceApplyFieldMailTickStatusDubboConsumerService.opCompleteV2_1(entitysOnlyOffLine, 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;
    }


}
