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.AESEncodeUtil;
import com.hai.common.security.UserCenter;
import com.hai.common.utils.BankNumberUtil;
import com.hai.common.utils.DateUtil;
import com.hai.dao.HighOilCardMapper;
import com.hai.entity.*;
import com.hai.enum_type.*;
import com.hai.model.OilCardOrderModel;
import com.hai.model.UserInfoModel;
import com.hai.service.*;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

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

@Service("oilCardService")
public class HighOilCardServiceImpl implements HighOilCardService {

    @Resource
    private HighOilCardMapper oilCardMapper;

    @Resource
    private HighOilCardContactRecordService oilCardContactRecordService;

    @Resource
    private HighOilCardRecordService oilCardRecordService;

    @Resource
    private BsOrganizationService organizationService;

    @Resource
    private BsCompanyService companyService;

    @Resource
    private HighCompanyAccountService companyAccountService;

    @Resource
    private UserCenter userCenter;

    @Resource
    private HighUserCardService userCardService;

    @Resource
    private HighUserService userService;

    @Resource
    private HighOrderService orderService;

    @Override
    public void editData(HighOilCard oilCard) {
        if (oilCard.getId() == null) {
            oilCard.setCreateTime(new Date());
            oilCard.setUpdateTime(new Date());
            oilCard.setStatus(OilCardStatusEnum.status1.getStatus());
            oilCard.setBindStatus(OilCardBindStatusEnum.status0.getStatus());
            oilCardMapper.insert(oilCard);
        } else {
            oilCard.setUpdateTime(new Date());
            oilCardMapper.updateByPrimaryKey(oilCard);
        }
    }

