package com.yc.ship.module.otc.api.store;


import cn.hutool.core.util.ObjectUtil;
import com.yc.ship.framework.common.exception.ServiceException;
import com.yc.ship.framework.common.lang.Asserts;
import com.yc.ship.framework.common.pojo.CommonResult;
import com.yc.ship.framework.common.util.object.BeanUtils;
import com.yc.ship.framework.tenant.core.context.TenantContextHolder;
import com.yc.ship.module.otc.api.store.StoreApi;
import com.yc.ship.module.otc.api.store.dto.*;
import com.yc.ship.module.otc.controller.admin.store.vo.StoreSaveReqVO;
import com.yc.ship.module.otc.controller.admin.store.vo.StoreSimpleReqVO;
import com.yc.ship.module.otc.controller.admin.storetradelog.vo.StoreTradeLogRespVO;
import com.yc.ship.module.otc.convert.store.StoreConvert;
import com.yc.ship.module.otc.dal.dataobject.store.StoreDO;
import com.yc.ship.module.otc.dal.dataobject.store.StoreMachineDO;
import com.yc.ship.module.otc.dal.dataobject.storecard.StoreCardDO;
import com.yc.ship.module.otc.dal.dataobject.storecreditlog.StoreCreditLogDO;
import com.yc.ship.module.otc.dal.dataobject.storetradelog.StoreTradeLogDO;
import com.yc.ship.module.otc.enums.TradeModeEnum;
import com.yc.ship.module.otc.enums.UseStatusEnum;
import com.yc.ship.module.otc.service.store.StoreService;
import com.yc.ship.module.otc.service.storecard.StoreCardService;
import com.yc.ship.module.otc.service.storecreditlog.StoreCreditLogService;
import com.yc.ship.module.otc.service.storetradelog.StoreTradeLogService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception0;
import static com.yc.ship.module.otc.enums.ErrorCodeConstants.*;


/**
 * &#064;Description 旅行社授权接口
 * &#064;Author qsl
 * &#064;Date 2025/6/4 15:28
 */
@RestController // 提供 RESTful API 接口，给 Feign 调用
@Validated
@Slf4j
public class StoreApiImpl implements StoreApi {

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private StoreService storeService;
    @Resource
    private StoreCardService storeCardService;

    @Resource
    private StoreTradeLogService storeTradeLogService;

    @Resource
    private StoreCreditLogService storeCreditLogService;

