package com.liquidnet.service.kylin.service.impl.admin;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.liquidnet.commons.lang.util.HttpUtil;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.kylin.constant.KylinTableStatusConst;
import com.liquidnet.service.kylin.dto.vo.KylinOrderTicketEntitiesVo;
import com.liquidnet.service.kylin.dto.vo.KylinOrderTicketVo;
import com.liquidnet.service.kylin.entity.*;
import com.liquidnet.service.kylin.mapper.KylinOrderRefundsMapper;
import com.liquidnet.service.kylin.mapper.KylinOrderTicketEntitiesMapper;
import com.liquidnet.service.kylin.mapper.KylinOrderTicketStatusMapper;
import com.liquidnet.service.kylin.mapper.KylinOrderTicketsMapper;
import com.liquidnet.service.kylin.utils.DataUtils;
import com.mongodb.BasicDBObject;
import com.mongodb.client.model.FindOneAndUpdateOptions;
import com.mongodb.client.model.ReturnDocument;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpException;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.awt.print.Book;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 退款表 服务实现类
 * </p>
 *
 * @author jiaangxiulong
 * @since 2021-05-26
 */
@Service
public class KylinRefundsStatusServiceImpl {

    @Autowired
    private KylinOrderTicketsMapper kylinOrderTicketsMapper;

    @Autowired
    private KylinOrderTicketStatusMapper kylinOrderTicketStatusMapper;

    @Autowired
    private KylinOrderRefundsMapper kylinOrderRefundsMapper;

    @Autowired
    private KylinOrderTicketEntitiesMapper kylinOrderTicketEntitiesMapper;

    @Autowired
    MongoTemplate mongoTemplate;

    @Autowired
    private DataUtils dataUtils;

