package com.ruoyi.web.controller.app;

import com.fasterxml.jackson.annotation.JsonView;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.JsonViewProfile;
import com.ruoyi.common.core.domain.ValidGroup;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.enums.OperatorType;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.dashboard.domain.vo.BillCountVo;
import com.ruoyi.ss.device.service.DeviceService;
import com.ruoyi.ss.device.service.DeviceValidator;
import com.ruoyi.ss.suit.domain.enums.SuitFeeType;
import com.ruoyi.ss.transactionBill.domain.TransactionBillQuery;
import com.ruoyi.ss.transactionBill.domain.bo.EndUseBO;
import com.ruoyi.ss.transactionBill.domain.dto.*;
import com.ruoyi.ss.transactionBill.domain.vo.TransactionBillVO;
import com.ruoyi.ss.transactionBill.domain.enums.TransactionBillGroupBy;
import com.ruoyi.ss.transactionBill.domain.enums.TransactionBillStatus;
import com.ruoyi.ss.transactionBill.domain.enums.TransactionBillType;
import com.ruoyi.ss.transactionBill.service.TransactionAssembler;
import com.ruoyi.ss.transactionBill.service.TransactionBillConverter;
import com.ruoyi.ss.transactionBill.service.TransactionBillService;
import com.ruoyi.ss.transactionBill.service.TransactionBillValidator;
import com.ruoyi.ss.user.domain.SmUserVO;
import com.ruoyi.ss.user.service.ISmUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * 充值记录Controller
 *
 * @author 邱贞招
 * @date 2024-02-21
 */
@Api(tags = "充值/提现记录")
@RestController
@RequestMapping("/app/bill")
public class AppTransactionBillController extends BaseController
{
    @Autowired
    private TransactionBillService transactionBillService;

    @Autowired
    private TransactionAssembler transactionAssembler;

    @Autowired
    private TransactionBillValidator transactionBillValidator;

    @Autowired
    private DeviceValidator deviceValidator;

    @Autowired
    private TransactionBillConverter transactionBillConverter;

    @Autowired
    private ISmUserService userService;

    @Autowired
    private DeviceService deviceService;

    /**
     * 查询充值记录列表
     */
    @ApiOperation("查询本人订单列表")
    @GetMapping("/rechargeList")
    @JsonView(JsonViewProfile.App.class)
    public TableDataInfo rechargeList(TransactionBillQuery smTransactionBill)
    {
        smTransactionBill.setUserId(getUserId());
        smTransactionBill.setType(TransactionBillType.RECHARGE.getType());
        startPage();
        List<TransactionBillVO> list = transactionBillService.selectSmTransactionBillList(smTransactionBill);
        transactionAssembler.assembleChannelName(list);
        return getDataTable(list);
    }

    /**
     * 查询提现记录列表
     */
    @ApiOperation("查询本人提现记录列表")
    @GetMapping("/withdrawList")
    public TableDataInfo withdrawList(TransactionBillQuery smTransactionBill)
    {
        startPage();
        smTransactionBill.setUserId(getUserId());
        smTransactionBill.setType(TransactionBillType.WITHDRAW.getType());
        List<TransactionBillVO> list = transactionBillService.selectSmTransactionBillList(smTransactionBill);
        return getDataTable(list);
    }

    /**
     * 查询收支列表
     */
//    @MchRequired
    @ApiOperation("查询本人收支列表")
    @GetMapping("/list")
    @JsonView(JsonViewProfile.AppMch.class)
    public TableDataInfo list(TransactionBillQuery smTransactionBill)
    {
        startPage();
        smTransactionBill.setUserId(getUserId());
        List<TransactionBillVO> list = transactionBillService.selectSmTransactionBillList(smTransactionBill);
        transactionAssembler.assembleChannelName(list);
        return getDataTable(list);
    }

    @ApiOperation("查询本人收款的订单列表")
    @GetMapping("/incomeList")
    @JsonView(JsonViewProfile.AppMch.class)
    public TableDataInfo incomeList(TransactionBillQuery query)
    {
        startPage();
        query.setIncomeUserId(getUserId());
        query.setType(TransactionBillType.RECHARGE.getType());
        List<TransactionBillVO> list = transactionBillService.selectSmTransactionBillList(query);
        transactionAssembler.assembleChannelName(list);
        transactionAssembler.handleMchUserMobile(list);
        transactionAssembler.assembleOperator(list, getUserId());
        return getDataTable(list);
    }

