package com.iformall.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.iformall.common.ErrorCode;
import com.iformall.common.IdWorker;
import com.iformall.common.Result;
import com.iformall.common.ResultData;
import com.iformall.domain.po.*;
import com.iformall.domain.vo.WxBillDailyExportVo;
import com.iformall.domain.vo.WxBillDailyVo;
import com.iformall.enums.*;
import com.iformall.exception.MallinkException;
import com.iformall.mapper.WxBillDailyMapper;
import com.iformall.mapper.WxMerchantShopMapper;
import com.iformall.mapper.WxShopMapper;
import com.iformall.service.ExcelService;
import com.iformall.service.WxBillActionService;
import com.iformall.service.WxBillDailyService;
import com.iformall.service.WxPayAccountBillService;
import com.iformall.utils.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author gongbiao
 */
@Service
public class WxBillDailyServiceImpl implements WxBillDailyService {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    WxBillDailyMapper wxBillDailyMapper;

    @Autowired
    WxShopMapper wxShopMapper;
    @Autowired
    WxBillActionService wxBillActionService;
    @Autowired
    ExcelService excelService;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    WxMerchantShopMapper wxMerchantShopMapper;
    @Autowired
    WxPayAccountBillService wxPayAccountBillService;

    @Override
    public PageInfo<WxBillDaily> listAsPage(WxBillDaily record, Integer pageIndex, Integer pageSize) {
        WxPayAccountBill wxPayAccountBill = wxPayAccountBillService.getByTenantId(record.getTenantId());
        //分页对象设置页数和条数
        PageHelper.startPage(pageIndex, pageSize);
        //查询
        List<WxBillDaily> billDepositList = wxBillDailyMapper.queryBillDailyList(record);
        billDepositList.stream().forEach(e->{
            //手续费 = 合同应收+手续费+滞纳金
            computeTotalMoney(wxPayAccountBill, e);
        });
        //结果放入分页对象
        PageInfo<WxBillDaily> pageInfo = new PageInfo<>(billDepositList);
        return pageInfo;
    }

    public void computeTotalMoney(WxPayAccountBill wxPayAccountBill, WxBillDaily e) {
        if (e.getReceivePay() != null) {
            BigDecimal servicePay;
            if (e.getServiceChargePay() != null) {
                servicePay = new BigDecimal(e.getServiceChargePay());
            } else {
                servicePay = new BigDecimal(e.getReceivePay()).multiply(new BigDecimal(wxPayAccountBill.getServiceChargeRate())).divide(new BigDecimal(10000), 2, BigDecimal.ROUND_HALF_UP);
            }
            Long realReceivePay = servicePay.longValue() + e.getReceivePay();
            e.setRealReceivePay(realReceivePay);
            e.setServiceChargePay(servicePay.intValue());
        }
    }

    @Override
    public void updateBillStatus(WxBillDaily record) {
        logger.info("更新日常账单状态开始...");
        //更新逾期天数及状态
        updateNotPaidStatus(record);
        //更新待缴的状态
        updateWaidPayStatus(record);
        logger.info("更新日常账单状态结束...");
    }

