package com.hai.service.impl;

import com.hai.common.exception.ErrorCode;
import com.hai.common.exception.ErrorHelp;
import com.hai.common.exception.SysCode;
import com.hai.common.security.UserCenter;
import com.hai.common.utils.BankNumberUtil;
import com.hai.common.utils.DateUtil;
import com.hai.dao.HighFleetOilCardMapper;
import com.hai.entity.*;
import com.hai.enum_type.*;
import com.hai.model.OilCardOrderModel;
import com.hai.model.UserInfoModel;
import com.hai.order.service.OrderService;
import com.hai.order.type.OrderPayType;
import com.hai.service.*;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.Duration;
import java.util.*;

/**
 * @className: HighFleetOilCardServiceImpl
 * @author: HuRui
 * @date: 2022/12/12
 **/
@Service("fleetOilCardService")
public class HighFleetOilCardServiceImpl implements HighFleetOilCardService {

    @Resource
    private HighFleetOilCardMapper fleetOilCardMapper;

    @Resource
    private HighFleetOilCardRecordService fleetOilCardRecordService;

    @Resource
    private HighFleetOilCardUserService fleetOilCardUserService;

    @Resource
    private HighCompanyAccountService companyAccountService;

    @Resource
    private BsCompanyService companyService;

    @Resource
    private BsOrganizationService organizationService;

    @Resource
    private OrderService orderService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private UserCenter userCenter;

    private final String LOCK_KEY = "lock_";