    @ApiOperation("获取订单详情")
    @GetMapping("/{billId}")
    @JsonView(JsonViewProfile.AppUser.class)
    public AjaxResult detail(@PathVariable Long billId) {
        ServiceUtil.assertion(transactionBillValidator.preGetDetailByApp(billId, getUserId()));
        TransactionBillVO bill = transactionBillService.selectSmTransactionBillByBillId(billId);
        if (!transactionBillValidator.canViewOrder(bill, getUserId())) {
            return error("您不允许查看该订单");
        }
        List<TransactionBillVO> list = Collections.singletonList(bill);
        transactionAssembler.assembleChannelName(Collections.singletonList(bill));
        transactionAssembler.handleMchUserMobile(list);
        transactionAssembler.assembleOperator(list, getUserId());
        return AjaxResult.success(bill);
    }

    @ApiOperation("通过订单编号获取订单详情")
    @GetMapping("/byNo/{billNo}")
    @JsonView(JsonViewProfile.AppUser.class)
    public AjaxResult detail(@PathVariable String billNo) {
        TransactionBillVO bill = transactionBillService.selectSmTransactionBillByBillNo(billNo);
        if (!transactionBillValidator.canViewOrder(bill, getUserId())) {
            return error("您不允许查看该订单");
        }
        transactionAssembler.assembleChannelName(Collections.singletonList(bill));
        return success(bill);
    }

//    @MchRequired
    @ApiOperation("获取商户统计信息")
    @JsonView(JsonViewProfile.AppMch.class)
    @GetMapping("/landlordCount")
    public AjaxResult landlordCount(@Validated({ValidGroup.Query.class}) TransactionBillQuery dto) {
        LocalDate now = LocalDate.now();
        if (dto.getEndDate() == null) {
            dto.setEndDate(now);
        }
        // 如果按日查询
        if (Objects.equals(dto.getGroupBy(), TransactionBillGroupBy.create_date.name())) {
            // 以下是新的需求，如果按日分组，则查询当月第一天到最后一天的数据，并补全中间缺少的数据
            dto.setStartDate(DateUtils.toLocalDate(DateUtils.getMonthFirstDate(dto.getYear(), dto.getMonth())));
            dto.setEndDate(DateUtils.toLocalDate(DateUtils.getMonthLastDate(dto.getYear(), dto.getMonth())));
        }

        // FIXME 需要过滤掉退款的金额
        dto.setMchId(getUserId());
        dto.setStatusList(TransactionBillStatus.income());
        AjaxResult ajax = AjaxResult.success(transactionBillService.selectLandlordCount(dto));

        // 总收入
        TransactionBillQuery allQuery = new TransactionBillQuery();
        allQuery.setMchId(getUserId());
        List<BillCountVo> totalList = transactionBillService.selectCount(allQuery);
        if (CollectionUtils.isEmpty(totalList)) {
            ajax.put("totalRecharge", 0);
        } else {
            BigDecimal total = totalList.get(0).getRecharge();
            ajax.put("totalRecharge", total == null ? 0 : total);
        }

        return ajax;
    }

    @Log(title = "创建订单", businessType = BusinessType.INSERT, operatorType = OperatorType.MOBILE)
    @ApiOperation("创建订单")
    @PostMapping("/recharge")
    public AjaxResult addRecharge(@RequestBody @Validated RechargeDTO dto) {
        return AjaxResult.success("操作成功", transactionBillService.addOrder(transactionBillConverter.toRechargeBO(dto)));
    }

    @Log(title = "取消充值订单", businessType = BusinessType.OTHER, operatorType = OperatorType.MOBILE)
    @ApiOperation("取消充值订单")
    @PutMapping("/recharge/cancel/{billNo}")
    public AjaxResult cancelRecharge(@PathVariable @ApiParam("订单编号") String billNo) {
        TransactionBillVO bill = transactionBillService.selectSmTransactionBillByBillNo(billNo);
        if (!transactionBillValidator.isMch(bill, getUserId())) {
            return error("您不是该订单的商户，无法取消");
        }
        return AjaxResult.success(transactionBillService.cancelRecharge(billNo, TransactionBillStatus.CANCELED));
    }

    @Log(title = "提现申请", businessType = BusinessType.INSERT, operatorType = OperatorType.MOBILE)
    @ApiOperation("提现申请")
    @PostMapping("/withdraw")
    public AjaxResult withdraw(@RequestBody @Validated WithdrawDTO dto) {
        dto.setUserId(getUserId());
        return AjaxResult.success("操作成功", transactionBillService.addWithdraw(transactionBillConverter.toWithdrawBO(dto)));
    }

