package cn.newfeifan.mall.module.trade.controller.admin.order;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.newfeifan.mall.framework.common.pojo.CommonResult;
import cn.newfeifan.mall.framework.common.pojo.PageParam;
import cn.newfeifan.mall.framework.common.pojo.PageResult;
import cn.newfeifan.mall.framework.common.pojo.echarts.EChartsResult;
import cn.newfeifan.mall.framework.common.util.date.DateUtils;
import cn.newfeifan.mall.framework.excel.core.util.ExcelUtils;
import cn.newfeifan.mall.framework.operatelog.core.annotations.OperateLog;
import cn.newfeifan.mall.module.distri.mq.message.order.CalcMessage;
import cn.newfeifan.mall.module.distri.mq.message.order.DistriOrderMessage;
import cn.newfeifan.mall.module.distri.mq.message.order.OrderCalcMessage;
import cn.newfeifan.mall.module.member.api.user.MemberUserApi;
import cn.newfeifan.mall.module.member.api.user.dto.MemberUserRespDTO;
import cn.newfeifan.mall.module.pay.controller.admin.order.vo.PayOrderPageItemRespVO;
import cn.newfeifan.mall.module.pay.controller.admin.order.vo.PayOrderPageReqVO;
import cn.newfeifan.mall.module.pay.convert.order.PayOrderConvert;
import cn.newfeifan.mall.module.pay.dal.dataobject.app.PayAppDO;
import cn.newfeifan.mall.module.pay.dal.dataobject.order.PayOrderDO;
import cn.newfeifan.mall.module.pay.service.app.PayAppService;
import cn.newfeifan.mall.module.pay.service.order.PayOrderService;
import cn.newfeifan.mall.module.trade.controller.admin.order.excelVO.DailyBillOrderRespVO;
import cn.newfeifan.mall.module.trade.controller.admin.order.excelVO.SettlementOrderRespVO;
import cn.newfeifan.mall.module.trade.controller.admin.order.vo.*;
import cn.newfeifan.mall.module.trade.convert.order.TradeOrderConvert;
import cn.newfeifan.mall.module.trade.dal.dataobject.order.TradeOrderDO;
import cn.newfeifan.mall.module.trade.dal.dataobject.order.TradeOrderItemDO;
import cn.newfeifan.mall.module.trade.dal.dataobject.order.TradeOrderLogDO;
import cn.newfeifan.mall.module.trade.enums.order.TradeOrderRefundStatusEnum;
import cn.newfeifan.mall.module.trade.enums.order.TradeOrderStateEnum;
import cn.newfeifan.mall.module.trade.enums.order.TradeOrderStatusEnum;
import cn.newfeifan.mall.module.trade.mq.producer.order.DistriOrderProducer;
import cn.newfeifan.mall.module.trade.service.order.TradeOrderLogService;
import cn.newfeifan.mall.module.trade.service.order.TradeOrderQueryService;
import cn.newfeifan.mall.module.trade.service.order.TradeOrderUpdateService;
import cn.newfeifan.mall.module.trade.service.ordercallbacklogs.OrderCallbackLogsService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.kuaidi100.sdk.response.SubscribeResp;
import com.kuaidi100.sdk.utils.SignUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import static cn.newfeifan.mall.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.newfeifan.mall.framework.common.pojo.CommonResult.success;
import static cn.newfeifan.mall.framework.common.util.collection.CollectionUtils.convertList;
import static cn.newfeifan.mall.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.newfeifan.mall.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
import static cn.newfeifan.mall.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
import static cn.newfeifan.mall.module.trade.enums.ErrorCodeConstants.CALLBACK_PARAMETER_ERROR;

@Tag(name = "管理后台 - 交易订单")
@RestController
@RequestMapping("/trade/order")
@Validated
@Slf4j
public class TradeOrderController {

    @Resource
    private TradeOrderUpdateService tradeOrderUpdateService;
    @Resource
    private TradeOrderQueryService tradeOrderQueryService;
    @Resource
    private TradeOrderLogService tradeOrderLogService;
    @Resource
    private MemberUserApi memberUserApi;

    @Resource
    private DistriOrderProducer distriOrderProducer;
    @Resource
    private PayOrderService orderService;
    @Resource
    private PayAppService appService;

    @Resource
    private OrderCallbackLogsService orderCallbackLogsService;