    @Transactional(rollbackFor = {Exception.class})
    public void updateWaidPayStatus(WxBillDaily record) {
        Map<String, Object> params = new HashMap<>();
        params.put("tenantId", record.getTenantId());
        params.put("waitPay", EnumBillDailyStatus.WAIT_PAY.getCode());
        params.put("paid", EnumBillRentStatus.PAID.getCode());
        try {
            wxBillDailyMapper.updateWaitPayStatus(params);
        } catch (Exception e) {
            logger.error("更新日常待缴账单状态失败,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
    }


    @Transactional(rollbackFor = {Exception.class})
    public void updateNotPaidStatus(WxBillDaily record) {
        Map<String, Object> params = new HashMap<>();
        params.put("tenantId", record.getTenantId());
        params.put("notPaid", EnumBillDailyStatus.NOT_PAID.getCode());
        params.put("paid", EnumBillRentStatus.PAID.getCode());
        try {
            wxBillDailyMapper.updateNotPaidStatus(params);
        } catch (Exception e) {
            logger.error("更新日常欠缴账单状态失败,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
    }

    @Override
    public WxBillDaily getById(Long id) {
        WxBillDaily record = new WxBillDaily();
        record.setId(id);
        WxBillDaily wxBillDaily = wxBillDailyMapper.queryBillDailyList(record).get(0);
        WxPayAccountBill wxPayAccountBill = wxPayAccountBillService.getByTenantId(record.getTenantId());
        computeTotalMoney(wxPayAccountBill, record);
        record.setOwe(record.getRealReceivePay() - record.getPay());
        if (wxBillDaily.getShopId() != null) {
            WxShop shop = new WxShop();
            shop.setId(wxBillDaily.getShopId());
            List<Map<String, Object>> shoplist = wxShopMapper.findListMap(shop);
            wxBillDaily.setShops(shoplist);
        }else{
            wxBillDaily.setShops(Collections.EMPTY_LIST);
        }
        return wxBillDaily;
    }

    @Override
    public ResultData saveOrUpdate(WxBillDaily record, MallUserInfo user) {
        int receivepay = record.getReceivePay()==null?0:record.getReceivePay().intValue();
        int pay = record.getPay()==null?0:record.getPay().intValue();
        if(pay>receivepay){
            return new ResultData(ErrorCode.BILL_PAY_ERROR.getCode(),"实收金额不能大于实际应收金额");
        }
        Date date = new Date();
        if (record.getId() == null) {
            logger.info("新增日常账单");
            WxBillDaily dailyQuery = new WxBillDaily();
            dailyQuery.setType(record.getType());
            dailyQuery.setTenantId(record.getTenantId());
            dailyQuery.setMerchantId(record.getMerchantId());
            dailyQuery.setReceiveDate(record.getReceiveDate());
            dailyQuery.setIsDel(EnumDelStatus.NOT_DEL.getCode());
            WxBillDaily daily = wxBillDailyMapper.selectOne(new QueryWrapper<>(dailyQuery));
            if (daily != null) {
                return new ResultData(ErrorCode.BILL_IS_FOUND);
            }
            final IdWorker idWorker = IdWorker.get();
            record.setId(idWorker.nextId());
            record.setStatus(record.getReceiveDate().after(date)?EnumBillDailyStatus.WAIT_PAY.getCode():EnumBillDailyStatus.NOT_PAID.getCode());
            record.setCreatetime(date);
            record.setUpdatetime(date);
            record.setExpiredDay(0L);
            record.setOwe(record.getReceivePay()-record.getPay());
            record.setIsDel(EnumDelStatus.NOT_DEL.getCode());
            try {
                wxBillDailyMapper.insert(record);
            } catch (Exception e) {
                logger.error("保存日常账单失败,e:" + e.getMessage());
                throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
            }
            return new ResultData(Result.SUCCESS, "保存日常账单成功");
        } else {
            logger.info("更新日常押金账单");
            WxBillDaily wxBillDaily = wxBillDailyMapper.selectById(record.getId());
            if(wxBillDaily==null){
                return new ResultData(ErrorCode.BILL_ROUTINE_IS_NOT_FOUND);
            }

            String price = "";
            String message = "";
            if(record.getServiceChargePayUpdate() != null){
                Double l = Double.valueOf(record.getServiceChargePayUpdate())*100;
                wxBillDaily.setServiceChargePay(l.intValue());
            }else{
                Long addpay = wxBillDaily.getPay();
                wxBillDaily.setPayDate(record.getPayDate());
                wxBillDaily.setPay(record.getPay());
                wxBillDaily.setReceivePay(record.getReceivePay());
                wxBillDaily.setOwe(record.getRealReceivePay() - record.getPay());
                if (record.getPay().equals(record.getReceivePay())) {
                    wxBillDaily.setStatus(EnumBillRentStatus.PAID.getCode());
                    Date payDate = record.getPayDate();
                    Date receiveDate = wxBillDaily.getReceiveDate();
                    wxBillDaily.setExpiredDay(0L);
                    if (payDate.after(receiveDate)) {
                        int expiredDay = DateUtils.daysBetween(receiveDate, payDate);
                        wxBillDaily.setExpiredDay((long) expiredDay);
                    }
                }
                wxBillDaily.setPayDate(record.getPayDate());
                wxBillDaily.setUpdatetime(date);
                wxBillDaily.setPayWay(record.getPayWay());
                wxBillDaily.setPriceDetail(record.getPriceDetail());
                message = EnumBillPayWay.getEnum(record.getPayWay()).getMessage();
                price = new BigDecimal(record.getPay() - addpay).divide(new BigDecimal(100)).toPlainString();
            }
            try {
                wxBillDailyMapper.updateById(wxBillDaily);
            } catch (Exception e) {
                logger.error("更新日常账单失败,e:" + e.getMessage());
                throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
            }
            //日志
            WxBillAction wxBillAction = new WxBillAction();
            wxBillAction.setBillId(wxBillDaily.getId());
            wxBillAction.setDetails(message + price + "元");
            if(record.getServiceChargePayUpdate() != null){
                wxBillAction.setAction(EnumBillAction.UPDATE_SERVICE_MONEY.getCode());
            }else{
                wxBillAction.setAction(EnumBillAction.OFFLINE_PAY.getCode());
            }
            wxBillAction.setUserId(user.getId());
            wxBillAction.setUserName(user.getName());
            wxBillAction.setPhone(user.getPhone());
            wxBillAction.setTenantId(wxBillDaily.getTenantId());
            wxBillAction.setPayDate(wxBillDaily.getPayDate());
            try {
                wxBillActionService.save(wxBillAction);
            } catch (Exception e) {
                logger.error("添加日常账单行为日志,e:" + e.getMessage());
                throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
            }
            return new ResultData(Result.SUCCESS, "更新日常账单成功");
        }
    }

    @Override
    public void deleteById(Long id) {
        wxBillDailyMapper.deleteById(id);
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public ResultData updatePaid(Long id) {
        WxBillDaily wxBillDaily = wxBillDailyMapper.selectById(id);
        if(wxBillDaily==null){
            return new ResultData(ErrorCode.BILL_ROUTINE_IS_NOT_FOUND);
        }
        wxBillDaily.setStatus(EnumBillDailyStatus.PAID.getCode());
        Date d =new Date();
        wxBillDaily.setPayDate(d);
        wxBillDaily.setUpdatetime(d);
        try {
            wxBillDailyMapper.updateById(wxBillDaily);
        } catch (Exception e) {
            logger.error("日常账单结单失败,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(),e.getMessage());
        }
        return new ResultData(Result.SUCCESS, "日常账单结单成功");
    }

    @Override
    public void exportTemplate(HttpServletRequest request, HttpServletResponse response, String tenantId) {
        List<WxBillDailyVo> list = new ArrayList<>();
        WxBillDailyVo v1 = new WxBillDailyVo();
        WxBillDailyVo v2 = new WxBillDailyVo();

        v1.setShopNumber("A0001");
        v1.setType(1);
        v1.setReceivePayStr("1");
        v1.setPayStr("0");
        v1.setReceiveDate(new Date());
        v1.setExpiredDay(0L);
        v1.setRentShopType(1);
        list.add(v1);

        v2.setShopNumber("A0002");
        v2.setType(2);
        v2.setReceivePayStr("1000");
        v2.setPayStr("0");
        v2.setReceiveDate(new Date());
        v2.setExpiredDay(0L);
        v2.setRentShopType(2);
        list.add(v2);

        excelService.exportExcel(list, null, "水电费模板", WxBillDailyVo.class, "水电费模板.xlsx", response, true);

    }

    @Override
    public void insertData(WxBillDailyVo billDaily, String importKey, MallUserInfo user) {

        Integer type = billDaily.getType();
        WxBillDaily wxBillDaily = new WxBillDaily();
        Long receivePay = billDaily.getReceivePay();
        wxBillDaily.setReceivePay(receivePay);
        Long pay = billDaily.getPay();
        wxBillDaily.setPay(pay);
        wxBillDaily.setOwe(receivePay - pay);
        wxBillDaily.setType(type);
        Date receiveDate = billDaily.getReceiveDate();
        wxBillDaily.setReceiveDate(receiveDate);
        Date date = new Date();
        if (pay > 0) {
            wxBillDaily.setPayDate(date);
        }
        int expiredDay = DateUtils.daysBetween(receiveDate, date);
        wxBillDaily.setExpiredDay(0L);
        if (expiredDay > 0) {
            wxBillDaily.setStatus(EnumBillRentStatus.NOT_PAID.getCode());
            wxBillDaily.setExpiredDay((long) expiredDay);
        } else {
            wxBillDaily.setStatus(EnumBillRentStatus.WAIT_PAY.getCode());
        }
        if (receivePay.equals(pay)) {
            wxBillDaily.setStatus(EnumBillRentStatus.PAID.getCode());
        }

        wxBillDaily.setUserId(user.getId());
        wxBillDaily.setShopId(billDaily.getShopId());
        wxBillDaily.setRentShopType(billDaily.getRentShopType());

        wxBillDaily.setPayWay(EnumBillPayWay.OTHER.getCode());
        wxBillDaily.setCreatetime(date);
        wxBillDaily.setUpdatetime(date);
        wxBillDaily.setIsDel(EnumDelStatus.NOT_DEL.getCode());
        //商户
        WxMerchantShop merchantShop = new WxMerchantShop();
        merchantShop.setShopId(billDaily.getShopId());
        merchantShop.setIsDel(EnumDelStatus.NOT_DEL.getCode());
        WxMerchantShop wxMerchantShop = wxMerchantShopMapper.selectOne(new QueryWrapper<>(merchantShop));
        wxBillDaily.setMerchantId(wxMerchantShop.getMerchantId());

        final IdWorker idWorker = IdWorker.get();
        wxBillDaily.setId(idWorker.nextId());
        wxBillDailyMapper.insert(wxBillDaily);

        //记数
        stringRedisTemplate.opsForHash().increment(importKey, "processCount", 1);
        stringRedisTemplate.expire(importKey, 10, TimeUnit.SECONDS);
    }

    @Override
    public void exportBill(HttpServletRequest request, HttpServletResponse response, WxBillDaily record) {
        WxPayAccountBill wxPayAccountBill = wxPayAccountBillService.getByTenantId(record.getTenantId());
        List<WxBillDaily> billDailyList = wxBillDailyMapper.queryBillDailyList(record);
        billDailyList.stream().forEach(e->{
            //手续费 = 合同应收+手续费+滞纳金
            computeTotalMoney(wxPayAccountBill, e);
        });
        List<WxBillDailyExportVo> datalist = new ArrayList<>();
        WxBillDailyExportVo wxBillDailyExportVo;
        for (int i = 0, size = billDailyList.size(); i < size; i++) {
            WxBillDaily b = billDailyList.get(i);
            wxBillDailyExportVo = new WxBillDailyExportVo();
            wxBillDailyExportVo.setShopNumber(b.getShopNumber());
            wxBillDailyExportVo.setMerchantName(b.getMerchantName());
            wxBillDailyExportVo.setReceivePay(b.getReceivePay());
            wxBillDailyExportVo.setPay(b.getPay());
            wxBillDailyExportVo.setOwe(b.getOwe());
            wxBillDailyExportVo.setReceiveDate(b.getReceiveDate());
            wxBillDailyExportVo.setPayDate(b.getPayDate());
            wxBillDailyExportVo.setExpiredDay(b.getExpiredDay());
            wxBillDailyExportVo.setStatus(b.getStatus());
            wxBillDailyExportVo.setType(b.getType());
            datalist.add(wxBillDailyExportVo);
        }
        excelService.exportExcel(datalist, null, "日常费用账单", WxBillDailyExportVo.class, "日常费用账单.xlsx", response, false);
    }

}