    @Log(title = "查询设备充值失败列表", businessType = BusinessType.OTHER, operatorType = OperatorType.MOBILE)
    @ApiOperation("查询设备充值失败列表")
    @GetMapping("/recharge/device/fail/list")
    public AjaxResult selectDeviceRechargeFailList() {
        return AjaxResult.success(transactionBillService.selectDeviceRechargeFailList(getUserId()));
    }

//    @MchRequired
    @ApiOperation("获取设备充值列表")
    @GetMapping("/rechargeListByDevice")
    @JsonView(JsonViewProfile.AppMch.class)
    public TableDataInfo getDeviceRechargeList(@RequestParam @ApiParam("设备id") Long deviceId) {
        ServiceUtil.assertion(!deviceValidator.isMch(deviceId, getUserId()), "这不是您的设备，无法查询");
        TransactionBillQuery query = new TransactionBillQuery();
        query.setDeviceId(deviceId);
        query.setMchId(getUserId());
        query.setType(TransactionBillType.RECHARGE.getType());
        query.setStatus(TransactionBillStatus.SUCCESS.getStatus());
        startPage();
        List<TransactionBillVO> list = transactionBillService.selectSmTransactionBillList(query);
        // 处理手机号
        transactionAssembler.handleMchUserMobile(list);
        return getDataTable(list);
    }

    @ApiOperation("蓝牙充值成功回调")
    @Log(title = "蓝牙充值成功回调", businessType = BusinessType.OTHER,  operatorType = OperatorType.MOBILE)
    @GetMapping("/recharge/{billNo}/bluetoothSuccess")
    public AjaxResult bluetoothRechargeSuccess(@PathVariable String billNo) {
        return success(transactionBillService.bluetoothRechargeSuccess(billNo));
    }

    @Log(title = "订单退款", businessType = BusinessType.OTHER, operatorType = OperatorType.MOBILE)
    @ApiOperation("订单退款")
    @PutMapping("/refund")
    public AjaxResult refund(@RequestBody @Validated BillRefundDTO dto) {
        // 判断用户是否订单收款人
        TransactionBillVO bill = transactionBillService.selectSmTransactionBillByBillId(dto.getBillId());
        if (bill == null) {
            return error("订单不存在");
        }
        Long userId = getUserId();
        if (!transactionBillValidator.canOperaOrder(bill, userId)) {
            return error("您无权操作该订单的退款");
        }

        // 判断是否限制退款
        SmUserVO user = userService.selectSmUserByUserId(userId);
        transactionBillValidator.checkRefundRisk(user);

        LoginUser loginUser = getLoginUser();
        dto.setUserName(loginUser.getUsername());
        dto.setUserType(loginUser.getLoginType().getType());
        dto.setUserId(getUserId());
        dto.setRefundReason(String.format("充值订单退款:%s", bill.getBillNo()));
        return toAjax(transactionBillService.refund(dto));
    }

    @Log(title = "刷新支付结果", businessType = BusinessType.OTHER, operatorType = OperatorType.MOBILE)
    @ApiOperation("刷新支付结果")
    @PutMapping("/{billNo}/refreshPayResult")
    public AjaxResult refreshPayResult(@PathVariable String billNo ) {
        return toAjax(transactionBillService.refreshPayResult(billNo));
    }

    @ApiOperation("获取用户提现手续费")
    @GetMapping("/getWithdrawService")
    public AjaxResult getWithdrawService(@RequestParam @ApiParam("渠道ID") Long channelId) {
        return success(transactionBillService.getUserWithdrawService(getUserId(), channelId));
    }

    @Log(title = "支付押金", businessType = BusinessType.OTHER, operatorType = OperatorType.MOBILE)
    @ApiOperation("支付押金")
    @PutMapping("/payDeposit")
    public AjaxResult payDeposit(@RequestBody @Validated PayDepositDTO dto) {
        return success(transactionBillService.payDeposit(transactionBillConverter.toRechargePayDepositBO(dto)));
    }

    @Log(title = "提前结束使用订单", businessType = BusinessType.OTHER, operatorType = OperatorType.MOBILE)
    @ApiOperation("提前结束使用订单")
    @PutMapping("/endUse")
    public AjaxResult endUse(@RequestBody @Validated EndUseDTO dto) {
        EndUseBO bo = transactionBillConverter.toEndUseBO(dto);
        if (!transactionBillValidator.isUser(bo.getOrder(), getUserId()) && !transactionBillValidator.isMch(bo.getOrder(), getUserId())) {
            return error("您不是该订单的用户或商户，无法结束订单");
        }

        TransactionBillVO order = bo.getOrder();

        if (SuitFeeType.rechargeTimeList().contains(order.getSuitFeeType())) {
            int i = deviceService.resetWithBill(order.getDeviceId(), false, bo.getTotalEle(), "提前结束使用订单:" + order.getBillNo(), true, false);
            return toAjax(i);
        } else if (SuitFeeType.rechargeCountList().contains(order.getSuitFeeType())) {
            int i = deviceService.resetWithBill(order.getDeviceId(), false, bo.getTotalEle(), "提前结束使用订单:" + order.getBillNo(), false, true);
            return toAjax(i);
        }

        return error("未知的订单套餐类型");
    }

