package cn.com.countrygarden.bi.main.service.resident.impl;

import cn.com.countrygarden.bi.main.dao.resident.PaymentHistoryMapper;
import cn.com.countrygarden.bi.main.dao.resident.PaymentMapper;
import cn.com.countrygarden.bi.main.dao.resident.ResidentContractMapper;
import cn.com.countrygarden.bi.main.dao.twerp.hm.TbHsprCommunityMapper;
import cn.com.countrygarden.bi.main.exception.ServiceException;
import cn.com.countrygarden.bi.main.model.PageData;
import cn.com.countrygarden.bi.main.model.resident.*;
import cn.com.countrygarden.bi.main.model.twerp.ErpCommunity;
import cn.com.countrygarden.bi.main.model.twerp.hm.TbSysUser;
import cn.com.countrygarden.bi.main.service.resident.ResidentPaymentService;
import cn.com.countrygarden.bi.main.service.twerp.hm.TbSysUserService;
import cn.com.countrygarden.bi.main.util.DateUtil;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageRowBounds;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Condition;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

/**
 * Created by chenweijiang on 2017/11/13.
 */
@Service
@Transactional(readOnly = false)
@PropertySource("classpath:/application.properties")
public class ResidentPaymentServiceImpl implements ResidentPaymentService {

    @Autowired
    private Environment env;

    @Autowired
    private TbHsprCommunityMapper tbHsprCommunityMapper;

    @Autowired
    private PaymentMapper mapper;

    @Autowired
    private ResidentContractMapper contractMapper;
    @Autowired
    private PaymentHistoryMapper historyMapper;

    @Autowired
    private TbSysUserService tbSysUserService;

    @Override
    public void reCreatePayment(ResidentContract contract) {
        Condition condition = new Condition(Payment.class);
        condition.createCriteria().andEqualTo("contractId", contract.getId());
        mapper.deleteByCondition(condition);
        createPayment(contract);
    }

    @Override
    public void createPayment(ResidentContract contract) {
        if (ContractConstant.PaymentMethod.ONCE.equals(contract.getPaymentMethod())) {
            Date[] rang = new Date[2];
            rang[0] = contract.getStartDate();
            rang[1] = contract.getEndDate();
            createPaymentByTime(contract, rang);
        } else if (ContractConstant.PaymentMethod.MONTH.equals(contract.getPaymentMethod())) {
            Date[] rang = DateUtil.getMonthRang(contract.getStartDate(), contract.getEndDate());
            createPaymentByTime(contract, rang);
        } else if (ContractConstant.PaymentMethod.SEASION.equals(contract.getPaymentMethod())) {
            Date[] rang = DateUtil.getQuarterRang(contract.getStartDate(), contract.getEndDate());
            createPaymentByTime(contract, rang);
        } else {
            throw new ServiceException(String.format("收款%s方式不支持，请重新选择", contract.getPaymentMethod()));
        }
    }

    private void createPaymentByTime(ResidentContract contract, Date[] rang) {
        List<Payment> insertList = new ArrayList<Payment>();
        double fixedAmount = contract.getFixedAmount().setScale(2).doubleValue();
        double divide = fixedAmount / rang.length * 2;
        int count = 0;
        for (int i = 0; i < rang.length; i = i + 2) {
            BigDecimal paymentFixedAmount;
            if (rang.length - i <= 2) {
                paymentFixedAmount = BigDecimal.valueOf(fixedAmount - divide * count);
            } else {
                paymentFixedAmount = BigDecimal.valueOf(divide);
            }

            Payment payment = new Payment();
            payment.setContractId(contract.getId());
            payment.setStartDate(rang[i]);
            payment.setEndDate(rang[i + 1]);
            payment.setGmtCreate(new Date());
            payment.setCreatedBy(contract.getModifiedBy());
            payment.setGmtModified(new Date());
            payment.setModifiedBy(contract.getModifiedBy());
            payment.setStatus(ContractConstant.PaymentStatus.UNCHECK);
            payment.setFixAmount(paymentFixedAmount);
            insertList.add(payment);

            count += 1;
        }
        if (insertList.size() > 0) {
            mapper.insertList(insertList);
        }
    }