    @Override
    public CommonResult<Long> storeTrade(StoreReqDTO reqDTO) {
        Long logId = null;
        TradeModeEnum tradeModeEnum = null;
        String orderId = reqDTO.getOrderId().toString();
        if (reqDTO.getOperateMode() == 2) {
            List<StoreTradeLogDO> tradeLogList = storeTradeLogService.getStoreTradeLogByOrderId(reqDTO.getStoreId(), orderId);
            if (tradeLogList == null || tradeLogList.isEmpty()) {
                // 支付
                String key = "[storeTrade-in]" + reqDTO.getStoreId();
                RLock lock = redissonClient.getLock(key);
                try {
                    if (lock.tryLock(30, 60, TimeUnit.SECONDS)) {
                        if(reqDTO.getOperateType() == null){
                            // 余额支付
                            tradeModeEnum = TradeModeEnum.valueOf(1, 5, reqDTO.getOperateMode());
                            reqDTO.setTradeModeEnum(tradeModeEnum);
                            logId = orderTrade(reqDTO);
                            if (logId == null) {
                                // 授信支付
                                tradeModeEnum = TradeModeEnum.valueOf(2, 6, reqDTO.getOperateMode());
                                reqDTO.setTradeModeEnum(tradeModeEnum);
                                logId = orderTrade(reqDTO);
                            }
                        }else{
                            //搬单传进来的5 是余额， 6是预付款
                            if(reqDTO.getOperateType() == 5){
                                tradeModeEnum = TradeModeEnum.valueOf(1, 5, reqDTO.getOperateMode());
                                reqDTO.setTradeModeEnum(tradeModeEnum);
                                logId = orderTrade(reqDTO);
                                Asserts.isTrue(logId !=null,"门店余额不足");
                            }
                            if(reqDTO.getOperateType() == 6){
                                tradeModeEnum = TradeModeEnum.valueOf(2, 6, reqDTO.getOperateMode());
                                reqDTO.setTradeModeEnum(tradeModeEnum);
                                logId = orderTrade(reqDTO);
                                Asserts.isTrue(logId !=null,"门店授信额度不足");
                            }
                            reqDTO.setOperateType(null);
                        }

                        if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                            lock.unlock();
                        }
                    }
                } catch (ServiceException e) {
                    return CommonResult.error(e);
                } catch (Exception e) {
                    log.error("[storeTrade] lock error", e);
                    return CommonResult.error(STORE_REQUEST_EXCEPTION_ERROR);
                }
            } else {
                logId = tradeLogList.get(0).getId();
            }
        }
        if (reqDTO.getOperateMode() == 1) {
            // 退款
            if (reqDTO.getRefundId() == null) {
                return CommonResult.error(20_011, "退款单号必传");
            }
            List<StoreTradeLogDO> tradeLogList = storeTradeLogService.getStoreTradeLogByOrderId(reqDTO.getStoreId(), orderId);
            if (tradeLogList == null || tradeLogList.isEmpty()) {
                return CommonResult.error(STORE_REQUEST_ORDER_NOT_EXIST);
            }
            // 支付的流水 只有一条
            List<StoreTradeLogDO> payTradeLogList = tradeLogList.stream()
                    .filter(tradeLogDO -> tradeLogDO.getTradeMode() == 2)
                    .collect(Collectors.toList());
            StoreTradeLogDO payTradeLogDO = payTradeLogList.get(0);
            BigDecimal payAmount = payTradeLogDO.getTradeAmount();
            // 已退的流水 可能有多条
            List<StoreTradeLogDO> refundTradeLogList = tradeLogList.stream()
                    .filter(tradeLogDO -> tradeLogDO.getTradeMode() == 1)
                    .collect(Collectors.toList());
            // 已退金额
            BigDecimal returnedAmount = BigDecimal.ZERO;
            for (StoreTradeLogDO refundTradeLog : refundTradeLogList) {
                returnedAmount = returnedAmount.add(refundTradeLog.getTradeAmount());
            }
            if (payAmount.compareTo(returnedAmount.add(reqDTO.getAmount())) < 0) {
                // 退款金额超出订单总支付金额，不能退款
                return CommonResult.error(STORE_REQUEST_AMOUNT_EXCEED);
            }
            if (payTradeLogDO.getTradeType() == 5) {
                // 3.余额购票、5.余额退款
                tradeModeEnum = TradeModeEnum.valueOf(1, 7, reqDTO.getOperateMode());
            }
            if (payTradeLogDO.getTradeType() == 6) {
                // 4.授信购票、6.授信退款
                tradeModeEnum = TradeModeEnum.valueOf(2, 8, reqDTO.getOperateMode());
            }
            reqDTO.setTradeModeEnum(tradeModeEnum);
            logId = orderTrade(reqDTO);
        }
        if (reqDTO.getOperateMode() == 3) {
            List<StoreTradeLogDO> tradeLogList = storeTradeLogService.getStoreTradeLogByOrderId(reqDTO.getStoreId(), orderId);
            if (tradeLogList == null || tradeLogList.isEmpty()) {
                return CommonResult.error(STORE_REQUEST_ORDER_NOT_EXIST);
            }
            // 正常回滚需要验证支付记录是否只有一条 如果有多条，则为异常订单记录，不能回滚
            if (tradeLogList.size() > 1) {
                return CommonResult.error(STORE_REQUEST_ORDER_TRADE_LOG_EXCEPTION);
            }
            StoreTradeLogDO payTradeLogDO = tradeLogList.get(0);
            BigDecimal payAmount = payTradeLogDO.getTradeAmount();
            if (payTradeLogDO.getTradeType() == 5) {
                // 3.余额购票、5.余额退款
                tradeModeEnum = TradeModeEnum.valueOf(1, 7, reqDTO.getOperateMode());
            }
            if (payTradeLogDO.getTradeType() == 6) {
                // 4.授信购票、6.授信退款
                tradeModeEnum = TradeModeEnum.valueOf(2, 8, reqDTO.getOperateMode());
            }
            reqDTO.setAmount(payAmount);
            reqDTO.setTradeModeEnum(tradeModeEnum);
            reqDTO.setLogId(payTradeLogDO.getId());
            logId = orderTrade(reqDTO);
        }
        if (logId != null) {
            return CommonResult.success(logId);
        }
        return CommonResult.error(STORE_REQUEST_PAY_ERROR);
    }

    @Override
    public CommonResult<StoreMachineDTO> getMachineByMachineId(String machineId) {
        StoreMachineDTO storeMachineDTO = storeService.getMachineByMachineId(machineId);
        Asserts.isTrue(storeMachineDTO != null && ObjectUtil.equal(storeMachineDTO.getIsUse(), UseStatusEnum.ENABLE.getStatus()), "设备不存在或未启用{}", machineId);
        return CommonResult.success(storeMachineDTO);
    }

    @Override
    public CommonResult<StoreMachineDTO> getMachineById(Long id) {
        StoreMachineDO storeMachineDO = storeService.getStoreMachine(id);
        Asserts.isTrue(storeMachineDO != null && ObjectUtil.equal(storeMachineDO.getIsUse(), UseStatusEnum.ENABLE.getStatus()), "设备不存在或未启用{}", id);
        return CommonResult.success(StoreConvert.INSTANCE.convert(storeMachineDO));
    }

    @Override
    public CommonResult<StoreInfoReqDTO> getStoreById(Long id) {
        StoreDO storeDO = storeService.getStore(id);
        StoreInfoReqDTO storeInfoReqDTO = BeanUtils.toBean(storeDO, StoreInfoReqDTO.class);
        StoreCardDO storeCardDO = storeCardService.getStoreCardByStoreId(storeDO.getId());
        storeInfoReqDTO.setBalanceType(storeCardDO.getBalanceType());
        storeInfoReqDTO.setCreditType(storeCardDO.getCreditType());
        return CommonResult.success(storeInfoReqDTO);
    }

    private Long orderTrade(StoreReqDTO reqDTO) {
        Long logId = null;
        Long storeId = reqDTO.getStoreId();
        StoreDO store = storeService.getStore(storeId);

//        RLock lock = null;
        try {
//            if(reqDTO.getOrderId()!=null){
//                //防止重复提交,如果有记录了就直接返回 ，忽略reqDTO.getTradeModeEnum().getOperateType() == 3 的情况
//                String key = "store_trade_log:"+reqDTO.getOrderId();
//                lock = redissonClient.getLock(key);
//                lock.lock();
//                StoreTradeLogDO storeTradeLog = storeTradeLogService.getStoreTradeLog(reqDTO.getOrderId(), reqDTO.getTradeModeEnum());
//                if(storeTradeLog!=null){
//                    return storeTradeLog.getId();
//                }
//            }

            if (store == null) {
                throw exception0(20_012, "门店不存在！");
            }
            if (store.getIsUse() == 0) {
                throw exception0(20_012, "门店已停用！");
            }
            logId = storeService.updateStoreCard(storeId, reqDTO.getTradeModeEnum(), reqDTO.getAmount(), reqDTO.getUserId(), reqDTO.getOrderId(), reqDTO.getRefundId(), reqDTO.getLogId());
            return logId;
        }finally {
//            if(lock!=null && lock.isLocked() && lock.isHeldByCurrentThread()){
//                lock.unlock();
//            }
        }
    }

    @Override
    public CommonResult<StoreRespDTO> storePlatTrade(StoreReqDTO reqDTO) {

        Long logId = orderTrade(reqDTO);
        if (logId != null) {
            StoreRespDTO storeRespDTO = new StoreRespDTO();
            storeRespDTO.setId(logId);
            try {
                if (reqDTO.getTradeModeEnum().getOperateType() == 3) {
                    StoreCreditLogDO storeCreditLogDO = storeCreditLogService.getStoreCreditLog(logId);
                    storeRespDTO.setAfterAmount(storeCreditLogDO.getAfterCredit());
                    storeRespDTO.setAmount(storeCreditLogDO.getCreditAmount());
                    storeRespDTO.setBeforeAmount(storeCreditLogDO.getBeforeCredit());
                }else{
                    StoreTradeLogRespVO storeTradeLogDO =  storeTradeLogService.getStoreTradeLog(logId);
                    storeRespDTO.setAfterAmount(storeTradeLogDO.getAfterBalance());
                    storeRespDTO.setAmount(storeTradeLogDO.getTradeAmount());
                    storeRespDTO.setBeforeAmount(storeTradeLogDO.getBeforeBalance());
                }
            }catch (Exception e) {
                //此处捕获，资金已处理完成
                log.error("日志保存异常",e);
            }

            return CommonResult.success(storeRespDTO);
        }
        return CommonResult.error(STORE_REQUEST_PLAT_SURPLUS);
    }

    @Override
    public CommonResult<Long> createDefaultStore(Long tenantId) {
        //默认门店、设备
        Long oldTenantId = TenantContextHolder.getTenantId();
        TenantContextHolder.setTenantId(tenantId);
        TenantContextHolder.setIgnore(false);
        StoreSaveReqVO storeSaveReqVO = new StoreSaveReqVO();
        storeSaveReqVO.setStoreName("默认门店");
        storeSaveReqVO.setStoreCode("00001");
        storeSaveReqVO.setIsUse(1);
        storeSaveReqVO.setAuditStatus(1);
        storeSaveReqVO.setSortNum(1);
        storeSaveReqVO.setCreditType(0);
        storeSaveReqVO.setBalanceType(0);
        Long storeId = storeService.createStore(storeSaveReqVO);

        StoreMachineDO machineDO = new StoreMachineDO();
        machineDO.setStoreId(storeId);
        machineDO.setMachineName("0001");
        machineDO.setMachineId("0001");
        machineDO.setIsUse(1);
        machineDO.setMachineType(0);
        machineDO.setSortNum(1);
        storeService.createStoreMachine(machineDO);
        TenantContextHolder.setTenantId(oldTenantId);
        return CommonResult.success(storeId);
    }

    @Override
    public CommonResult<StoreCardRespDTO> getStoreByUserId(Long userId) {
        //通过用户id获取门店信息和设备信息
        StoreCardRespDTO storeDO = storeService.getStoreByUserId(userId);
        return CommonResult.success(BeanUtils.toBean(storeDO, StoreCardRespDTO.class));
    }

    @Override
    public CommonResult<Boolean> syncStoreProductStatus(StoreProductReqDTO reqDTO) {
        storeService.updateStoreProductStatus(reqDTO);
        return CommonResult.success(true);
    }

    @Override
    public StoreInfoRespDTO getStoreInfo(Long id) {
        StoreDO store = storeService.getStore(id);
        StoreInfoRespDTO storeInfoRespDTO = new StoreInfoRespDTO();
        storeInfoRespDTO.setId(store.getId());
        storeInfoRespDTO.setName(store.getStoreName());
        return storeInfoRespDTO;
    }

    @Override
    public List<StoreInfoRespDTO> getStoreList() {
        List<StoreDO> storeList = storeService.getStoreList(new StoreSimpleReqVO().setStatus(UseStatusEnum.ENABLE.getStatus()));
        return BeanUtils.toBean(storeList, StoreInfoRespDTO.class);
    }
}