    @Log(title = "提前结束使用智能订单", businessType = BusinessType.OTHER, operatorType = OperatorType.MOBILE)
    @ApiOperation("提前结束使用智能订单")
    @PutMapping("/endSmartUse")
    public AjaxResult endSmartUse(@RequestBody @Validated EndUseDTO dto) {
        return error("当前接口已弃用，请使用/app/bill/endUse");
//        EndUseBO bo = transactionBillConverter.toEndUseBO(dto);
//        if (!transactionBillValidator.isUser(bo.getOrder(), getUserId()) && !transactionBillValidator.isMch(bo.getOrder(), getUserId())) {
//            return error("您不是该订单的用户或商户，无法结束订单");
//        }
//        return success(transactionBillService.endUse(bo, true ));
    }


    @Log(title = "提前结束使用分时段订单", businessType = BusinessType.OTHER, operatorType = OperatorType.MOBILE)
    @ApiOperation("提前结束使用分时段订单")
    @PutMapping("/endTimingUse")
    public AjaxResult endTimingUse(@RequestBody @Validated EndUseDTO dto) {
        return error("当前接口已弃用，请使用/app/bill/endUse");
//        EndUseBO bo = transactionBillConverter.toEndUseBO(dto);
//        if (!transactionBillValidator.isUser(bo.getOrder(), getUserId()) && !transactionBillValidator.isMch(bo.getOrder(), getUserId())) {
//            return error("您不是该订单的用户或商户，无法结束订单");
//        }
//        return success(transactionBillService.endUse(bo, true ));
    }

    @ApiOperation("获取订单预估金额")
    @GetMapping("/calcPrice")
    public AjaxResult calcPrice(@RequestParam Long billId, @RequestParam(required = false) BigDecimal totalEle) {
        return success(transactionBillService.calcAmount(billId, LocalDateTime.now(), totalEle));
    }

    @ApiOperation("获取本人使用中的订单列表")
    @GetMapping("/usingList")
    @JsonView(JsonViewProfile.App.class)
    public AjaxResult getUsingList(TransactionBillQuery query) {
        query.setUserId(getUserId());
        return success(transactionBillService.selectUsingBill(query));
    }

    @ApiOperation("获取本人未支付的分时段订单列表")
    @GetMapping("/unpaidTimingList")
    @JsonView(JsonViewProfile.App.class)
    public AjaxResult getUnpaidTimingList(TransactionBillQuery query) {
        query.setUserId(getUserId());
        return success(transactionBillService.selectUnpaidTimingBill(query));
    }

    @ApiOperation("开启/关闭正在使用的订单设备")
    @Log(title = "开启/关闭正在使用的订单设备", businessType = BusinessType.OTHER, operatorType = OperatorType.MOBILE)
    @PutMapping("/switchDevice")
    public AjaxResult switchDevice(@RequestParam Long billId, @RequestParam Boolean open) {
        TransactionBillQuery query = new TransactionBillQuery();
        query.setUserId(getUserId());
        query.setBillId(billId);
        TransactionBillVO bill = transactionBillService.selectOne(query);
        if (bill == null) {
            return error("订单不存在");
        }
        return toAjax(transactionBillService.switchDevice(bill, open));
    }

    @Log(title = "支付订单", businessType = BusinessType.OTHER, operatorType = OperatorType.MOBILE)
    @ApiOperation("支付订单")
    @PutMapping("/pay")
    public AjaxResult pay(@RequestBody BillPayDTO dto) {
        TransactionBillVO bill = transactionBillService.selectSmTransactionBillByBillNo(dto.getBillNo());
        if (!transactionBillValidator.isUser(bill, getUserId())) {
            return error("这不是您的订单，无法支付");
        }
        RechargePayBO bo = transactionBillConverter.toRechargePayBO(bill, dto.getChannelId());
        return success(transactionBillService.pay(bo));
    }

    @ApiOperation("充值订单设备")
    @PutMapping("/rechargeBillDevice")
    @Log(title = "充值订单设备", businessType = BusinessType.OTHER, operatorType = OperatorType.MOBILE)
    public AjaxResult rechargeBillDevice(@RequestParam String billNo) {
        TransactionBillVO bill = transactionBillService.selectSmTransactionBillByBillNo(billNo);
        if (bill == null) {
            return error("订单不存在");
        }
        return success(transactionBillService.rechargeDevice(bill.getBillId()));
    }

}