    public Boolean orderTicketRefunding(String orderTicketsId, String refundData, String reason, String orderRefundBatchesId) throws HttpException {
        // 处理数据
        String authId = "434";
        String authName = "sss";
        JsonNode refundDataJson = JsonUtils.fromJson(refundData, JsonNode.class);
        JsonNode ticketEntityIds = refundDataJson.get("ticketEntityIds");
        double RefundpriceExpress = refundDataJson.get("RefundpriceExpress").doubleValue();

        KylinOrderTickets orderInfo = kylinOrderTicketsMapper.selectOne(
                new UpdateWrapper<KylinOrderTickets>().eq("order_tickets_id", orderTicketsId)
        );
        KylinOrderTicketStatus orderStatus = kylinOrderTicketStatusMapper.selectOne(
                new UpdateWrapper<KylinOrderTicketStatus>().eq("order_id", orderTicketsId)
        );
        int thisOrderStatus = orderStatus.getStatus();
        int thisPayStatus = orderStatus.getPayStatus();
        double priceExpress = orderInfo.getPriceExpress().doubleValue();
        double priceActual = orderInfo.getPriceActual().doubleValue();

        // todo 转增是否能退

        // 订单状态需已付款
        if (thisOrderStatus != KylinTableStatusConst.ORDER_STATUS1) {
            throw new HttpException("订单状态信息有误");
        }
        // 订单支付状态需为已支付
        if (thisPayStatus != KylinTableStatusConst.ORDER_PAY_STATUS1) {
            throw new HttpException("订单支付信息有误");
        }
        // 传的快递费不能大于实际的快递费
        if (RefundpriceExpress > priceExpress) {
            throw new HttpException("快递费不能大于实际的快递费");
        }
        // 该订单正在退款或已有退款
        QueryWrapper<com.liquidnet.service.kylin.entity.KylinOrderRefunds> refundingCountQuery = new QueryWrapper<KylinOrderRefunds>()
                .eq("order_tickets_id", orderTicketsId)
                .ne("status", KylinTableStatusConst.ORDER_REFUND_STATUS_CANCEL);
        for (JsonNode v : ticketEntityIds) {
            refundingCountQuery.like("order_ticket_entities_ids", v);
        }
        int refundingCount = kylinOrderRefundsMapper.selectCount(refundingCountQuery);
        if (refundingCount > 0) {
            throw new HttpException("该订单正在退款或已有退款");
        }

        // 该订单的入场人未付款/正在退款/已退款
        // TODO: 2021/5/27 出票未出票不知是否要处理
        QueryWrapper<KylinOrderTicketEntities> notPayCountQuery = new QueryWrapper<KylinOrderTicketEntities>()
                .in("order_ticket_entities_id", ticketEntityIds)
                .in("is_payment", new Integer[]{
                        KylinTableStatusConst.ENTITIES_IS_PAYMENT0,
                        KylinTableStatusConst.ENTITIES_IS_PAYMENT2,
                        KylinTableStatusConst.ENTITIES_IS_PAYMENT3});
        int notPayCount = kylinOrderTicketEntitiesMapper.selectCount(notPayCountQuery);

        // 选择退款的入场人是否正确
        // TODO: 2021/5/27 出票未出票不知是否要处理
        QueryWrapper<KylinOrderTicketEntities> choiceCountQuery = new QueryWrapper<KylinOrderTicketEntities>()
                .eq("order_id", orderTicketsId)
                .eq("is_payment", KylinTableStatusConst.ENTITIES_IS_PAYMENT1)
                .in("order_ticket_entities_id", ticketEntityIds);
        int choiceCount = kylinOrderTicketEntitiesMapper.selectCount(choiceCountQuery);
        int ticketEntityCount = ticketEntityIds.size();
        if (choiceCount < 0 || choiceCount != ticketEntityCount) {
            throw new HttpException("入场人订单有误或不存在");
        }

        // 本次退款总金额
        // 总入场人数量 排出未付款的 用来计算单入场人的价格
        int allEntitiesCount = kylinOrderTicketEntitiesMapper.selectCount(
                new QueryWrapper<KylinOrderTicketEntities>()
                        .eq("order_id", orderTicketsId)
                        .ne("is_payment", KylinTableStatusConst.ENTITIES_IS_PAYMENT0)
        );
        double refundTotalPrice = RefundpriceExpress + ((priceActual - priceExpress) / allEntitiesCount * ticketEntityCount);

        // 更新数据
        // 订单状态表
        KylinOrderTicketStatus orderStatusTable = new KylinOrderTicketStatus();
        // TODO: 2021/5/27 事物 and 部分退款
        orderStatusTable.setStatus(KylinTableStatusConst.ORDER_STATUS3);
        kylinOrderTicketStatusMapper.update(orderStatusTable, new UpdateWrapper<KylinOrderTicketStatus>()
                .eq("order_ticket_status_id", orderTicketsId));

        KylinOrderTicketVo kylinOrderTicketVo = new KylinOrderTicketVo();
        kylinOrderTicketVo.setStatus(KylinTableStatusConst.ORDER_STATUS3);
        BasicDBObject orderObject = new BasicDBObject("$set", JSON.parse(JsonUtils.toJson(kylinOrderTicketVo)));
        Document orderDoc = mongoTemplate.getCollection(KylinOrderTicketVo.class.getSimpleName()).findOneAndUpdate(
                Query.query(Criteria.where("orderTicketsId").is(orderTicketsId)).getQueryObject(),
                orderObject,
                new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER)
        );
        dataUtils.delOrderTicketRedis(orderTicketsId);


        // 入场人
        for (JsonNode v : ticketEntityIds) {
            KylinOrderTicketEntities entitiesTable = new KylinOrderTicketEntities();
            // TODO: 2021/5/27 事物 and 部分退款
            entitiesTable.setIsPayment(KylinTableStatusConst.ENTITIES_IS_PAYMENT2);
            kylinOrderTicketEntitiesMapper.update(entitiesTable, new UpdateWrapper<KylinOrderTicketEntities>()
                    .eq("order_ticket_entities_id", v));

            KylinOrderTicketEntitiesVo kylinOrderTicketEntitiesVo = new KylinOrderTicketEntitiesVo();
            kylinOrderTicketEntitiesVo.setIsPayment(KylinTableStatusConst.ENTITIES_IS_PAYMENT2);
            BasicDBObject entitiesObject = new BasicDBObject("$set", JSON.parse(JsonUtils.toJson(kylinOrderTicketEntitiesVo)));
            Document entitiesDoc = mongoTemplate.getCollection(KylinOrderTicketEntitiesVo.class.getSimpleName()).findOneAndUpdate(
                    Query.query(Criteria.where("orderTicketEntitiesId").is(v)).getQueryObject(),
                    entitiesObject,
                    new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER)
            );