    @Override
    public int findPaidPayment(Integer contractId) {
        Condition condition = new Condition(Payment.class);
        condition.createCriteria().andEqualTo("contractId", contractId)
                .andIsNotNull("receivedTime");
        return mapper.selectCountByCondition(condition);
    }

    @Override
    public void invoice(Payment payment, String userCode) {
        Payment entity = mapper.selectByPrimaryKey(payment.getId());
        Condition updateCondiction = new Condition(Payment.class);
        updateCondiction.createCriteria().andEqualTo("id", entity.getId())
                .andEqualTo("gmtModified", entity.getGmtModified());

        if (!StringUtils.isEmpty(entity.getInvoiceNumber())) {
            throw new ServiceException("已开票，不能重复开票：" + entity.getInvoiceNumber());
        }
        if (entity.getReceivedTime() == null) {
            throw new ServiceException("未收费不能开票");
        }
        if (!ContractConstant.PaymentStatus.CHECKED.equals(entity.getStatus())) {
            throw new ServiceException("请先审核再开票");
        }
        entity.setAmount(payment.getAmount());
        entity.setAmountWithoutTax(payment.getAmountWithoutTax());
        entity.setValueAddedTax(payment.getValueAddedTax());
        entity.setInvoiceNumber(payment.getInvoiceNumber());
        entity.setInvoiceImg(payment.getInvoiceImg());
        entity.setGmtModified(new Date());
        entity.setModifiedBy(userCode);
        int updates = mapper.updateByCondition(entity, updateCondiction);
        if (updates == 0) {
            throw new ServiceException("开票失败，请重新再试");
        }

        String json = JSON.toJSONString(entity);
        PaymentHistory history = new PaymentHistory();
        history.setContent(json);
        history.setCreateBy(userCode);
        history.setPaymentId(entity.getId());
        history.setGmtCreate(new Date());
        historyMapper.insert(history);
    }

    @Override
    public void paid(Payment payment, String userCode) {
        Payment entity = mapper.selectByPrimaryKey(payment.getId());
        ResidentContract contract = contractMapper.selectByPrimaryKey(entity.getContractId());
        Condition updateCondiction = new Condition(Payment.class);
        updateCondiction.createCriteria().andEqualTo("id", entity.getId())
                .andEqualTo("gmtModified", entity.getGmtModified());
        if (!ContractConstant.EMPTY_FLOAT_AMOUNT.equals(contract.getFloatAmount()) &
                payment.getFloatAmount() == null) {
            throw new ServiceException(String.format("请按公式'%s'填写浮动金额", contract.getFloatAmount()));
        }

        if (entity.getValueAddedTax() != null) {
            throw new ServiceException("已开票的收费不能编辑");
        }
        if (ContractConstant.PaymentStatus.CHECKED.equals(entity.getStatus())) {
            throw new ServiceException("已审核的收费不能编辑");
        }

        if (payment.getFloatAmount() == null) {
            payment.setFloatAmount(new BigDecimal(0));
        }
        entity.setReceipt(payment.getReceipt());
        entity.setFloatAmount(payment.getFloatAmount());
        entity.setFixAmount(payment.getFixAmount());
        entity.setRemark(payment.getRemark());
        entity.setReceivedTime(payment.getReceivedTime());

        if (ContractConstant.PaymentStatus.REOPEN.equals(entity.getStatus())) {
            entity.setStatus(ContractConstant.PaymentStatus.UNCHECK);
        }

        int updates = mapper.updateByCondition(entity, updateCondiction);
        if (updates == 0) {
            throw new ServiceException("收费失败，请重新再试");
        }

        String json = JSON.toJSONString(entity);
        PaymentHistory history = new PaymentHistory();
        history.setContent(json);
        history.setCreateBy(userCode);
        history.setPaymentId(entity.getId());
        history.setGmtCreate(new Date());
        historyMapper.insert(history);
    }