    @GetMapping("/page")
    @Operation(summary = "获得交易订单分页")
    @PreAuthorize("@ss.hasPermission('trade:order:query')")
    public CommonResult<PageResult<TradeOrderPageItemRespVO>> getOrderPage(TradeOrderPageReqVO reqVO) {
        // 查询订单
        PageResult<TradeOrderDO> pageResult = tradeOrderQueryService.getOrderPage(reqVO);
        if (CollUtil.isEmpty(pageResult.getList())) {
            return success(PageResult.empty());
        }

        // 查询用户信息
        Set<Long> userIds = CollUtil.unionDistinct(convertList(pageResult.getList(), TradeOrderDO::getUserId),
                convertList(pageResult.getList(), TradeOrderDO::getBrokerageUserId, Objects::nonNull));
        Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(userIds);
        // 查询订单项
        List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(
                convertSet(pageResult.getList(), TradeOrderDO::getId));
        // 最终组合
        PageResult<TradeOrderPageItemRespVO> data = TradeOrderConvert.INSTANCE.convertPage(pageResult, orderItems, userMap);
        for (TradeOrderPageItemRespVO tradeOrderPageItemRespVO : data.getList()) {
            tradeOrderPageItemRespVO.setSpuType(tradeOrderQueryService.getSpuType(orderItems));
        }
        return success(data);
    }

    @GetMapping("/summary")
    @Operation(summary = "获得交易订单统计")
    @PreAuthorize("@ss.hasPermission('trade:order:query')")
    public CommonResult<TradeOrderSummaryRespVO> getOrderSummary(TradeOrderPageReqVO reqVO) {
        return success(tradeOrderQueryService.getOrderSummary(reqVO));
    }

  /*  @GetMapping("/order-count")
    @Operation(summary = "获得交易订单统计")
    @PreAuthorize("@ss.hasPermission('trade:order:query')")
    public CommonResult<TradeOrderSummaryRespVO> getOrderCount(TradeOrderPageReqVO reqVO) {
        Long orderCount = tradeOrderQueryService.getOrderCount(getLoginUserId(), null, null);
        return success(orderCount);
    }*/


    @GetMapping("/get-detail")
    @Operation(summary = "获得交易订单详情")
    @Parameter(name = "id", description = "订单编号", required = true, example = "1")
    @PreAuthorize("@ss.hasPermission('trade:order:query')")
    public CommonResult<TradeOrderDetailRespVO> getOrderDetail(@RequestParam("id") Long id) {
        // 查询订单
        TradeOrderDO order = tradeOrderQueryService.getOrder(id);
        if (order == null) {
            return success(null);
        }
        // 查询订单项
        List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(id);

        // 拼接数据
        MemberUserRespDTO user = memberUserApi.getUser(order.getUserId());
        MemberUserRespDTO brokerageUser = order.getBrokerageUserId() != null ?
                memberUserApi.getUser(order.getBrokerageUserId()) : null;
        List<TradeOrderLogDO> orderLogs = tradeOrderLogService.getOrderLogListByOrderId(id);
        TradeOrderDetailRespVO convert = TradeOrderConvert.INSTANCE.convert(order, orderItems, orderLogs, user, brokerageUser);
        convert.setSpuType(tradeOrderQueryService.getSpuType(orderItems));

        if(convert.getRefundStatus().equals(TradeOrderRefundStatusEnum.ALL.getStatus())){
            convert.setStatus(TradeOrderStatusEnum.AFTER_SALE.getStatus());
        }

        return success(convert);
    }

    @GetMapping("/get-express-track-list")
    @Operation(summary = "获得交易订单的物流轨迹")
    @Parameter(name = "id", description = "交易订单编号")
    @PreAuthorize("@ss.hasPermission('trade:order:query')")
    public CommonResult<List<?>> getOrderExpressTrackList(@RequestParam("id") Long id) {
        return success(TradeOrderConvert.INSTANCE.convertList02(
                tradeOrderQueryService.getExpressTrackList(id)));
    }

    @PutMapping("/delivery")
    @Operation(summary = "订单发货")
    @PreAuthorize("@ss.hasPermission('trade:order:update')")
    public CommonResult<Boolean> deliveryOrder(@RequestBody TradeOrderDeliveryReqVO deliveryReqVO) {
        tradeOrderUpdateService.deliveryOrder(deliveryReqVO);
        return success(true);
    }