            dataUtils.delOrderTicketEntitiesRedis(v.toString());
        }

        // 退款明细
        KylinOrderRefunds kylinOrderRefunds = new KylinOrderRefunds();
        String orderRefundsId = IDGenerator.nextSnowId().toString();
        kylinOrderRefunds.setOrderRefundsId(orderRefundsId);
        kylinOrderRefunds.setOrderTicketsId(orderTicketsId);
        kylinOrderRefunds.setOrderRefundBatchesId(orderRefundBatchesId);

        Integer refundCount = kylinOrderRefundsMapper.selectCount(
                new QueryWrapper<KylinOrderRefunds>()
                        .eq("order_tickets_id", orderTicketsId)
        );

        String orderRefundCode = orderInfo.getOrderCode();
        String codeNum = StringUtils.leftPad(String.valueOf(refundCount), 3, "0");
        kylinOrderRefunds.setOrderRefundCode(orderRefundCode + codeNum);
        kylinOrderRefunds.setPrice(BigDecimal.valueOf(refundTotalPrice));
        kylinOrderRefunds.setStatus(KylinTableStatusConst.ORDER_REFUND_STATUS_APPLY);
        kylinOrderRefunds.setType(0);
        kylinOrderRefunds.setApplicantId(authId);
        kylinOrderRefunds.setApplicantName(authName);
        kylinOrderRefunds.setApplicantAt(LocalDateTime.now());
        kylinOrderRefunds.setReason(reason);
        // TODO: 2021/5/27 判断tyoe
        if (RefundpriceExpress > 0) {
            kylinOrderRefunds.setRefundType("all");
        } else {
            kylinOrderRefunds.setRefundType("ticket");
        }
        kylinOrderRefunds.setOrderTicketEntitiesIds(ticketEntityIds.toString());
        kylinOrderRefunds.setCreatedAt(LocalDateTime.now());

        return true;
    }

    public boolean orderTicketRefundCancel(List<KylinOrderRefunds> refundList) {
        for (KylinOrderRefunds v : refundList) {
            String orderTicketEntitiesIds = v.getOrderTicketEntitiesIds();
            String[] orderTicketEntitiesIdsArr = orderTicketEntitiesIds.split(",");
            String orderTicketsId = v.getOrderTicketsId();
            String orderRefundsId = v.getOrderRefundsId();

            // 更新数据
            // 订单状态表
            KylinOrderTicketStatus orderStatusTable = new KylinOrderTicketStatus();
            // TODO: 2021/5/27 事物 and 部分退款
            orderStatusTable.setStatus(KylinTableStatusConst.ORDER_STATUS1);
            kylinOrderTicketStatusMapper.update(orderStatusTable, new UpdateWrapper<KylinOrderTicketStatus>()
                    .eq("order_ticket_status_id", orderTicketsId));

            KylinOrderTicketVo kylinOrderTicketVo = new KylinOrderTicketVo();
            kylinOrderTicketVo.setStatus(KylinTableStatusConst.ORDER_STATUS1);
            BasicDBObject orderObject = new BasicDBObject("$set", JSON.parse(JsonUtils.toJson(kylinOrderTicketVo)));
            Document orderDoc = mongoTemplate.getCollection(KylinOrderTicketVo.class.getSimpleName()).findOneAndUpdate(
                    Query.query(Criteria.where("orderTicketsId").is(orderTicketsId)).getQueryObject(),
                    orderObject,
                    new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER)
            );
            dataUtils.delOrderTicketRedis(orderTicketsId);


            // 入场人
            for (String entitiesId : orderTicketEntitiesIdsArr) {
                KylinOrderTicketEntities entitiesTable = new KylinOrderTicketEntities();
                // TODO: 2021/5/27 事物 and 部分退款
                entitiesTable.setIsPayment(KylinTableStatusConst.ENTITIES_IS_PAYMENT1);
                kylinOrderTicketEntitiesMapper.update(entitiesTable, new UpdateWrapper<KylinOrderTicketEntities>()
                        .eq("order_ticket_entities_id", entitiesId)
                        .eq("is_payment", KylinTableStatusConst.ENTITIES_IS_PAYMENT2)
                );

                KylinOrderTicketEntitiesVo kylinOrderTicketEntitiesVo = new KylinOrderTicketEntitiesVo();
                kylinOrderTicketEntitiesVo.setIsPayment(KylinTableStatusConst.ENTITIES_IS_PAYMENT1);
                BasicDBObject entitiesObject = new BasicDBObject("$set", JSON.parse(JsonUtils.toJson(kylinOrderTicketEntitiesVo)));
                Document entitiesDoc = mongoTemplate.getCollection(KylinOrderTicketEntitiesVo.class.getSimpleName()).findOneAndUpdate(
                        Query.query(Criteria.where("orderTicketEntitiesId").is(entitiesId)).getQueryObject(),
                        entitiesObject,
                        new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER)
                );

                dataUtils.delOrderTicketEntitiesRedis(entitiesId);
            }

            // 退款细节取消
            KylinOrderRefunds kylinOrderRefunds = new KylinOrderRefunds();
            kylinOrderRefunds.setStatus(KylinTableStatusConst.ORDER_REFUND_STATUS_CANCEL);
            kylinOrderRefundsMapper.update(kylinOrderRefunds, new UpdateWrapper<KylinOrderRefunds>()
                    .eq("order_refunds_id", orderRefundsId));

        }
        return true;
    }

    public boolean orderTicketRefundReapply(List<KylinOrderRefunds> refundList) {
        String authId = "434";
        String authName = "sss";

        KylinOrderRefunds kylinOrderRefunds = new KylinOrderRefunds();
        kylinOrderRefunds.setStatus(KylinTableStatusConst.ORDER_REFUND_STATUS_APPLY);
        kylinOrderRefunds.setApplicantId(authId);
        kylinOrderRefunds.setApplicantName(authName);
        kylinOrderRefunds.setApplicantAt(LocalDateTime.now());

        List<String> refundIds = refundList.stream().map(KylinOrderRefunds -> KylinOrderRefunds.getOrderRefundsId()).collect(Collectors.toList());

        kylinOrderRefundsMapper.update(
                kylinOrderRefunds,
                new UpdateWrapper<KylinOrderRefunds>().in("order_refunds_id", refundIds)
        );

        return true;
    }

    public boolean orderTicketRefundApproved(List<KylinOrderRefunds> refundList, String reject) {
        String authId = "434";
        String authName = "sss";

        KylinOrderRefunds kylinOrderRefunds = new KylinOrderRefunds();
        kylinOrderRefunds.setStatus(KylinTableStatusConst.ORDER_REFUND_STATUS_APPROVED);
        kylinOrderRefunds.setAuditorId(authId);
        kylinOrderRefunds.setAuditorName(authName);
        kylinOrderRefunds.setAuditorAt(LocalDateTime.now());
        kylinOrderRefunds.setReject(reject);

        List<String> refundIds = refundList.stream().map(KylinOrderRefunds -> KylinOrderRefunds.getOrderRefundsId()).collect(Collectors.toList());

        kylinOrderRefundsMapper.update(
                kylinOrderRefunds,
                new UpdateWrapper<KylinOrderRefunds>().in("order_refunds_id", refundIds)
        );

        return true;
    }

    public boolean orderTicketRefundReject(List<KylinOrderRefunds> refundList, String reject) {
        String authId = "434";
        String authName = "sss";

        KylinOrderRefunds kylinOrderRefunds = new KylinOrderRefunds();
        kylinOrderRefunds.setStatus(KylinTableStatusConst.ORDER_REFUND_STATUS_REJECT);
        kylinOrderRefunds.setAuditorId(authId);
        kylinOrderRefunds.setAuditorName(authName);
        kylinOrderRefunds.setAuditorAt(LocalDateTime.now());
        kylinOrderRefunds.setReject(reject);

        List<String> refundIds = refundList.stream().map(KylinOrderRefunds -> KylinOrderRefunds.getOrderRefundsId()).collect(Collectors.toList());

        kylinOrderRefundsMapper.update(
                kylinOrderRefunds,
                new UpdateWrapper<KylinOrderRefunds>().in("order_refunds_id", refundIds)
        );

        return true;
    }

    public boolean orderTicketRefundRefuse(List<KylinOrderRefunds> refundList, String refuse) {
        String authId = "434";
        String authName = "sss";

        KylinOrderRefunds kylinOrderRefunds = new KylinOrderRefunds();
        kylinOrderRefunds.setStatus(KylinTableStatusConst.ORDER_REFUND_STATUS_REFUSE);
        kylinOrderRefunds.setExecutorId(authId);
        kylinOrderRefunds.setExecutorName(authName);
        kylinOrderRefunds.setExecutorAt(LocalDateTime.now());
        kylinOrderRefunds.setRefuse(refuse);

        List<String> refundIds = refundList.stream().map(KylinOrderRefunds -> KylinOrderRefunds.getOrderRefundsId()).collect(Collectors.toList());

        kylinOrderRefundsMapper.update(
                kylinOrderRefunds,
                new UpdateWrapper<KylinOrderRefunds>().in("order_refunds_id", refundIds)
        );

        return true;
    }

    public boolean orderTicketRefundUnfilled(List<KylinOrderRefunds> refundList, String refuse) throws Exception {
        String authId = "434";
        String authName = "sss";

        KylinOrderRefunds kylinOrderRefunds = new KylinOrderRefunds();
        kylinOrderRefunds.setStatus(KylinTableStatusConst.ORDER_REFUND_STATUS_UNFILLED);
        kylinOrderRefunds.setExecutorId(authId);
        kylinOrderRefunds.setExecutorName(authName);
        kylinOrderRefunds.setExecutorAt(LocalDateTime.now());
        kylinOrderRefunds.setRefuse(refuse);

        List<String> refundIds = refundList.stream().map(KylinOrderRefunds -> KylinOrderRefunds.getOrderRefundsId()).collect(Collectors.toList());

        kylinOrderRefundsMapper.update(
                kylinOrderRefunds,
                new UpdateWrapper<KylinOrderRefunds>().in("order_refunds_id", refundIds)
        );

        // 开始执行退款
        String postUrl = "sss";

        String token = "sss";
        MultiValueMap<String, String> headers = new LinkedMultiValueMap();
        headers.add("token", token);

        for (KylinOrderRefunds refund: refundList) {
            KylinOrderTickets oderInfo = kylinOrderTicketsMapper.selectOne(
                    new QueryWrapper<KylinOrderTickets>()
                            .eq("order_tickets_id", refund.getOrderTicketsId())
            );
            HashMap<String, Object> params = new HashMap();
            params.put("code", oderInfo.getPayCode());
            params.put("order_refund_code", refund.getOrderRefundCode());
            params.put("price", refund.getPrice());
            params.put("reason", refund.getReason());
            params.put("notify_url", "sdadurl");
            params.put("sign", "qwrertasf");
            MultiValueMap<String, String> allParams = new LinkedMultiValueMap();
            allParams.put("headers", (List<String>) headers);
            allParams.put("form_params", (List<String>) params);

            // start 
            // TODO: 2021/5/31 待整理
            params.put("form_params", "qwrertasf");
            String postResult = HttpUtil.post(postUrl, allParams, headers);
            JsonNode postResultNew = JsonUtils.fromJson(postResult, JsonNode.class);
            // 请求提审接口结果
            if (postResultNew.get("message").toString() != "OK") {
                KylinOrderRefunds kylinOrderRefundsErr = new KylinOrderRefunds();
                kylinOrderRefundsErr.setStatus(KylinTableStatusConst.ORDER_REFUND_STATUS_ERROR);
                kylinOrderRefundsErr.setRefundError("通知退款中心失败");
                kylinOrderRefundsErr.setRefundAt(LocalDateTime.now());
                kylinOrderRefundsMapper.update(
                        kylinOrderRefundsErr,
                        new UpdateWrapper<KylinOrderRefunds>().eq("order_refunds_id", refund.getOrderTicketsId())
                );
            }
        }

        return true;
    }
}