    @Override
    public void paidBatch(Payment payment, String userCode) {
        ResidentContract contract = contractMapper.selectByPrimaryKey(payment.getContractId());

        if (!ContractConstant.EMPTY_FLOAT_AMOUNT.equals(contract.getFloatAmount()) &
                payment.getFloatAmount() == null) {
            throw new ServiceException(String.format("请按公式'%s'填写浮动金额", contract.getFloatAmount()));
        }


        Condition findCondiction = new Condition(Payment.class);
        findCondiction.createCriteria().andEqualTo("contractId", payment.getContractId())
                .andIsNull("valueAddedTax")
                .andNotEqualTo("status", ContractConstant.PaymentStatus.CHECKED);
        List<Payment> payments = mapper.selectByCondition(findCondiction);

        for (Payment entity : payments) {
            if (entity.getValueAddedTax() != null) {
                continue;
            }
            if (ContractConstant.PaymentStatus.CHECKED.equals(entity.getStatus())) {
                continue;
            }

            if (payment.getFloatAmount() == null) {
                payment.setFloatAmount(new BigDecimal(0));
            }
            entity.setReceipt(payment.getReceipt());
            entity.setFloatAmount(payment.getFloatAmount());
            entity.setFixAmount(payment.getFixAmount());
            entity.setRemark(payment.getRemark());
            entity.setReceivedTime(payment.getReceivedTime());

            if (ContractConstant.PaymentStatus.REOPEN.equals(entity.getStatus())) {
                entity.setStatus(ContractConstant.PaymentStatus.UNCHECK);
            }

            Condition updateCondiction = new Condition(Payment.class);
            updateCondiction.createCriteria().andEqualTo("id", entity.getId())
                    .andEqualTo("gmtModified", entity.getGmtModified());
            int updates = mapper.updateByCondition(entity, updateCondiction);
            if (updates == 0) {
                throw new ServiceException("收费失败，请重新再试");
            }

            String json = JSON.toJSONString(entity);
            PaymentHistory history = new PaymentHistory();
            history.setContent(json);
            history.setCreateBy(userCode);
            history.setPaymentId(entity.getId());
            history.setGmtCreate(new Date());
            historyMapper.insert(history);
        }
    }

    @Override
    public PageData search(String organId,
                           String commId,
                           String startTime,
                           String endTime,
                           String receivedStartTime,
                           String receivedEndTime,
                           String contractCode,
                           String contractStatus,
                           String isPaid,
                           String hasInvoice,
                           String status,
                           int page,
                           int size,
                           String userCode) {
        HashMap<String, Object> paramters = new HashMap<String, Object>();
        if (!StringUtils.isEmpty(commId)) {
            paramters.put("commId", commId);
        }
        if (!StringUtils.isEmpty(organId)) {
            paramters.put("organId", organId);
        }
        if (!StringUtils.isEmpty(startTime)) {
            paramters.put("startTime", DateUtil.parseDate(startTime));
        }
        if (!StringUtils.isEmpty(endTime)) {
            paramters.put("endTime", DateUtil.parseDate(endTime));
        }
        if (!StringUtils.isEmpty(receivedStartTime)) {
            paramters.put("receivedStartTime", DateUtil.parseDate(receivedStartTime));
        }
        if (!StringUtils.isEmpty(receivedEndTime)) {
            paramters.put("receivedEndTime", DateUtil.parseDate(receivedEndTime));
        }
        if (!StringUtils.isEmpty(contractCode)) {
            paramters.put("contractCode", contractCode);
        }
        if (!StringUtils.isEmpty(contractStatus)) {
            paramters.put("contractStatus", contractStatus);
        }
        if (!StringUtils.isEmpty(isPaid)) {
            paramters.put("isPaid", isPaid);
        }
        if (!StringUtils.isEmpty(hasInvoice)) {
            paramters.put("hasInvoice", hasInvoice);
        }

        if (!StringUtils.isEmpty(status) && ContractConstant.PaymentStatus.nameMap.containsKey(status)) {
            paramters.put("status", status);
        }


        if (StringUtils.isEmpty(commId)) {
            List<ErpCommunity> organBase = tbHsprCommunityMapper.findOrganBaseByUserCode(userCode, organId);
            List<ErpCommunity> commBase = tbHsprCommunityMapper.findCommBaseByUserCode(userCode, organId);

            List<String> organCodes = new ArrayList<String>();
            List<String> commIds = new ArrayList<String>();
            for (ErpCommunity community : organBase) {
                organCodes.add(community.getOrganCode());
            }
            for (ErpCommunity community : commBase) {
                commIds.add(community.getCommId());
            }
            if (organCodes.size() > 0) {
                paramters.put("organCodes", organCodes);
            }
            if (commIds.size() > 0) {
                paramters.put("commIds", commIds);
            }
            if (organCodes.size() == 0 && commIds.size() == 0) {
                List<ResidentContract> emptyList = new ArrayList<ResidentContract>();
                PageRowBounds pageRowBounds = new PageRowBounds(page, size);
                pageRowBounds.setTotal(0l);
                PageData pageData = new PageData(emptyList, pageRowBounds);
                return pageData;
            }
        }
        String baseUrl = env.getProperty("resident.file.url.base");
        if (StringUtils.isEmpty(baseUrl)) {
            baseUrl = "";
        }
        PageRowBounds pageRowBounds = new PageRowBounds(page, size);
        List<ResidentPaymentData> paymentDataList = mapper.findBy(paramters, pageRowBounds);
        for (ResidentPaymentData data : paymentDataList) {
            if (!StringUtils.isEmpty(data.getReceipt())) {
                data.setReceipt(baseUrl.concat(data.getReceipt()));
            }
            if (!StringUtils.isEmpty(data.getInvoiceImg())) {
                data.setInvoiceImg(baseUrl.concat(data.getInvoiceImg()));
            }
            String contractStatusName = ContractConstant.ContractStatus.nameMap.get(data.getContractStatus());
            data.setContractStatus(contractStatusName);
            String paymentStatus = ContractConstant.PaymentStatus.nameMap.get(data.getStatus());
            data.setStatus(paymentStatus);

            String createBy = data.getCreatedBy();
            String updateBy = data.getModifiedBy();
            try {
                TbSysUser createUser = tbSysUserService.findByUserCode(createBy);
                data.setCreatedBy(createUser.getUserName());

                TbSysUser upateUser = tbSysUserService.findByUserCode(updateBy);
                data.setModifiedBy(upateUser.getUserName());
            } catch (Exception e) {

            }
        }
        return new PageData(paymentDataList, pageRowBounds);
    }