    @Override
    public void editData(HighFleetOilCard fleetOilCard) {
        if (fleetOilCard.getId() == null) {
            fleetOilCard.setCreateTime(new Date());
            fleetOilCard.setUpdateTime(new Date());
            fleetOilCardMapper.insert(fleetOilCard);
        } else {
            fleetOilCard.setUpdateTime(new Date());
            fleetOilCardMapper.updateByPrimaryKey(fleetOilCard);
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void recharge(String fleetCardNo, BigDecimal price, Long orgId) {
        // 查询车队油卡
        HighFleetOilCard oilCard = getFleetOilCardByCardNo(fleetCardNo);
        if (oilCard == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "油卡卡号错误");
        }
        if (!oilCard.getStatus().equals(OilCardStatusEnum.status1.getStatus())) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "油卡不处于正常状态");
        }
        // 获取锁
        Boolean lock = redisTemplate.opsForValue().setIfAbsent(LOCK_KEY+fleetCardNo, "");
        if (!lock) {
            try {
                Thread.sleep(100);
            } catch (Exception e) {
                e.printStackTrace();
            }
            recharge(fleetCardNo, price, orgId);
        }
        try {
            // 获取锁成功
            // 账户扣款
            Map<String, Object> consumeType = new HashMap<>();
            consumeType.put("sourceType", CompanyAmountSourceTypeEnum.type4.getType());
            consumeType.put("sourceId", oilCard.getId());
            consumeType.put("sourceContent", "车队油卡："+oilCard.getCardNo()+"，充值：￥"+price.toString());
            companyAccountService.consume(orgId, price, consumeType);

            // 变更前金额
            BigDecimal beforeAmount = oilCard.getAmount();
            // 计算金额
            oilCard.setAmount(oilCard.getAmount().add(price));
            editData(oilCard);
            // 变更后金额
            BigDecimal afterAmount = oilCard.getAmount();

            HighFleetOilCardRecord record = new HighFleetOilCardRecord();
            record.setFleetOilCardId(oilCard.getId());
            record.setFleetOilCardNo(oilCard.getCardNo());
            record.setType(OilCardRecordTypeEnum.type1.getType());
            record.setTransactionAmount(price);
            record.setBeforeAmount(beforeAmount);
            record.setAfterAmount(afterAmount);
            record.setSourceType(OilCardRecordSourceTypeEnum.type1.getType());
            try {
                record.setSourceOrderNo(DateUtil.date2String(new Date(), "yyyyMMddHHmmss"));
            } catch (Exception e) {
                e.printStackTrace();
            }
            record.setSourceContent("充值油卡金额：" + record.getTransactionAmount());
            fleetOilCardRecordService.insertRecord(record);

        } finally {
            redisTemplate.delete(LOCK_KEY+fleetCardNo);
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void recycleAmount(String fleetCardNo) {
        // 查询车队油卡
        HighFleetOilCard oilCard = getFleetOilCardByCardNo(fleetCardNo);
        if (oilCard == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "油卡卡号错误");
        }
        if (!oilCard.getStatus().equals(OilCardStatusEnum.status1.getStatus())) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "油卡不处于正常状态");
        }
        // 获取锁
        Boolean lock = redisTemplate.opsForValue().setIfAbsent(LOCK_KEY+fleetCardNo, "");
        if (!lock) {
            try {
                Thread.sleep(100);
            } catch (Exception e) {
                e.printStackTrace();
            }
            recycleAmount(fleetCardNo);
        }
        try {
            // 账户进账
            Map<String, Object> rechargeType = new HashMap<>();
            rechargeType.put("sourceType", CompanyAmountSourceTypeEnum.type3.getType());
            rechargeType.put("sourceId", oilCard.getId());
            rechargeType.put("sourceContent", "油卡：" + oilCard.getCardNo() + "，回收余额：￥" + oilCard.getAmount());
            companyAccountService.recharge(oilCard.getOrgId(), oilCard.getAmount(), rechargeType);

            // 变更前金额
            BigDecimal beforeAmount = oilCard.getAmount();
            BigDecimal price = oilCard.getAmount();
            // 计算金额
            oilCard.setAmount(new BigDecimal("0"));
            editData(oilCard);
            // 变更后金额
            BigDecimal afterAmount = oilCard.getAmount();

            HighFleetOilCardRecord record = new HighFleetOilCardRecord();
            record.setFleetOilCardId(oilCard.getId());
            record.setFleetOilCardNo(oilCard.getCardNo());
            record.setType(OilCardRecordTypeEnum.type2.getType());
            record.setTransactionAmount(price);
            record.setBeforeAmount(beforeAmount);
            record.setAfterAmount(afterAmount);
            record.setSourceType(OilCardRecordSourceTypeEnum.type4.getType());
            try {
                record.setSourceOrderNo(DateUtil.date2String(new Date(), "yyyyMMddHHmmss"));
            } catch (Exception e) {
                e.printStackTrace();
            }
            record.setSourceContent("回收油卡余额：" + price);
            fleetOilCardRecordService.insertRecord(record);
        } finally {
            redisTemplate.delete(LOCK_KEY+fleetCardNo);
        }
    }

    @Override
    public HighFleetOilCard getFleetOilCardByCardNo(String fleetCardNo) {
        HighFleetOilCardExample example = new HighFleetOilCardExample();
        example.createCriteria().andCardNoEqualTo(fleetCardNo).andStatusNotEqualTo(0);
        List<HighFleetOilCard> list = fleetOilCardMapper.selectByExample(example);
        if (list.size() > 0) {
            return list.get(0);
        }
        return null;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void consume(String fleetCardNo,String contactPhone, BigDecimal amount, Map<String, Object> otherParam) {
        // 获取锁 todo api扣款需要
        Boolean lock = redisTemplate.opsForValue().setIfAbsent(LOCK_KEY+fleetCardNo, "");
        if (!lock) {
            try {
                Thread.sleep(100);
            } catch (Exception e) {
                e.printStackTrace();
            }
            consume(fleetCardNo, contactPhone, amount, otherParam);
        }
        try {
            // 查询车队油卡
            HighFleetOilCard oilCard = getFleetOilCardByCardNo(fleetCardNo);
            if (oilCard == null) {
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "油卡卡号错误");
            }
            if (!oilCard.getStatus().equals(OilCardStatusEnum.status1.getStatus())) {
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "油卡状态异常，暂无法消费");
            }
            // 油卡余额 是否小于 消费余额
            if (oilCard.getAmount().compareTo(amount) == -1) {
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "油卡余额不足");
            }
            // 油卡用户
            HighFleetOilCardUser cardUser = fleetOilCardUserService.getCardUser(oilCard.getCardNo(), contactPhone);
            if (cardUser == null) {
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "油卡未绑定" + contactPhone+"手机号");
            }
            cardUser.setAmountConsume(cardUser.getAmountConsume().add(amount));
            cardUser.setLatelyConsumeTime(new Date());
            fleetOilCardUserService.editUser(cardUser);

            // 变更前金额
            BigDecimal beforeAmount = oilCard.getAmount();
            // 计算消费后金额
            oilCard.setAmount(oilCard.getAmount().subtract(amount));
            // 累积消费金额
            oilCard.setAmountConsume(oilCard.getAmountConsume().add(amount));
            editData(oilCard);
            // 变更后金额
            BigDecimal afterAmount = oilCard.getAmount();

            HighFleetOilCardRecord record = new HighFleetOilCardRecord();
            record.setFleetOilCardId(oilCard.getId());
            record.setFleetOilCardNo(oilCard.getCardNo());
            record.setType(OilCardRecordTypeEnum.type2.getType());
            record.setTransactionAmount(amount);
            record.setBeforeAmount(beforeAmount);
            record.setAfterAmount(afterAmount);
            record.setSourceType(MapUtils.getInteger(otherParam, "sourceType"));
            record.setSourceId(MapUtils.getLong(otherParam, "sourceId"));
            record.setSourceOrderNo(MapUtils.getString(otherParam, "sourceOrderNo"));
            record.setSourceContent(MapUtils.getString(otherParam, "sourceContent"));
            fleetOilCardRecordService.insertRecord(record);

        } finally {
            redisTemplate.delete(LOCK_KEY+fleetCardNo);
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void refund(String orderNo) {
        HighOrder order = orderService.getOrderDetailByNo(orderNo);
        if (order == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知的的订单");
        }
        if (!order.getOrderStatus().equals(OrderStatusEnum.type2.getType())
            && !order.getOrderStatus().equals(OrderStatusEnum.type3.getType())
            && !order.getOrderStatus().equals(OrderStatusEnum.type7.getType())) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "订单当前状态无法退款");
        }
        if (!order.getPayType().equals(OrderPayType.PAY_TYPE8.getNumber())) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "支付方式，不是车队油卡");
        }
        if (StringUtils.isBlank(order.getMemCardNo())) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知的油卡卡号");
        }
        // 获取锁
        Boolean lock = redisTemplate.opsForValue().setIfAbsent(LOCK_KEY+order.getMemCardNo(), "");
        if (!lock) {
            try {
                Thread.sleep(100);
            } catch (Exception e) {
                e.printStackTrace();
            }
            refund(orderNo);
        }

        // 查询油卡卡号
        HighFleetOilCard oilCard = getFleetOilCardByCardNo(order.getMemCardNo());
        if (oilCard == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知的油卡卡号");
        }
        try {
            order.setOrderStatus(4);
            order.setRefundTime(new Date());
            orderService.updateOrderData(order);

            // 变更前金额
            BigDecimal beforeAmount = oilCard.getAmount();
            // 计算金额
            oilCard.setAmount(oilCard.getAmount().add(order.getPayRealPrice()));
            oilCard.setAmountConsume(oilCard.getAmountConsume().subtract(order.getPayRealPrice()));
            editData(oilCard);
            // 变更后金额
            BigDecimal afterAmount = oilCard.getAmount();

            HighFleetOilCardRecord record = new HighFleetOilCardRecord();
            record.setFleetOilCardId(oilCard.getId());
            record.setFleetOilCardNo(oilCard.getCardNo());
            record.setType(OilCardRecordTypeEnum.type1.getType());
            record.setTransactionAmount(order.getPayRealPrice());
            record.setBeforeAmount(beforeAmount);
            record.setAfterAmount(afterAmount);
            record.setSourceType(OilCardRecordSourceTypeEnum.type3.getType());
            record.setSourceId(order.getId());
            try {
                record.setSourceOrderNo(orderNo);
            } catch (Exception e) {
                e.printStackTrace();
            }
            record.setSourceContent("订单号：" + orderNo + "，退款金额：" + order.getPayRealPrice());
            fleetOilCardRecordService.insertRecord(record);

        } finally {
            redisTemplate.delete(LOCK_KEY+ oilCard.getCardNo());
        }
    }

    @Override
    public void generateCard(Long orgId, Integer generateNum) {
        UserInfoModel userInfoModel = userCenter.getSessionModel(UserInfoModel.class);
        // 查询部门信息
        BsOrganization organization = organizationService.findById(orgId);
        if (organization == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到部门");
        }
        BsCompany company = companyService.getCompanyById(organization.getCompanyId());

        HighFleetOilCard oilCard;
        for (int i = 0; i < generateNum; i++) {
            oilCard = new HighFleetOilCard();
            oilCard.setCompanyId(organization.getCompanyId());
            oilCard.setCompanyName(company.getName());
            oilCard.setOrgId(organization.getId());
            oilCard.setOrgName(organization.getName());
            oilCard.setAmount(new BigDecimal("0"));
            oilCard.setAmountConsume(new BigDecimal("0"));
            oilCard.setCardNo(BankNumberUtil.getBrankNumber("8"));
            oilCard.setOpUserId(userInfoModel.getSecUser().getId());
            oilCard.setOpUserName(userInfoModel.getSecUser().getUserName());
            oilCard.setCreateTime(new Date());
            oilCard.setUpdateTime(new Date());
            oilCard.setStatus(FleetOilCardStatusEnum.status1.getStatus());
            editData(oilCard);
        }
    }

    @Override
    public void setContact(String cardNo, String contactName, String contactPhone) {
        // 查询油卡
        HighFleetOilCard oilCard = getFleetOilCardByCardNo(cardNo);
        if (oilCard == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到油卡");
        }
        oilCard.setContactName(contactName);
        oilCard.setContactPhone(contactPhone);
        editData(oilCard);
    }

    @Override
    public void disabled(String fleetCardNo) {
        // 查询油卡
        HighFleetOilCard oilCard = getFleetOilCardByCardNo(fleetCardNo);
        if (oilCard == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到油卡");
        }
        if (!oilCard.getStatus().equals(FleetOilCardStatusEnum.status1.getStatus())) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "油卡状态错误");
        }
        oilCard.setStatus(FleetOilCardStatusEnum.status2.getStatus());
        editData(oilCard);
    }

    @Override
    public void enable(String fleetCardNo) {
        // 查询油卡
        HighFleetOilCard oilCard = getFleetOilCardByCardNo(fleetCardNo);
        if (oilCard == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到油卡");
        }
        if (!oilCard.getStatus().equals(FleetOilCardStatusEnum.status2.getStatus())) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "油卡状态错误");
        }
        oilCard.setStatus(FleetOilCardStatusEnum.status1.getStatus());
        editData(oilCard);
    }

    @Override
    public List<HighFleetOilCard> getFleetOilCardList(Map<String, Object> param) {
        HighFleetOilCardExample example = new HighFleetOilCardExample();
        HighFleetOilCardExample.Criteria criteria = example.createCriteria().andStatusNotEqualTo(0);

        if (MapUtils.getLong(param, "companyId") != null) {
            criteria.andCompanyIdEqualTo(MapUtils.getLong(param, "companyId"));
        }

        if (MapUtils.getLong(param, "orgId") != null) {
            criteria.andOrgIdEqualTo(MapUtils.getLong(param, "orgId"));
        }

        if (StringUtils.isNotBlank(MapUtils.getString(param, "cardNo"))) {
            criteria.andCardNoLike("%" + MapUtils.getString(param, "cardNo") + "%");
        }

        if (StringUtils.isNotBlank(MapUtils.getString(param, "contactName"))) {
            criteria.andContactNameLike("%" + MapUtils.getString(param, "contactName") + "%");
        }

        if (StringUtils.isNotBlank(MapUtils.getString(param, "contactPhone"))) {
            criteria.andContactPhoneLike("%" + MapUtils.getString(param, "contactPhone") + "%");
        }

        if (MapUtils.getLong(param, "createTimeS") != null) {
            criteria.andCreateTimeGreaterThanOrEqualTo(new Date(MapUtils.getLong(param, "createTimeS")));
        }

        if (MapUtils.getLong(param, "createTimeE") != null) {
            criteria.andCreateTimeLessThanOrEqualTo(new Date(MapUtils.getLong(param, "createTimeE")));
        }

        if (MapUtils.getInteger(param, "status") != null) {
            criteria.andStatusEqualTo(MapUtils.getInteger(param, "status"));
        }

        example.setOrderByClause("create_time desc");
        return fleetOilCardMapper.selectByExample(example);
    }

    @Override
    public List<OilCardOrderModel> getFleetOilCardOrderList(Map<String, Object> param) throws Exception {
        if (MapUtils.getLong(param, "payTimeS") != null) {
            param.put("payTimeS", DateUtil.date2String(new Date(MapUtils.getLong(param, "payTimeS")), "yyyy-MM-dd HH:mm:ss"));
        }

        if (MapUtils.getLong(param, "payTimeE") != null) {
            param.put("payTimeE", DateUtil.date2String(new Date(MapUtils.getLong(param, "payTimeE")), "yyyy-MM-dd HH:mm:ss"));
        }
        return fleetOilCardMapper.selectOilCardOrderList(param);
    }
}