    @PostMapping("/callBackUrl")
    @Operation(summary = "订单订阅回调")
    public SubscribeResp callBackUrl(HttpServletRequest request) {
        String param = request.getParameter("param");
        if (param == null) {
            throw exception(CALLBACK_PARAMETER_ERROR);
        }
        String sign = request.getParameter("sign");
        String orderId = request.getParameter("orderId");

        Gson gson = new Gson();
        Map<String, Object> map = gson.fromJson(param, Map.class);
        Map<String, Object> lastResult = (Map<String, Object>) map.get("lastResult");
        String state = (String) lastResult.get("state");
        TradeOrderDO order = tradeOrderQueryService.getOrderById(Long.valueOf(orderId));

        //建议记录一下这个回调的内容，方便出问题后双方排查问题
        log.debug("快递100订阅推送回调结果|{}|{}", param, sign);
        //订阅时传的salt,没有可以忽略
        String salt = order.getLogisticsNo();
        String ourSign = SignUtils.sign(param + salt);
        log.info("订单:{},回调param:{}", orderId, param);
        SubscribeResp subscribeResp = new SubscribeResp();
        subscribeResp.setResult(Boolean.TRUE);
        subscribeResp.setReturnCode("200");
        subscribeResp.setMessage("成功");
        //加密如果相等，属于快递100推送；否则可以忽略掉当前请求
        ObjectMapper mapper = new ObjectMapper();
        if (ourSign.equals(sign)) {
            //判断订单状态是否是已签收
            if (state.equals(TradeOrderStateEnum.RECEIVED.getState())) {
                List<Map<String, Object>> dataList = (List<Map<String, Object>>) lastResult.get("data");
                Map<String, Object> firstData = dataList.get(0);
                //保存签收时间
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern(FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND);
                order.setReceivingTime(LocalDateTime.parse(firstData.get("time").toString(), formatter));
                tradeOrderUpdateService.updateOrderById(order);
            }

            return subscribeResp;
        }
        //添加到日志
        try {
            orderCallbackLogsService.create(orderId, param, mapper.writeValueAsString(lastResult), lastResult.get("status").toString());
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    @PutMapping("/update-remark")
    @Operation(summary = "订单备注")
    @PreAuthorize("@ss.hasPermission('trade:order:update')")
    public CommonResult<Boolean> updateOrderRemark(@RequestBody TradeOrderRemarkReqVO reqVO) {
        tradeOrderUpdateService.updateOrderRemark(reqVO);
        return success(true);
    }

    @PutMapping("/update-price")
    @Operation(summary = "订单调价")
    @PreAuthorize("@ss.hasPermission('trade:order:update')")
    public CommonResult<Boolean> updateOrderPrice(@RequestBody TradeOrderUpdatePriceReqVO reqVO) {
        tradeOrderUpdateService.updateOrderPrice(reqVO);
        return success(true);
    }

    @PutMapping("/update-address")
    @Operation(summary = "修改订单收货地址")
    @PreAuthorize("@ss.hasPermission('trade:order:update')")
    public CommonResult<Boolean> updateOrderAddress(@RequestBody TradeOrderUpdateAddressReqVO reqVO) {
        tradeOrderUpdateService.updateOrderAddress(reqVO);
        return success(true);
    }

    @PutMapping("/pick-up-by-id")
    @Operation(summary = "订单核销")
    @Parameter(name = "id", description = "交易订单编号")
    @PreAuthorize("@ss.hasPermission('trade:order:pick-up')")
    public CommonResult<Boolean> pickUpOrderById(@RequestParam("id") Long id) {
        tradeOrderUpdateService.pickUpOrderByAdmin(id);
        return success(true);
    }

    @PutMapping("/pick-up-by-verify-code")
    @Operation(summary = "订单核销")
    @Parameter(name = "pickUpVerifyCode", description = "自提核销码")
    @PreAuthorize("@ss.hasPermission('trade:order:pick-up')")
    public CommonResult<Boolean> pickUpOrderByVerifyCode(@RequestParam("pickUpVerifyCode") String pickUpVerifyCode) {
        tradeOrderUpdateService.pickUpOrderByAdmin(pickUpVerifyCode);
        return success(true);
    }

    @GetMapping("/get-by-pick-up-verify-code")
    @Operation(summary = "查询核销码对应的订单")
    @Parameter(name = "pickUpVerifyCode", description = "自提核销码")
    @PreAuthorize("@ss.hasPermission('trade:order:query')")
    public CommonResult<TradeOrderDetailRespVO> getByPickUpVerifyCode(@RequestParam("pickUpVerifyCode") String pickUpVerifyCode) {
        TradeOrderDO tradeOrder = tradeOrderUpdateService.getByPickUpVerifyCode(pickUpVerifyCode);
        return success(TradeOrderConvert.INSTANCE.convert2(tradeOrder, null));
    }


    @GetMapping("/get-count")
    @Operation(summary = "获得交易订单数量")
    public CommonResult<Map<Integer, Long>> getOrderCount(TradeOrderPageReqVO reqVO) {
        Map<Integer, Long> orderCount = Maps.newLinkedHashMapWithExpectedSize(7);

        orderCount.put(-1, tradeOrderQueryService.getOrderCount(null, reqVO));
        orderCount.put(TradeOrderStatusEnum.AFTER_SALE.getStatus(), tradeOrderQueryService.getOrderCountByRefundStatus(TradeOrderRefundStatusEnum.ALL.getStatus(), reqVO));
        orderCount.put(TradeOrderStatusEnum.UNPAID.getStatus(), tradeOrderQueryService.getOrderCount(TradeOrderStatusEnum.UNPAID.getStatus(), reqVO));
        orderCount.put(TradeOrderStatusEnum.UNDELIVERED.getStatus(), tradeOrderQueryService.getOrderCount(TradeOrderStatusEnum.UNDELIVERED.getStatus(), reqVO));
        orderCount.put(TradeOrderStatusEnum.DELIVERED.getStatus(), tradeOrderQueryService.getOrderCount(TradeOrderStatusEnum.DELIVERED.getStatus(), reqVO));
        orderCount.put(TradeOrderStatusEnum.COMPLETED.getStatus(), tradeOrderQueryService.getOrderCount(TradeOrderStatusEnum.COMPLETED.getStatus(), reqVO));
        orderCount.put(TradeOrderStatusEnum.CANCELED.getStatus(), tradeOrderQueryService.getOrderCount(TradeOrderStatusEnum.CANCELED.getStatus(), reqVO));
        return success(orderCount);
    }

    @GetMapping("/get-countByUser")
    @Operation(summary = "获得用户的交易订单数量")
    public CommonResult<Map<Integer, Long>> getOrderCountByUser(@RequestParam(value = "userId", required = false) Long userId) {
        Map<Integer, Long> orderCount = Maps.newLinkedHashMapWithExpectedSize(7);

        orderCount.put(-1, tradeOrderQueryService.getOrderCount(null, userId));
        orderCount.put(TradeOrderStatusEnum.AFTER_SALE.getStatus(), tradeOrderQueryService.getOrderCountByRefundStatus(TradeOrderRefundStatusEnum.ALL.getStatus(), userId));
        orderCount.put(TradeOrderStatusEnum.UNPAID.getStatus(), tradeOrderQueryService.getOrderCount(TradeOrderStatusEnum.UNPAID.getStatus(), userId));
        orderCount.put(TradeOrderStatusEnum.UNDELIVERED.getStatus(), tradeOrderQueryService.getOrderCount(TradeOrderStatusEnum.UNDELIVERED.getStatus(), userId));
        orderCount.put(TradeOrderStatusEnum.DELIVERED.getStatus(), tradeOrderQueryService.getOrderCount(TradeOrderStatusEnum.DELIVERED.getStatus(), userId));
        orderCount.put(TradeOrderStatusEnum.COMPLETED.getStatus(), tradeOrderQueryService.getOrderCount(TradeOrderStatusEnum.COMPLETED.getStatus(), userId));
        orderCount.put(TradeOrderStatusEnum.CANCELED.getStatus(), tradeOrderQueryService.getOrderCount(TradeOrderStatusEnum.CANCELED.getStatus(), userId));
        return success(orderCount);
    }


    @GetMapping("/pay/page")
    @Operation(summary = "获得支付订单分页")
    @PreAuthorize("@ss.hasPermission('pay:order:query')")
    public CommonResult<PageResult<PayOrderPageItemRespVO>> getOrderPage(@Valid PayOrderPageReqVO pageVO) {
        PageResult<PayOrderDO> pageResult = orderService.getOrderPage(pageVO);
        if (CollectionUtil.isEmpty(pageResult.getList())) {
            return success(new PageResult<>(pageResult.getTotal()));
        }

        // 拼接返回
        Map<Long, PayAppDO> appMap = appService.getAppMap(convertList(pageResult.getList(), PayOrderDO::getAppId));
        PageResult<PayOrderPageItemRespVO> data = PayOrderConvert.INSTANCE.convertPage(pageResult, appMap);
        List<PayOrderPageItemRespVO> list = tradeOrderQueryService.getOrderNoAndPicUrl(data.getList());
        data.setList(list);

        return success(data);
    }


    @GetMapping("/startCalc")
    @Operation(summary = "计算启动")
    @PreAuthorize("@ss.hasPermission('trade:order:delete')")
    public CommonResult<String> startCalc() {
        //发货七天前订单
        List<DistriOrderMessage> appTradeOrderDetailRespVos = tradeOrderQueryService.queryAllOrder();
        List<OrderCalcMessage> orderCalcMessages = tradeOrderQueryService.getOrderCalcMessage(appTradeOrderDetailRespVos);

        //每日订单
        List<DistriOrderMessage> appTradeOrderDetailRespVos2 = tradeOrderQueryService.queryDailyOrder();
        List<OrderCalcMessage> orderCalcMessages2 = tradeOrderQueryService.getOrderCalcMessage(appTradeOrderDetailRespVos2);

        CalcMessage calcMessage = CalcMessage.builder().orderCalcMessages(orderCalcMessages).bonusQuotaOrderDO(orderCalcMessages2).distriOrderMessages(appTradeOrderDetailRespVos).build();
        distriOrderProducer.sendDistriOrderMessage(calcMessage);

        return success("success");
    }

//    @GetMapping("/calcOrderItem")
//    @Operation(summary = "计算所有订单的订单项的可获得峰值")
//    public CommonResult<String> calcOrderItem() {
//        tradeOrderUpdateService.updateOrderItemByFreezeHighQuota();
//
//        return success("success");
//    }

    @GetMapping("/initializationOrderItem")
    @Operation(summary = "初始化订单详情中的成本价和推广费")
    @PreAuthorize("@ss.hasPermission('trade:order:delete')")
    public CommonResult<String> initializationOrderItem() {
        tradeOrderUpdateService.initializationOrderItem();

        return success("success");
    }

    @GetMapping("/export-excel/shopSettlement")
    @Operation(summary = "导出每日结算单 Excel")
    @PreAuthorize("@ss.hasPermission('trade:order:export')")
    @OperateLog(type = EXPORT)
    public void exportOrderExcelShopSettlement(@Valid TradeOrderPageReqVO pageReqVO, HttpServletResponse response) throws IOException {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);

        List<SettlementOrderRespVO> list = TradeOrderConvert.INSTANCE.convertSettOrder(tradeOrderQueryService.getOrderPage(pageReqVO).getList());
        // 导出 Excel
        ExcelUtils.write(response, "每日账单.xls", "数据", SettlementOrderRespVO.class,
                list);
    }

    @GetMapping("/export-excel/dailyBill")
    @Operation(summary = "导出每日账单下的订单 Excel")
    @PreAuthorize("@ss.hasPermission('trade:order:export')")
    @OperateLog(type = EXPORT)
    public void exportOrderExcelByDailyBill(@Valid TradeOrderPageReqVO pageReqVO, HttpServletResponse response) throws IOException {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);

        List<DailyBillOrderRespVO> list = TradeOrderConvert.INSTANCE.convertDailyBillOrder(tradeOrderQueryService.getOrderPage(pageReqVO).getList());

        for (DailyBillOrderRespVO respVO : list) {
            respVO.setUsername(memberUserApi.getUser(respVO.getUserId()).getUsername());
        }

        // 导出 Excel
        ExcelUtils.write(response, "每日账单下的订单.xls", "数据", DailyBillOrderRespVO.class,
                list);
    }

