package org.jeecg.modules.app.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.RepeatSubmit;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.modules.app.dto.AppOrderInfoDTO;
import org.jeecg.modules.app.dto.RefundsInfoDTO;
import org.jeecg.modules.app.form.CreateOrderForm;
import org.jeecg.modules.app.form.PageOrdersForm;
import org.jeecg.modules.app.form.RefundOrderForm;
import org.jeecg.modules.app.form.UserPayForm;
import org.jeecg.modules.app.service.IAppIsinService;
import org.jeecg.modules.app.service.IOrderService;
import org.jeecg.modules.app.service.WeChatPayService;
import org.jeecg.modules.app.vo.AppOrderUseRecordsVO;
import org.jeecg.modules.app.vo.OrderVO;
import org.jeecg.modules.app.vo.PageOrdersVO;
import org.jeecg.modules.app.vo.QueryOrderVerifyRecordsVO;
import org.jeecg.modules.pay.config.WeChatProfitSharingService;
import org.jeecg.modules.pay.config.WechatCallbackRefundData;
import org.jeecg.modules.pay.config.WechatRefundCallback;
import org.jeecg.modules.pay.entity.WxchatCallbackRefundData;
import org.jeecg.modules.system.app.entity.AppOrder;
import org.jeecg.modules.system.app.entity.AppOrderProInfo;
import org.jeecg.modules.system.app.entity.AppOrderRefundsInfo;
import org.jeecg.modules.system.app.mapper.AppOrderMapper;
import org.jeecg.modules.system.app.mapper.AppOrderProInfoMapper;
import org.jeecg.modules.system.app.mapper.AppOrderRefundsInfoMapper;
import org.jeecg.modules.system.app.service.IAppOrderProInfoService;
import org.jeecg.modules.system.app.service.IAppOrderRefundsInfoService;
import org.jeecg.modules.system.app.service.impl.AppOrderProInfoServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
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 java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Slf4j
@Tag(name = "APP订单相关接口")
@RestController
@RequestMapping("/app/order")
public class OrderController {
    @Resource
    private IOrderService appOrderService;
    @Resource
    private IAppOrderProInfoService appOrderProInfoService;
    @Resource
    private WeChatPayService weChatPayService;
    @Resource
    private IAppIsinService appIsinService;
    @Resource
    private WeChatProfitSharingService weChatProfitSharingService;
    @Resource
    private IAppOrderRefundsInfoService appOrderRefundsInfoService;

    /**
     * @return Result<OrderVO.PreviewOrderPlaceSchool>
     * @Author SheepHy
     * @Description 学校场地预约-预览页
     * @Date 10:10 2025/7/14
     * @Param placeId startTime
     **/
    @Operation(summary = "学校场地预约-预览页")
    @GetMapping("/previewOrderPlaceSchool")
    public Result<OrderVO.PreviewOrderPlaceSchool> previewOrderPlaceSchool(@RequestParam("placeId") @Schema(description = "场地ID") String placeId,
                                                                           @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
                                                                           @DateTimeFormat(pattern = "yyyy-MM-dd")
                                                                           @RequestParam("startTime") @Schema(description = "当前选择日期（年月日）") Date startTime) {
        return Result.ok(appOrderService.previewOrderPlaceSchool(placeId, startTime));
    }

    /**
     * @return boolean
     * @Author SheepHy
     * @Description 课程限购校验
     * @Date 16:22 2025/7/14
     * @Param courseId 课程ID
     **/
    @Operation(summary = "课程限购校验")
    @GetMapping("/checkCourseLimitNum")
    public Result<Boolean> checkCourseLimitNum(@RequestParam("courseId") @Schema(description = "课程ID") String courseId,
                                               @RequestParam("limitNum") @Schema(description = "购买数") int limitNum) {
        return Result.OK(appOrderService.checkCourseLimitNum(courseId, limitNum));
    }

    /**
     * @return OrderVO.PreviewOrderCourseSchool {@link OrderVO.PreviewOrderCourse}
     * @Author SheepHy
     * @Description 课程购买-预览页（学校课程、体育馆课程、教练课程）
     * @Date 15:43 2025/7/14
     * @Param courseId
     **/
    @Operation(summary = "课程购买-预览页（学校课程、体育馆课程、教练课程）")
    @GetMapping("/previewOrderCourse")
    public Result<OrderVO.PreviewOrderCourse> previewOrderCourse(@RequestParam("courseId") @Schema(description = "课程ID") String courseId) {
        return Result.ok(appOrderService.previewOrderCourse(courseId));
    }