    @Override
    public void check(Integer id, String status, String userCode) {
        Payment payment = mapper.selectByPrimaryKey(id);
        if (payment.getReceivedTime() == null) {
            throw new ServiceException("未收费不能审核");
        }
        if (!StringUtils.isEmpty(payment.getInvoiceNumber())) {
            throw new ServiceException("已开票收费不能进行审核");
        }
        String name = ContractConstant.PaymentStatus.nameMap.get(status);
        if (name == null) {
            throw new ServiceException(status + "状态不存在");
        }
        Condition updateCondiction = new Condition(Payment.class);
        updateCondiction.createCriteria().andEqualTo("id", payment.getId())
                .andEqualTo("gmtModified", payment.getGmtModified());
        payment.setStatus(status);
        payment.setGmtModified(new Date());
        payment.setModifiedBy(userCode);
        int updates = mapper.updateByCondition(payment, updateCondiction);
        if (updates == 0) {
            throw new ServiceException("更新失败，请重新操作");
        }
        String json = JSON.toJSONString(payment);
        PaymentHistory history = new PaymentHistory();
        history.setContent(json);
        history.setCreateBy(userCode);
        history.setPaymentId(payment.getId());
        history.setGmtCreate(new Date());
        historyMapper.insert(history);
    }

    @Override
    public void createPaymentBatch(ResidentContract contract) {
        String paymentMethod = contract.getPaymentMethod();
        switch (paymentMethod) {
            case ContractConstant.PaymentMethod.ONCE:
            case ContractConstant.PaymentMethod.MONTH:
            case ContractConstant.PaymentMethod.SEASION:
                Date[] rang = DateUtil.getMonthRang(contract.getStartDate(), contract.getEndDate());
                createPaymentByTime(contract, rang);
                break;
            default:
                throw new ServiceException(String.format("收款%s方式不支持，请重新选择", contract.getPaymentMethod()));
        }
    }

    @Override
    public ResidentPaymentAggregate aggregate(Integer contractId){
        return mapper.aggregate(contractId);
    }
}
