package cn.freemud.adapter;

import cn.freemud.base.entity.BaseResponse;
import cn.freemud.constant.CommonsConstant;
import cn.freemud.entities.dto.order.InvoiceCreateResponse;
import cn.freemud.entities.dto.order.OrderInvoiceResponse;
import cn.freemud.entities.dto.order.QueryInvoiceByCodesResponse;
import cn.freemud.entities.dto.pay.InvoiceCreateRequest;
import cn.freemud.entities.dto.pay.InvoiceProductDetailRequest;
import cn.freemud.entities.dto.pay.OrderInvoiceRequest;
import cn.freemud.entities.dto.pay.QueryInvoiceByCodesRequest;
import cn.freemud.entities.vo.order.CreateOrderInvoiceRequest;
import cn.freemud.enums.InvoiceTypeCodeEnum;
import cn.freemud.enums.OrderInvoiceConfigEnum;
import cn.freemud.enums.OrderStatus;
import cn.freemud.enums.ResponseResult;
import cn.freemud.service.thirdparty.OrderServiceClient;
import cn.freemud.utils.DateUtils;
import cn.freemud.utils.ResponseUtil;
import com.freemud.api.assortment.datamanager.entity.vo.AssortmentCustomerInfoVo;
import com.freemud.application.sdk.api.ordercenter.entities.v1.OrderBeanV1;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Component
public class OrderInvoiceAdapter {

    @Autowired
    OrderServiceClient orderServiceClient;

    // 开票参数 从B端后台查询，根据商户自己建的配置开票
//    public static final String INVOICE_PRODUCTCODE = "3070401000000000000";
//    public static final String INVOICE_PRODUCTNAME = "餐饮类商品";
//    public static final String INVOICE_TAXRATE = "0.06";
//    public static final String INVOICE_CONTENT = "非码订单开票";

    // 单张发票订单数量限制
    public static final Integer ORDER_INVOICE_NUM_LIMIT = 30;

    // 可开发票订单状态
    public static final List<Integer> canOpenOrderInvoiceStatus = Arrays.asList(
            OrderStatus.COMPLETE.getCode()
    );

    /**
     * 校验订单数据
     * @param request
     * @return
     */
    public BaseResponse checkOrderData(CreateOrderInvoiceRequest request){
        // 【1】. 订单去重判断
        List<String> distinctOrderCodes = request.getOrderCodes().stream().distinct().collect(Collectors.toList());
        if(request.getOrderCodes().size() != distinctOrderCodes.size()){
            return ResponseUtil.error(ResponseResult.ORDER_CODES_REPEAT);
        }

        // 【2】 单张发票包含的订单数量限制30
        if(request.getOrderCodes().size() > ORDER_INVOICE_NUM_LIMIT){
            return ResponseUtil.error(ResponseResult.ORDER_INVOINVE_LIMIT_30);
        }

        return ResponseUtil.success();
    }