    /**
     * @return OrderVO.PreviewOrderPlaceGymnasiumChartered {@link OrderVO.PreviewOrderPlaceGymnasiumChartered}
     * @Author SheepHy
     * @Description 体育馆包场-预览页
     * @Date 16:13 2025/7/14
     * @Param placeId
     **/
    @Operation(summary = "体育馆包场-预览页")
    @GetMapping("/previewOrderPlaceGymnasiumChartered")
    public Result<OrderVO.PreviewOrderPlaceGymnasiumChartered> previewOrderPlaceGymnasiumChartered(@RequestParam("rulesId") @Schema(description = "场次IDS多个逗号拼接") String rulesId) {
        return Result.ok(appOrderService.previewOrderPlaceGymnasiumChartered(rulesId));
    }

    /**
     * @return OrderVO.createOrderPlaceSchool
     * @Author SheepHy
     * @Description 学校场地预约-创建
     * @Date 10:10 2025/7/14
     * @Param rulesId 时间段ID
     **/
    @Operation(summary = "学校场地预约-创建")
    @GetMapping("/createOrderPlaceSchool")
    public Result<OrderVO.createOrderPlaceSchool> createOrderPlaceSchool(@RequestParam("rulesId") @Schema(description = "场次IDS多个逗号拼接") String rulesId,
                                                                         @RequestParam("userIds") @Schema(description = "使用用户IDS多个逗号拼接") String userIds) {
        return Result.ok(appOrderService.createOrderPlaceSchool(rulesId, userIds));
    }

    /**
     * @return OrderVO.PreviewOrderPlaceSchoolTime {@link OrderVO.PreviewOrderPlaceSchoolTime}
     * @Author SheepHy
     * @Description 学校包场-预览时间选择
     * @Date 14:45 2025/7/17
     * @Param placeId
     **/
    @Operation(summary = "学校包场-预览时间选择")
    @GetMapping("/previewOrderPlaceSchoolTime")
    public Result<List<OrderVO.PreviewOrderPlaceSchoolTime>> previewOrderPlaceSchoolTime(@RequestParam("placeId") @Schema(description = "当前选择场次ID") String placeId) {
        return Result.ok(appOrderService.previewOrderPlaceSchoolTime(placeId));
    }

    /**
     * 订单-创建
     *
     * @param createOrderForm
     * @return
     */
    @Operation(summary = "订单-创建")
    @RepeatSubmit(serviceId = "createOrder", limitType = RepeatSubmit.Type.PARAM, lockTime = 3)
    @PostMapping("/createOrder")
    public Result<UserPayForm> createOrder(@Validated @RequestBody CreateOrderForm createOrderForm) throws IOException {
        return Result.ok(appOrderService.createOrder(createOrderForm));
    }

    /**
     * 订单-支付
     *
     * @param appOrderId
     * @return
     */
    @Operation(summary = "订单-支付")
    @RepeatSubmit(serviceId = "payOrder", limitType = RepeatSubmit.Type.PARAM, lockTime = 3)
    @PutMapping("/payOrder")
    public Result<UserPayForm> payOrder(@RequestParam("appOrderId") String appOrderId){
        return Result.ok(appOrderService.payOrder(appOrderId));
    }

    /**
     * 支付回调
     *
     * @param request
     * @return
     */
    @Operation(summary = "支付回调")
    @RepeatSubmit(serviceId = "createOrder", limitType = RepeatSubmit.Type.PARAM, lockTime = 10)
    @RequestMapping("/wechatPayNotify")
    public Map<String, String> wechatPayNotify(HttpServletRequest request, HttpServletResponse response) throws InterruptedException {
        log.info("--------------------------------------------支付回调");
        return appOrderService.wechatPayNotify(request, response);
    }

    /**
     * 订单支付是否成功查询
     *
     * @param orderCode
     * @return
     */
    @Operation(summary = "订单支付是否成功查询")
    @GetMapping("/orderQuery")
    public Result<String> orderQuery(@RequestParam(name = "orderCode") String orderCode) throws IOException {
        return Result.OK(appOrderService.orderQuery(orderCode));
    }

