package com.iformall.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.iformall.common.ErrorCode;
import com.iformall.common.ResultData;
import com.iformall.domain.po.*;
import com.iformall.domain.vo.WxBillAll;
import com.iformall.enums.*;
import com.iformall.exception.MallinkException;
import com.iformall.mapper.*;
import com.iformall.service.*;
import com.iformall.utils.Constant;
import com.iformall.utils.DateUtils;
import org.apache.commons.io.FileUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

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

    @Autowired
    WxBillAllMapper wxBillAllMapper;

    @Autowired
    WxBillDailyService wxBillDailyService;

    @Autowired
    WxBillDepositService wxBillDepositService;

    @Autowired
    WxBillPropertyDepositService wxBillPropertyDepositService;

    @Autowired
    WxBillPropertyService wxBillPropertyService;

    @Autowired
    WxBillRentService wxBillRentService;

    @Autowired
    WxBillOtherService wxBillOtherService;

    @Autowired
    WxBillOtherDepositService wxBillOtherDepositService;

    @Autowired
    WxBillDailyMapper wxBillDailyMapper;

    @Autowired
    WxBillDepositMapper wxBillDepositMapper;

    @Autowired
    WxBillPropertyDepositMapper wxBillPropertyDepositMapper;

    @Autowired
    WxBillPropertyMapper wxBillPropertyMapper;

    @Autowired
    WxBillRentMapper wxBillRentMapper;

    @Autowired
    WxBillOtherMapper wxBillOtherMapper;

    @Autowired
    WxBillOtherDepositMapper wxBillOtherDepositMapper;

    @Override
    public Map<String, Object> listAsPage(WxBillAll record, Integer pageIndex, Integer pageSize) {
        //更新各账单状态
        updateBillStatus(record);
        PageHelper.startPage(pageIndex, pageSize);
        List<Map<String, Object>> billList = wxBillAllMapper.list(record);
        PageInfo<Map<String, Object>> pageInfo = new PageInfo<>(billList);
        Map<String, Object> result = new HashMap<>();
        result.put("pageInfo", pageInfo);
        return result;
    }

    @Override
    public List<Map<String, Object>> listBillOweAndWaitPay(WxBillAll wxBillAll) {
        //更新各账单状态
        updateBillStatus(wxBillAll);
        ArrayList<Integer> statusList = new ArrayList<>();
        statusList.add(EnumBillRentStatus.NOT_PAID.getCode());
        statusList.add(EnumBillRentStatus.WAIT_PAY.getCode());
        wxBillAll.setStatusList(statusList);
        return wxBillAllMapper.listData(wxBillAll);
    }

    @Override
    public ResultData listBill(WxBillAll wxBillAll) {
        //更新各账单状态
        updateBillStatus(wxBillAll);
        //账单类型
        if (wxBillAll.getBillTypeValue() != null) {
            if (wxBillAll.getBillTypeValue().equals(EnumBillType.RENT.getCode())) {
                wxBillAll.setBillTypeValue(EnumBillTypeParam.RENT.getCode());
            } else if (wxBillAll.getBillTypeValue().equals(EnumBillType.DEPOSIT.getCode())) {
                wxBillAll.setBillTypeValue(null);
                ArrayList typeList = new ArrayList();
                typeList.add(EnumBillTypeParam.RENT_DEPOSIT.getCode());
                typeList.add(EnumBillTypeParam.PROPERTY_DEPOSIT.getCode());
                typeList.add(EnumBillTypeParam.ATHER_DEPOSIT.getCode());
                wxBillAll.setTypeList(typeList);
            } else if (wxBillAll.getBillTypeValue().equals(EnumBillType.PROPERTY.getCode())) {
                wxBillAll.setBillTypeValue(EnumBillTypeParam.PROPERTY.getCode());
            } else if (wxBillAll.getBillTypeValue().equals(EnumBillType.WATER.getCode())) {
                wxBillAll.setBillTypeValue(EnumBillTypeParam.WATER.getCode());
            } else if (wxBillAll.getBillTypeValue().equals(EnumBillType.POWER.getCode())) {
                wxBillAll.setBillTypeValue(EnumBillTypeParam.POWER.getCode());
            } else if (wxBillAll.getBillTypeValue().equals(EnumBillType.ROUTINE.getCode())) {
                wxBillAll.setBillTypeValue(EnumBillTypeParam.ROUTINE.getCode());
            } else {
                logger.info("账单不存在");
                return new ResultData(ErrorCode.BILL_ROUTINE_IS_NOT_FOUND);
            }
        }
        if (wxBillAll.getPageIndex() != null && wxBillAll.getPageIndex() != null) {
            PageHelper.startPage(wxBillAll.getPageIndex(), wxBillAll.getPageSize());
            List<Map<String, Object>> maps = wxBillAllMapper.listData(wxBillAll);
            PageInfo<Map<String, Object>> pageInfo = new PageInfo<>(maps);
            return new ResultData(pageInfo);
        }
        List<Map<String, Object>> maps = wxBillAllMapper.listData(wxBillAll);
        return new ResultData(maps);
    }

    @Override
    public void updateBill(Map<String, Object> bill) {

        int billTypeValue = ((Long) bill.get("billTypeValue")).intValue();
        if (billTypeValue==EnumBillTypeParam.RENT.getCode().intValue()) {
            //更新租金账单
            WxBillRent billRent = wxBillRentMapper.selectByPrimaryKey(bill.get("id"));
            if(billRent!=null && !billRent.getStatus().equals(EnumBillRentStatus.PAID.getCode())){
                updateBillRent(bill);
            }
        } else if (billTypeValue==EnumBillTypeParam.RENT_DEPOSIT.getCode().intValue()) {
            //更新租金押金账单
            WxBillDeposit billDeposit = wxBillDepositMapper.selectByPrimaryKey(bill.get("id"));
            if(billDeposit!=null && !billDeposit.getStatus().equals(EnumBillRentStatus.PAID.getCode())){
                updateBillRentDeposit(bill);
            }
        } else if (billTypeValue==EnumBillTypeParam.PROPERTY.getCode().intValue()) {
            //更新物业账单
            WxBillProperty property = wxBillPropertyMapper.selectByPrimaryKey(bill.get("id"));
            if(property!=null && !property.getStatus().equals(EnumBillRentStatus.PAID.getCode())){
                updateBillProperty(bill);
            }
        } else if (billTypeValue==EnumBillTypeParam.PROPERTY_DEPOSIT.getCode().intValue()) {
            //更新物业押金账单
            WxBillPropertyDeposit wxBillPropertyDeposit = wxBillPropertyDepositMapper.selectByPrimaryKey(bill.get("id"));
            if(wxBillPropertyDeposit!=null && !wxBillPropertyDeposit.getStatus().equals(EnumBillRentStatus.PAID.getCode())){
                updateBillPropertyDeposit(bill);
            }
        } else if (billTypeValue==EnumBillTypeParam.WATER.getCode().intValue()) {
            //更新水费账单
            WxBillDaily wxBillDaily = wxBillDailyMapper.selectByPrimaryKey(bill.get("id"));
            if(wxBillDaily!=null && !wxBillDaily.getStatus().equals(EnumBillRentStatus.PAID.getCode())){
                updateBillDaily(bill);
            }
        } else if (billTypeValue==EnumBillTypeParam.POWER.getCode().intValue()) {
            //更新电费账单
            WxBillDaily wxBillDaily = wxBillDailyMapper.selectByPrimaryKey(bill.get("id"));
            if(wxBillDaily!=null && !wxBillDaily.getStatus().equals(EnumBillRentStatus.PAID.getCode())){
                updateBillDaily(bill);
            }
        } else if (billTypeValue==EnumBillTypeParam.ROUTINE.getCode().intValue()) {
            //更新其他账单
            WxBillOther wxBillOther = wxBillOtherMapper.selectByPrimaryKey(bill.get("id"));
            if(wxBillOther!=null && !wxBillOther.getStatus().equals(EnumBillRentStatus.PAID.getCode())){
                updateBillOther(bill);
            }
        } else {
            logger.info("账单类型不存在");
        }
    }

    @Override
    public void exportBill(HttpServletRequest request, HttpServletResponse response, WxBillAll wxBillAll) {
        //得到当前月
        //String month = DateUtils.getSystemTime("yyyy-MM");
        //设置查询参数-当前月
        //wxBillAll.setMonth(month);
        //查询
        Map<Object, List<Map<String, Object>>> billMapList = wxBillAllMapper.list(wxBillAll).parallelStream().collect(Collectors.groupingBy(x -> {
            return x.get("merchantId");
        }));
        XSSFWorkbook workbook;
        String filepath = Constant.fileDirectory;
        File savefile = new File(filepath);
        if (!savefile.exists()) {
            savefile.mkdirs();
        }
        String filename = UUID.randomUUID() + ".xlsx";
        filepath = filepath + filename;

        try {
            File file = new File(filepath);
            workbook = new XSSFWorkbook();
            int count=1;
            Set<Map.Entry<Object, List<Map<String, Object>>>> entries = billMapList.entrySet();
            for(Map.Entry<Object, List<Map<String, Object>>> entry:entries){
                List<Map<String, Object>> billList = entry.getValue();
                Map<String, Object> billInfo = billList.get(0);
                String merchantName = billInfo.get("merchantName").toString();
                XSSFSheet sheet = workbook.createSheet(merchantName+"-"+count++);
                Row row = sheet.createRow(0);
                Cell shopNumberCell = row.createCell(0);
                Cell merchantNameCell = row.createCell(1);
                Cell shopTypeCell = row.createCell(2);
                Cell billNameCell = row.createCell(3);
                Cell receivePayCell = row.createCell(4);
                Cell payCell = row.createCell(5);
                Cell oweCell = row.createCell(6);
                Cell receiveDateCell = row.createCell(7);
                Cell expiredDayCell = row.createCell(8);
                Cell statusCell = row.createCell(9);

                shopNumberCell.setCellValue("商铺号");
                merchantNameCell.setCellValue("商户名称");
                shopTypeCell.setCellValue("商铺类型");
                billNameCell.setCellValue("费用类型");
                receivePayCell.setCellValue("实际应收金额(元)");
                payCell.setCellValue("实收金额(元)");
                oweCell.setCellValue("欠缴金额(元)");
                receiveDateCell.setCellValue("缴款截止日期");
                expiredDayCell.setCellValue("逾期天数");
                statusCell.setCellValue("账单状态");

                for (int i = 0,size=billList.size(); i < size; i++) {
                    row = sheet.createRow(i + 1);
                    shopNumberCell = row.createCell(0);
                    merchantNameCell = row.createCell(1);
                    shopTypeCell = row.createCell(2);
                    billNameCell = row.createCell(3);
                    receivePayCell = row.createCell(4);
                    payCell = row.createCell(5);
                    oweCell = row.createCell(6);
                    receiveDateCell = row.createCell(7);
                    expiredDayCell = row.createCell(8);
                    statusCell = row.createCell(9);
                    Map<String, Object> billMap = billList.get(i);
                    logger.info(billMap.toString());
                    shopNumberCell.setCellValue(billMap.get("shopNumber").toString());
                    merchantNameCell.setCellValue(billMap.get("merchantName").toString());
                    shopTypeCell.setCellValue(EnumRentShopType.getEnum((Integer) billMap.get("rentShopType")).getMessage());
                    billNameCell.setCellValue(billMap.get("name").toString());
                    BigDecimal needPay = new BigDecimal(billMap.get("pay").toString()).divide(new BigDecimal(100));
                    payCell.setCellValue(needPay.toString());
                    BigDecimal receivePay = new BigDecimal(billMap.get("receivePay").toString()).divide(new BigDecimal(100));
                    receivePayCell.setCellValue(receivePay.toString());
                    BigDecimal owe = new BigDecimal(billMap.get("owe").toString()).divide(new BigDecimal(100));
                    oweCell.setCellValue(owe.toString());
                    String receiveDate = DateUtils.date2String((Date) billMap.get("receiveDate"), "yyyy-MM-dd");
                    receiveDateCell.setCellValue(receiveDate);
                    expiredDayCell.setCellValue(billMap.get("expiredDay").toString());
                    statusCell.setCellValue(EnumBillRentStatus.getEnum((Integer) billMap.get("status")).getMessage());
                }
                row = sheet.createRow(billList.size()+1);
                Cell managerInfoCell = row.createCell(0);
                Cell managerCell = row.createCell(1);
                Cell managerPhoneCell = row.createCell(2);
                managerInfoCell.setCellValue("负责人信息:");
                managerCell.setCellValue(billInfo.get("manager")==null?"":billInfo.get("manager").toString());
                managerPhoneCell.setCellValue(billInfo.get("managerPhone")==null?"":billInfo.get("managerPhone").toString());

            }

            FileOutputStream fileOut = new FileOutputStream(file);
            workbook.write(fileOut);
            fileOut.close();
            workbook.close();
            downFile(filepath, filename, "账单数据.xlsx",response, request);
            FileUtils.forceDelete(file);
        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    public void downFile(String filePath, String filename, String exportFileName,HttpServletResponse response,
                         HttpServletRequest req) throws IOException {
        try {
            response.reset();
            response.setContentType("bin");
            String agent = req.getHeader("user-agent");
            if (agent.contains("Firefox")) {
                response.setHeader("Content-disposition",
                        "attachment; filename="
                                + new String(exportFileName.getBytes("GB2312"),
                                "ISO-8859-1"));
            } else {
                response
                        .setHeader("Content-disposition",
                                "attachment; filename="
                                        + java.net.URLEncoder.encode(exportFileName,
                                        "UTF-8"));
            }
            // 循环取出流中的数据
            byte[] b = new byte[1024];
            int len;
            InputStream inStream = new FileInputStream(filePath);
            while ((len = inStream.read(b)) > 0)
                response.getOutputStream().write(b, 0, len);
            inStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private int updateBillOther(Map<String, Object> bill) {
        logger.info("updateBillOther params:"+bill.toString());
        Object id = bill.get("id");
        WxBillOther wxBillOther = wxBillOtherMapper.selectByPrimaryKey(id);
        if(wxBillOther==null){
            return 0;
        }
        Date date = new Date();
        wxBillOther.setPayDate(date);
        Integer owe = (Integer) bill.get("owe");
        wxBillOther.setPay(wxBillOther.getPay()+owe);
        wxBillOther.setOwe(0);
        wxBillOther.setStatus(EnumBillDailyStatus.PAID.getCode());
        wxBillOther.setUpdatetime(date);
        try {
            return wxBillOtherMapper.updateByPrimaryKeySelective(wxBillOther);
        } catch (Exception e) {
            logger.error("更新其他账单失败,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
    }

    private int updateBillDaily(Map<String, Object> bill) {
        logger.info("updateBillDaily params:"+bill.toString());
        Object id = bill.get("id");
        WxBillDaily wxBillDaily = wxBillDailyMapper.selectByPrimaryKey(id);
        if(wxBillDaily==null){
            return 0;
        }
        Date date = new Date();
        wxBillDaily.setPayDate(date);
        Integer owe = (Integer) bill.get("owe");
        wxBillDaily.setPay(wxBillDaily.getPay()+owe);
        wxBillDaily.setOwe(0);
        wxBillDaily.setStatus(EnumBillDailyStatus.PAID.getCode());
        wxBillDaily.setUpdatetime(date);
        try {
            return wxBillDailyMapper.updateByPrimaryKeySelective(wxBillDaily);
        } catch (Exception e) {
            logger.error("更新日常账单失败,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
    }

    private int updateBillPropertyDeposit(Map<String, Object> bill) {
        logger.info("updateBillPropertyDeposit params:"+bill.toString());
        Object id = bill.get("id");
        WxBillPropertyDeposit wxBillPropertyDeposit = wxBillPropertyDepositMapper.selectByPrimaryKey(id);
        if(wxBillPropertyDeposit==null){
            return 0;
        }
        Date date = new Date();
        wxBillPropertyDeposit.setPayDate(date);
        Integer owe = (Integer) bill.get("owe");
        wxBillPropertyDeposit.setPay(wxBillPropertyDeposit.getPay()+owe);
        wxBillPropertyDeposit.setOwe(0);
        wxBillPropertyDeposit.setStatus(EnumBillDailyStatus.PAID.getCode());
        wxBillPropertyDeposit.setUpdatetime(date);
        try {
            return wxBillPropertyDepositMapper.updateByPrimaryKeySelective(wxBillPropertyDeposit);
        } catch (Exception e) {
            logger.error("更新物业押金账单失败,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
    }

    private int updateBillProperty(Map<String, Object> bill) {
        logger.info("updateBillProperty params:"+bill.toString());
        Object id = bill.get("id");
        WxBillProperty property = wxBillPropertyMapper.selectByPrimaryKey(id);
        if(property==null){
            return 0;
        }
        Date date = new Date();
        property.setPayDate(date);
        Integer owe = (Integer) bill.get("owe");
        property.setPay(property.getPay()+owe);
        property.setOwe(0);
        property.setStatus(EnumBillDailyStatus.PAID.getCode());
        property.setUpdatetime(date);
        try {
            return wxBillPropertyMapper.updateByPrimaryKeySelective(property);
        } catch (Exception e) {
            logger.error("更新物业账单失败,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
    }

    private int updateBillRentDeposit(Map<String, Object> bill) {
        logger.info("updateBillRentDeposit params:"+bill.toString());
        Object id = bill.get("id");
        WxBillDeposit wxBillDeposit = wxBillDepositMapper.selectByPrimaryKey(id);
        if(wxBillDeposit==null){
            return 0;
        }
        Date date = new Date();
        wxBillDeposit.setPayDate(date);
        Integer owe = (Integer) bill.get("owe");
        wxBillDeposit.setPay(wxBillDeposit.getPay()+owe);
        wxBillDeposit.setOwe(0);
        wxBillDeposit.setStatus(EnumBillDailyStatus.PAID.getCode());
        wxBillDeposit.setUpdatetime(date);
        try {
            return wxBillDepositMapper.updateByPrimaryKeySelective(wxBillDeposit);
        } catch (Exception e) {
            logger.error("更新租赁押金账单失败,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
    }

    private int updateBillRent(Map<String, Object> bill) {
        logger.info("updateBillRentDeposit params:"+bill.toString());
        Object id = bill.get("id");
        WxBillRent wxBillRent = wxBillRentMapper.selectByPrimaryKey(id);
        if(wxBillRent==null){
            return 0;
        }
        Date date = new Date();
        wxBillRent.setPayDate(date);
        Integer owe = (Integer) bill.get("owe");
        wxBillRent.setPay(wxBillRent.getPay()+owe);
        wxBillRent.setOwe(0);
        wxBillRent.setStatus(EnumBillDailyStatus.PAID.getCode());
        wxBillRent.setUpdatetime(date);
        try {
            return wxBillRentMapper.updateByPrimaryKeySelective(wxBillRent);
        } catch (Exception e) {
            logger.error("更新租金账单失败,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
    }


    private void updateBillStatus(WxBillAll record) {
        logger.info("更新各账单状态开始");
        //更新其他押金账单
        //WxBillOtherDeposit wxBillOtherDeposit = new WxBillOtherDeposit();
        //wxBillOtherDeposit.setTenantId(record.getTenantId());
        //wxBillOtherDepositService.updateBillStatus(wxBillOtherDeposit);
        //更新其他账单
        WxBillOther wxBillOther = new WxBillOther();
        wxBillOther.setTenantId(record.getTenantId());
        wxBillOtherService.updateBillStatus(wxBillOther);
        //更新日常账单状态
        WxBillDaily wxBillDaily = new WxBillDaily();
        wxBillDaily.setTenantId(record.getTenantId());
        wxBillDailyService.updateBillStatus(wxBillDaily);
        //更新租赁押金账单状态
        //WxBillDeposit wxBillDeposit = new WxBillDeposit();
        //wxBillDeposit.setTenantId(record.getTenantId());
        //wxBillDepositService.updateBillStatus(wxBillDeposit);
        //更新物业押金账单状态
        //WxBillPropertyDeposit wxBillPropertyDeposit = new WxBillPropertyDeposit();
        //wxBillPropertyDeposit.setTenantId(record.getTenantId());
        //wxBillPropertyDepositService.updateBillStatus(wxBillPropertyDeposit);
        //更新物业账单状态
        WxBillProperty wxBillProperty = new WxBillProperty();
        wxBillProperty.setTenantId(record.getTenantId());
        wxBillPropertyService.updateBillStatus(wxBillProperty);
        //更新租赁账单状态
        WxBillRent wxBillRent = new WxBillRent();
        wxBillRent.setTenantId(record.getTenantId());
        wxBillRentService.updateBillStatus(wxBillRent);
        logger.info("更新各账单状态结束");
    }

    @Override
    public Object getBillInfo(WxBillAll record) {

        record.setRentShopType(EnumRentShopType.SHOP.getCode());
        record.setStatus(EnumBillRentStatus.NOT_PAID.getCode());
        Map<String, Object> oweInfoForShop = wxBillAllMapper.queryOweInfo(record);
        record.setStatus(EnumBillRentStatus.PAID.getCode());
        Map<String, Object> paidInfoForShop = wxBillAllMapper.queryPaidInfo(record);

        record.setRentShopType(EnumRentShopType.POINT.getCode());
        record.setStatus(EnumBillRentStatus.NOT_PAID.getCode());
        Map<String, Object> oweInfoForPoint = wxBillAllMapper.queryOweInfo(record);
        record.setStatus(EnumBillRentStatus.PAID.getCode());
        Map<String, Object> paidInfoForPoint = wxBillAllMapper.queryPaidInfo(record);

        Map<String, Object> result = new HashMap<>(4);
        result.put("oweInfoForShop", oweInfoForShop);
        result.put("paidInfoForShop", paidInfoForShop);
        result.put("oweInfoForPoint", oweInfoForPoint);
        result.put("paidInfoForPoint", paidInfoForPoint);
        return result;
    }

    @Override
    public Long hasOweBill(Long contractId, Integer type) {
        if(type.intValue() == 1){
            return  wxBillRentMapper.oweBillCount(contractId);
        }else if(type.intValue() == 2){
            return  wxBillPropertyMapper.oweBillCount(contractId);
        }
        return 0l;
    }
}