    @Override
    @Transactional(rollbackFor=Exception.class,isolation = Isolation.SERIALIZABLE,propagation= Propagation.REQUIRES_NEW)
    public synchronized void recharge(String cardNo, BigDecimal price, Long orgId) {
        HighOilCard oilCard = getOilCardByCardNo(cardNo);
        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, "油卡不处于正常状态");
        }
        // 账户扣款
        Map<String, Object> consumeType = new HashMap<>();
        consumeType.put("sourceType", CompanyAmountSourceTypeEnum.type2.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();

        HighOilCardRecord record = new HighOilCardRecord();
        record.setOilCardId(oilCard.getId());
        record.setCardNo(oilCard.getCardNo());
        record.setType(OilCardRecordTypeEnum.type1.getType());
        record.setAmount(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.getAmount());
        oilCardRecordService.insertRecord(record);
    }

    @Override
    @Transactional(rollbackFor=Exception.class,isolation = Isolation.SERIALIZABLE,propagation= Propagation.REQUIRES_NEW)
    public synchronized void recycleAmount(String cardNo) {
        HighOilCard oilCard = getOilCardByCardNo(cardNo);
        if (oilCard == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "油卡卡号错误");
        }
        if (oilCard.getAmount().compareTo(new BigDecimal("0.01")) == -1) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "油卡余额低于￥0.01，无需回收");
        }
        // 账户进账
        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();

        HighOilCardRecord record = new HighOilCardRecord();
        record.setOilCardId(oilCard.getId());
        record.setCardNo(oilCard.getCardNo());
        record.setType(OilCardRecordTypeEnum.type2.getType());
        record.setAmount(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);
        oilCardRecordService.insertRecord(record);
    }

    @Override
    public void consume(String cardNo, BigDecimal amount, Map<String, Object> otherParam) {
        // 油卡
        HighOilCard card = getOilCardByCardNo(cardNo);
        if (card == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知的卡号");
        }
        if (!card.getStatus().equals(OilCardStatusEnum.status1.getStatus())) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "油卡状态异常，暂无法消费");
        }
        // 油卡余额 是否小于 消费余额
        if (card.getAmount().compareTo(amount) == -1) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "油卡余额不足");
        }
        // 变更前金额
        BigDecimal beforeAmount = card.getAmount();
        // 计算消费后金额
        card.setAmount(card.getAmount().subtract(amount));
        // 累积消费金额
        card.setAmountConsume(card.getAmountConsume().add(amount));
        editData(card);
        // 变更后金额
        BigDecimal afterAmount = card.getAmount();

        HighOilCardRecord record = new HighOilCardRecord();
        record.setOilCardId(card.getId());
        record.setCardNo(card.getCardNo());
        record.setType(OilCardRecordTypeEnum.type2.getType());
        record.setAmount(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"));
        oilCardRecordService.insertRecord(record);
    }

    @Override
    @Transactional(rollbackFor=Exception.class,isolation = Isolation.SERIALIZABLE,propagation= Propagation.REQUIRES_NEW)
    public void refund(String orderNo) {
        HighOrder order = orderService.getOrderByOrderNo(orderNo);
        if (order == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知的的订单");
        }
        if (!order.getPayType().equals(OrderPayTypeEnum.type7.getType())) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "支付方式，不是油卡");
        }
        if (StringUtils.isBlank(order.getMemCardNo())) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知的油卡卡号");
        }
        // 查询油卡卡号
        HighOilCard oilCard = getOilCardByCardNo(order.getMemCardNo());
        if (oilCard == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知的油卡卡号");
        }
        // 订单状态：1 待支付  2 已支付  3.已完成  4. 已退款  5.已取消   6.退款中   7.拒绝退款
        if (order.getOrderStatus() == 2 || order.getOrderStatus() == 3 || order.getOrderStatus() == 6 || order.getOrderStatus() == 7) {
            order.setOrderStatus(4);
            order.setRefundTime(new Date());
            order.setRefundPrice(order.getPayRealPrice());
            orderService.updateOrderDetail(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();

            HighOilCardRecord record = new HighOilCardRecord();
            record.setOilCardId(oilCard.getId());
            record.setCardNo(oilCard.getCardNo());
            record.setType(OilCardRecordTypeEnum.type1.getType());
            record.setAmount(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());
            oilCardRecordService.insertRecord(record);
            return;
        }
        throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "订单状态异常");
    }

    @Override
    @Transactional(propagation= Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    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());

        List<HighOilCard> oilCardList = new ArrayList<>();

        HighOilCard oilCard;
        for (int i = 0; i < generateNum; i++) {
            oilCard = new HighOilCard();
            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(OilCardStatusEnum.status1.getStatus());
            oilCard.setBindStatus(OilCardBindStatusEnum.status0.getStatus());
            oilCardList.add(oilCard);
        }
        oilCardMapper.insertList(oilCardList);
    }

    @Override
    @Transactional(propagation= Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void setContact(String cardNo, String contactName, String contactPhone) {
        // 查询油卡
        HighOilCard oilCard = getOilCardByCardNo(cardNo);
        if (oilCard == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到油卡");
        }
        // 查询手机号是否绑定油卡
        HighOilCard phone = getOilCardByPhone(contactPhone);
        if (phone != null && !phone.getId().equals(oilCard.getId())) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "联系电话已绑定其他油卡");
        }
        if (StringUtils.isBlank(oilCard.getContactPhone())) {
            oilCardContactRecordService.insert(oilCard.getId(), oilCard.getCardNo(), "新设置：联系人【"+contactName+"】，联系电话【"+contactPhone+"】");

            // 根据手机号查询 用户是否存在;存在：自动绑定油卡
            HighUser user = userService.findByPhone(contactPhone);
            if (user != null) {
                if (userCardService.getListByUser(user.getId(),UserCardType.type2.getType()).size() > 0) {
                    throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "联系电话已绑定其他油卡");
                }
                userCardService.bindCard(UserCardType.type2.getType(), oilCard.getCardNo(), user.getId());
                oilCard.setBindStatus(1);
                oilCard.setBindTime(new Date());
            }

        } else if (StringUtils.isNotBlank(oilCard.getContactPhone()) && !oilCard.getContactPhone().equals(contactPhone)) {
            // 绑定状态  0：未绑定   1：已绑定
            if (oilCard.getBindStatus().equals(1)) {
                oilCard.setBindTime(null);
                oilCard.setBindStatus(0);
                // 查询用户绑定油卡列表
                List<HighUserCard> userCardList = userCardService.getDetailByCardNo(oilCard.getCardNo());
                // 油卡解绑
                for (HighUserCard userCard : userCardList) {
                    userCard.setStatus(0);
                    userCardService.editCard(userCard);
                }
            }

            // 根据手机号查询 用户是否存在;存在：自动绑定油卡
            HighUser user = userService.findByPhone(contactPhone);
            if (user != null) {
                if (userCardService.getListByUser(user.getId(),UserCardType.type2.getType()).size() > 0) {
                    throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "联系电话已绑定其他油卡");
                }
                userCardService.bindCard(UserCardType.type2.getType(), oilCard.getCardNo(), user.getId());
                oilCard.setBindStatus(1);
                oilCard.setBindTime(new Date());
            }
            oilCardContactRecordService.insert(oilCard.getId(), oilCard.getCardNo(), "联系信息变更：原联系人【"+oilCard.getContactName()+"】，联系电话【"+oilCard.getContactPhone()+"】。" +
                    "变跟后联系人【"+contactName+ "】，联系电话【"+contactPhone+"】");
        }
        oilCard.setContactName(contactName);
        oilCard.setContactPhone(contactPhone);
        editData(oilCard);
    }

    @Override
    public void disabled(String cardNo) {
        // 查询油卡
        HighOilCard oilCard = getOilCardByCardNo(cardNo);
        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, "油卡状态错误");
        }
        oilCard.setStatus(OilCardStatusEnum.status2.getStatus());
        editData(oilCard);

        oilCardContactRecordService.insert(oilCard.getId(), oilCard.getCardNo(), "禁用油卡");
    }

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

        oilCardContactRecordService.insert(oilCard.getId(), oilCard.getCardNo(),  "启用油卡");
    }

    @Override
    public HighOilCard getOilCardByPhone(String phone) {
        HighOilCardExample example = new HighOilCardExample();
        example.createCriteria().andStatusNotEqualTo(0).andContactPhoneEqualTo(phone);
        List<HighOilCard> list = oilCardMapper.selectByExample(example);
        if (list.size() > 0) {
            return list.get(0);
        }
        return null;
    }

    @Override
    public HighOilCard getOilCardByCardNo(String cardNo) {
        HighOilCardExample example = new HighOilCardExample();
        example.createCriteria().andStatusNotEqualTo(0).andCardNoEqualTo(cardNo);
        List<HighOilCard> list = oilCardMapper.selectByExample(example);
        if (list.size() > 0) {
            return list.get(0);
        }
        return null;
    }

    @Override
    public List<HighOilCard> getOilCardList(Map<String, Object> param) {
        HighOilCardExample example = new HighOilCardExample();
        HighOilCardExample.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.getLong(param, "bindTimeS") != null) {
            criteria.andBindTimeGreaterThanOrEqualTo(new Date(MapUtils.getLong(param, "bindTimeS")));
        }

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

        if (MapUtils.getBoolean(param, "isConfigContact") != null) {
            if (MapUtils.getBoolean(param, "isConfigContact") == true) {
                criteria.andContactPhoneIsNotNull();
            }
            if (MapUtils.getBoolean(param, "isConfigContact") == false) {
                criteria.andContactPhoneIsNull();
            }
        }

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

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

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

    @Override
    public List<OilCardOrderModel> getOilCardOrderList(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 oilCardMapper.selectOilCardOrderList(param);
    }
}