    /**
     * 分页查询我的订单列表
     *
     * @param pageOrdersForm
     * @return
     */
    @Operation(summary = "分页查询我的订单列表")
    @PostMapping("/pageOrders")
    public Result<IPage<PageOrdersVO>> pageOrders(@RequestBody PageOrdersForm pageOrdersForm) {
        return Result.OK(appOrderService.pageOrders(pageOrdersForm));
    }

    /**
     * 订单主动取消
     *
     * @param orderId
     * @return
     */
    @Operation(summary = "订单主动取消")
    @PutMapping("/cancelOrder")
    public Result<String> cancelOrder(@RequestParam(name = "orderId") String orderId) {
        return Result.OK(appOrderService.cancelOrder(orderId));
    }

    /**
     * 订单退款
     *
     * @param refundOrderForm
     * @return
     */
    @Operation(summary = "订单退款")
    @PostMapping("/refundOrder")
    public Result<String> refundOrder(@RequestBody RefundOrderForm refundOrderForm) {
        return Result.OK(appOrderService.refundOrder(refundOrderForm));
    }


    /**
     * 赛事订单退款
     * @param orderCode
     * @param reason
     * @return
     */
    @Operation(summary = "赛事订单退款")
    @GetMapping("/gameRefundOrder")
    public Result<String> gameRefundOrder(@RequestParam(name = "orderCode", required = true) String orderCode,@RequestParam(name = "reason", required = true) String reason) {
        return Result.OK(appOrderService.gameRefundOrder(orderCode, reason));
    }

    /**
     * 订单退款回调
     *
     * @param jsonData
     * @return
     */
    @Operation(summary = "订单退款回调")
    @RequestMapping("/refundOrderNotify")
    public Map<String, Object> refundOrderNotify(@RequestBody String jsonData) throws GeneralSecurityException, IOException {
        return weChatPayService.refundOrderNotify(jsonData);
    }

    /**
     * 订单退款回调
     * @param request
     * @param response
     * @return
     * @throws GeneralSecurityException
     * @throws IOException
     */
    @Operation(summary = "订单退款回调")
    @PostMapping("/callback/refundOrderNotify")
    public Map<String, Object> refundOrderNotify(HttpServletRequest request, HttpServletResponse response) {
        return weChatProfitSharingService.wxPayRefundCallback(request, response, new WechatRefundCallback() {
            @Override
            public void success(WechatCallbackRefundData refundData) {
                log.info("---------------------------------------------------微信退款成功回调");
                //  退款成功的业务逻辑，例如更改订单状态为退款成功等
                AppOrder appOrder = appOrderService.getOne(Wrappers.lambdaQuery(AppOrder.class).eq(AppOrder::getOrderCode, refundData.getOrderNo()));
                appOrder.setOrderStatus(CommonConstant.ORDER_STATUS_6).setAfterSaleStatus(CommonConstant.NUMBER_2);
                appOrderService.updateById(appOrder);
                List<AppOrderProInfo> orderProInfoList = appOrderProInfoService.list(Wrappers.<AppOrderProInfo>lambdaQuery()
                        .eq(AppOrderProInfo::getOrderId, appOrder.getId())
                        .ne(AppOrderProInfo::getType, CommonConstant.ORDER_PRO_INFO_TYPE_6)
                );

                for (AppOrderProInfo appOrderProInfo : orderProInfoList) {
                    appOrderProInfo.setOrderStatus(CommonConstant.ORDER_STATUS_6).setAfterSaleStatus(CommonConstant.NUMBER_2);
                    appOrderProInfoService.updateById(appOrderProInfo);
                }
                AppOrderRefundsInfo appOrderRefundsInfo = appOrderRefundsInfoService.getOne(Wrappers.<AppOrderRefundsInfo>lambdaQuery().eq(AppOrderRefundsInfo::getOrderId,
                        appOrder.getId()).eq(AppOrderRefundsInfo::getRefundId, refundData.getTransactionRefundId()).last("limit 1"));
                appOrderRefundsInfo.setStatus(refundData.getStatus());
                appOrderRefundsInfo.setSuccessTime(refundData.getSuccessTime());
                appOrderRefundsInfoService.updateById(appOrderRefundsInfo);
            }

            @Override
            public void fail(WechatCallbackRefundData refundData) {
                log.info("---------------------------------------------------微信退款失败回调");
                //  特殊情况下退款失败业务处理，例如银行卡冻结需要人工退款，此时可以邮件或短信提醒管理员，并携带退款单号等关键信息
                AppOrder appOrder = appOrderService.getOne(Wrappers.lambdaQuery(AppOrder.class).eq(AppOrder::getOrderCode, refundData.getOrderNo()));
                appOrder.setOrderStatus(CommonConstant.ORDER_STATUS_6).setAfterSaleStatus(CommonConstant.NUMBER_2);
                appOrderService.updateById(appOrder);

                List<AppOrderProInfo> orderProInfoList = appOrderProInfoService.list(Wrappers.<AppOrderProInfo>lambdaQuery().ne(AppOrderProInfo::getType, CommonConstant.ORDER_PRO_INFO_TYPE_6).eq(AppOrderProInfo::getOrderId,
                        appOrder.getId()));

                for (AppOrderProInfo appOrderProInfo : orderProInfoList) {
                    appOrderProInfo.setOrderStatus(CommonConstant.ORDER_STATUS_6).setAfterSaleStatus(CommonConstant.NUMBER_2);
                    appOrderProInfoService.updateById(appOrderProInfo);
                }
                AppOrderRefundsInfo appOrderRefundsInfo =
                        appOrderRefundsInfoService.getOne(Wrappers.<AppOrderRefundsInfo>lambdaQuery()
                                .eq(AppOrderRefundsInfo::getOrderId, appOrder.getId())
                                .eq(AppOrderRefundsInfo::getRefundId, refundData.getTransactionRefundId())
                        );
                appOrderRefundsInfo.setStatus(refundData.getStatus());
                appOrderRefundsInfoService.updateById(appOrderRefundsInfo);
            }
        });

    }