    /**
     * 校验订单开票数据
     * @return
     */
    public BaseResponse checkOrderOpenInvoiceData(List<OrderBeanV1> orders, CreateOrderInvoiceRequest request, AssortmentCustomerInfoVo userLoginInfoDto){
        // 【1】 前端传的订单有误，部分订单查不到详情
        if(CollectionUtils.isEmpty(orders) || orders.size() != request.getOrderCodes().size()){
            return ResponseUtil.error(ResponseResult.ORDER_QUERY_ANY_ERR);
        }

        // 【2】 过滤订单状态&&实付金额是否符合开票原则
        List<OrderBeanV1> orderBeanV1List = orders.stream()
                .filter(x -> canOpenOrderInvoiceStatus.contains(x.getStatus()))
                .filter(x -> x.getActualPayAmount() != null).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(orderBeanV1List)){
            return ResponseUtil.error(ResponseResult.ORDER_INVOICE_OPEN_ERR);
        }
        Long totalActualPayAmount = orderBeanV1List.stream().map(e -> e.getActualPayAmount()).reduce(Long::sum).get();
        // 【3】 实际支付金额为0，不能开票
        if(null == totalActualPayAmount || totalActualPayAmount.equals(Long.valueOf(0))){
            return ResponseUtil.error(ResponseResult.ACTUALPAYAMOUNT_IS_ZERO);
        }
        // 【4】 将前端传的实际支付金额和服务端查出订单【可开票状态】实际支付金额对比，如果不相等，不予开票
        if(!totalActualPayAmount.equals(request.getTotalActualPayAmount())){
            return ResponseUtil.error(ResponseResult.ACTUALPAYAMOUNT_IS_ERROR);
        }
        // 【5】 单张发票最大限制1000元，超过最大限额不能开票
        double actualPayAmount2yuan = new BigDecimal(totalActualPayAmount)
                .divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP).doubleValue();
        if(actualPayAmount2yuan > CommonsConstant.CONSTANTS_ONE_THOUSAND){
            return ResponseUtil.error(ResponseResult.ACTUALPAYAMOUNT_OUT_OF_ONE_THOUSAND);
        }
        // 【6】 查询请求订单号是否开过发票，如果存在订单已开过发票，不予处理
        QueryInvoiceByCodesRequest queryInvoiceByCodesRequest = new QueryInvoiceByCodesRequest();
        queryInvoiceByCodesRequest.setPartnerId(request.getPartnerId());
        queryInvoiceByCodesRequest.setOrderCodes(request.getOrderCodes());
        queryInvoiceByCodesRequest.setUserId(userLoginInfoDto.getMemberId());
        BaseResponse<QueryInvoiceByCodesResponse> queryInvoiceResponse = orderServiceClient.queryInvoiceByCodes(queryInvoiceByCodesRequest);
        if(!ResponseResult.SUCCESS.getCode().equals(queryInvoiceResponse.getCode())){
            return ResponseUtil.error(queryInvoiceResponse.getCode(), queryInvoiceResponse.getMessage());
        }
        if(null == queryInvoiceResponse.getResult()){
            return ResponseUtil.error(ResponseResult.ORDER_INVOICE_QUERY_ERROR);
        }
        QueryInvoiceByCodesResponse orderInvoice = queryInvoiceResponse.getResult();
        if(!orderInvoice.getCheckPass() || CollectionUtils.isNotEmpty(orderInvoice.getInvoicedList())){
            return ResponseUtil.error(ResponseResult.ORDER_INVOICE_IS_OPENED);
        }

        return ResponseUtil.success();

    }

    public InvoiceCreateRequest convert2InvoiceCreateRequest(List<OrderBeanV1> orders
            , CreateOrderInvoiceRequest createRequest, OrderInvoiceResponse orderInvoiceConfig){
        InvoiceCreateRequest request = new InvoiceCreateRequest();
        request.setPartnerId(createRequest.getPartnerId());
        request.setInvoiceTerminalCode(CommonsConstant.CONSTANTS_TWO_STRING);
        request.setOrgCode(null);
        request.setPushChannelType(null);
        request.setInvoiceTypeCode(InvoiceTypeCodeEnum.getBwType(orderInvoiceConfig.getInvoiceType()));
        request.setInvoiceNo(UUID.randomUUID().toString().replaceAll("-", ""));
        request.setDrawer(createRequest.getDrawer());
        request.setPriceTaxMark(CommonsConstant.CONSTANTS_ZERO_STRING); //含税标记，不含税

        // 订单商品明细
        List<InvoiceProductDetailRequest> productDetailList = new ArrayList<>();

        // 支付总金额
        BigDecimal actualPayAmount = new BigDecimal(0);
        for(OrderBeanV1 orderBean : orders){
            actualPayAmount = new BigDecimal(orderBean.getActualPayAmount()).add(actualPayAmount);
        }

        // 分转元
        BigDecimal actualPayAmount2yuan = actualPayAmount.divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);

        InvoiceProductDetailRequest invoiceDetailRequest = new InvoiceProductDetailRequest();
        invoiceDetailRequest.setProductCode(orderInvoiceConfig.getProductCode());
        invoiceDetailRequest.setProductName(orderInvoiceConfig.getProductName());
        invoiceDetailRequest.setProductSpecification("");
        invoiceDetailRequest.setGoodsUnit("");
        invoiceDetailRequest.setGoodsQuantity(CommonsConstant.CONSTANTS_ONE_INTEGER);
        invoiceDetailRequest.setGoodsTaxRate(new BigDecimal(orderInvoiceConfig.getTaxRate()).setScale(2, BigDecimal.ROUND_HALF_UP));
        // 税额 = 商品金额(不含税) * 税率 / (1+税率)
        BigDecimal goodsTotalTax = actualPayAmount2yuan
                .multiply(invoiceDetailRequest.getGoodsTaxRate())
                .divide(new BigDecimal(1).add(invoiceDetailRequest.getGoodsTaxRate()),5,BigDecimal.ROUND_HALF_UP)
                .setScale(2, BigDecimal.ROUND_HALF_UP);
        invoiceDetailRequest.setGoodsTotalTax(goodsTotalTax);
        // 商品金额(不含税) = 商品金额(含税) - 税额
        BigDecimal excludedTaxPayAmount2yuan = actualPayAmount2yuan.subtract(goodsTotalTax);
        invoiceDetailRequest.setGoodsPrice(excludedTaxPayAmount2yuan);
        // 商品总价
        invoiceDetailRequest.setGoodsTotalPrice(excludedTaxPayAmount2yuan);
        productDetailList.add(invoiceDetailRequest);
        request.setProductDetailList(productDetailList);
        // fisherman 新增缺少字段
        request.setAppKey(orderInvoiceConfig.getAppKey());
        request.setAppSercret(orderInvoiceConfig.getAppSercret());
        // 百旺云
        request.setClientCode(OrderInvoiceConfigEnum.getClientCode(orderInvoiceConfig.getChannelType()));
        request.setSalt(orderInvoiceConfig.getSalt());
        request.setTaxNo(orderInvoiceConfig.getTaxNo());
        request.setUserName(orderInvoiceConfig.getUserName());
        request.setPassword(orderInvoiceConfig.getPassword());
        return request;
    }

    public OrderInvoiceRequest convert2OrderInvoiceRequest(InvoiceCreateRequest invoiceCreateRequest, InvoiceCreateResponse invoiceData
            , OrderInvoiceResponse orderInvoiceConfig, List<String> orderCodes, String memberId ){
        OrderInvoiceRequest request = new OrderInvoiceRequest();
        request.setPartnerId(invoiceCreateRequest.getPartnerId());
        request.setInvoiceType(orderInvoiceConfig.getInvoiceType());
        request.setContent(orderInvoiceConfig.getContent());
        request.setAmount(invoiceCreateRequest.getProductDetailList().get(0).getGoodsTotalPrice().multiply(new BigDecimal(100)).intValue());
        request.setInvoiceUrl(invoiceData.getScanUrl());
        request.setUserId(memberId);
        request.setInvoiceNo(invoiceCreateRequest.getInvoiceNo());
        request.setTaxRate(orderInvoiceConfig.getTaxRate());
        request.setPickUpNo(invoiceData.getCode());
        request.setEndingDate(DateUtils.convert2Date(invoiceData.getEndingDate()));
        request.setOrderCodes(orderCodes);
        return request;
    }

    /**
     * 发票格式处理
     * @param scanUrl
     */
    public String handleInvoiceData(String scanUrl){
        if(StringUtils.isEmpty(scanUrl)){
            return null;
        }
        if(scanUrl.startsWith("<![CDATA[")){
            scanUrl = scanUrl.substring(9,scanUrl.length());
        }
        if(scanUrl.endsWith("]]>")){
            scanUrl = scanUrl.substring(0,scanUrl.length()-3);
        }
        return scanUrl;
    }
}