    @GetMapping("/export-excel")
    @Operation(summary = "导出订单 Excel")
    @PreAuthorize("@ss.hasPermission('trade:order:export')")
    @OperateLog(type = EXPORT)
    public void exportOrderExcel(@Valid TradeOrderPageReqVO pageReqVO, HttpServletResponse response) throws IOException {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);

        List<TradeOrderRespVO> list = TradeOrderConvert.INSTANCE.convertOrderList(tradeOrderQueryService.getOrderPage(pageReqVO).getList());
        // 导出 Excel
        ExcelUtils.write(response, "每日账单下的订单.xls", "数据", TradeOrderRespVO.class,
                list);
    }

    @GetMapping("/getOrderCountWithMoney")
    @Operation(summary = "获得对应日期订单数量及金额")
    @PreAuthorize("@ss.hasPermission('trade:order:query')")
    public CommonResult<EChartsResult> getOrderCountWithMoney(@DateTimeFormat(pattern = DateUtils.FORMAT_YEAR_MONTH_DAY) LocalDate startTime, @DateTimeFormat(pattern = DateUtils.FORMAT_YEAR_MONTH_DAY) LocalDate endTime) {

        return success(tradeOrderQueryService.getOrderCountWithMoney(startTime,endTime));
    }

    @GetMapping("/calc")
    @Operation(summary = "计算权益分配变更后")
    @PreAuthorize("@ss.hasPermission('trade:order:calc')")
    public CommonResult<String> calc() {
        tradeOrderQueryService.calc();
        return success("success");
    }

}