    /**
     * 订单-小程序退款详情
     *
     * @param orderId
     * @param orderProInfoId
     * @return
     */
    @Operation(summary = "订单-小程序退款详情")
    @GetMapping("/getRefundsInfo")
    public Result<RefundsInfoDTO> getRefundsInfo(@RequestParam(name = "orderId") String orderId,
                                                 @RequestParam(name = "orderProInfoId") String orderProInfoId) {
        return Result.ok(appOrderRefundsInfoService.getRefundsInfo(orderId, orderProInfoId));
    }

    /**
     * 订单-小程序支付后回显信息
     *
     * @param orderId
     * @return
     */
    @Operation(summary = "订单-小程序支付后回显信息")
    @GetMapping("/queryOrderInfo")
    public Result<AppOrderInfoDTO> queryOrderInfo(@Schema(description = "订单ID") @RequestParam(name = "orderId") String orderId) {
        return Result.ok(appOrderService.queryOrderInfo(orderId));
    }

    /**
     * 订单-查询课程课时核销记录
     *
     * @param orderId
     * @param ticketNo
     * @return
     */
    @Operation(summary = "订单-查询课程课时核销记录")
    @GetMapping("/queryOrderVerifyRecords")
    public Result<List<QueryOrderVerifyRecordsVO>> queryOrderVerifyRecords(@Schema(description = "订单ID") @RequestParam(name = "orderId") String orderId,
                                                                           @Schema(description = "券号") @RequestParam(name = "ticketNo") String ticketNo) {
        return Result.ok(appOrderService.queryOrderVerifyRecords(orderId, ticketNo));
    }

    /**
     * 订单-查询券使用记录
     *
     * @param ticketNo
     * @return
     */
    @Operation(summary = "订单-查询券使用记录")
    @GetMapping("/queryOrderUseRecords")
    public Result<AppOrderUseRecordsVO> queryOrderUseRecords(@Schema(description = "券号") @RequestParam(name = "ticketNo") String ticketNo) {
        AppOrderUseRecordsVO appOrderUseRecordsVO = appIsinService.queryOrderUseRecords(ticketNo);
        return Result.ok(appOrderUseRecordsVO);
    }

    /**
     * @return
     * @Author SheepHy
     * @Description 体育馆无固定场-预览页
     * @Date 17:22 2025/8/4
     * @Param
     **/
    @Operation(summary = "体育馆无固定场-预览页")
    @GetMapping("/PreviewOrderPlaceGymnasiumNoFixation")
    public Result<OrderVO.PreviewOrderPlaceGymnasiumNoFixation> previewOrderPlaceGymnasiumNoFixation(@RequestParam("placeId") @Schema(description = "场地ID") String placeId) {
        return Result.ok(appOrderService.previewOrderPlaceGymnasiumNoFixation(placeId));
    }
}
