package common.service.impl;

import com.amazonaws.services.dynamodbv2.xspec.B;
import common.model.*;
import common.repository.AuthRepository;
import common.repository.ContractBodyRepository;
import common.repository.ContractChangeRepository;
import common.repository.ContractRepository;
import common.service.ShareIncomeService;
import dic.ContractStatusEnum;
import dic.RoleEnum;
import net.sf.json.JSONArray;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ShareIncomeServiceImpl implements ShareIncomeService {

    private final Logger logger = LoggerFactory.getLogger(ShareIncomeServiceImpl.class);

    @Autowired
    private ContractRepository contractRepository;
    @Autowired
    private AuthRepository authRepository;
    @Autowired
    private ContractBodyRepository contractBodyRepository;
    @Autowired
    private ContractChangeRepository contractChangeRepository;

    @Override
    public List<Contract> shareIncomeList(User loginAccount, String startDate, String endDate, String platform, String bodyCode, String serchName) {

        List<Contract> contracts = new ArrayList<>();

        if ("all".equals(bodyCode)) {
            bodyCode = null;
        }

        List<String> financeBodies = null;
        if (RoleEnum.FINANCE.getKey().equals(loginAccount.getRole())) {
            Auth auth = authRepository.findByUser(loginAccount.getId());
            financeBodies = JSONArray.fromObject(auth.getAuthExtend());
        }

        if (!StringUtils.isEmpty(bodyCode) && !StringUtils.isEmpty(serchName)) {

            if (financeBodies != null && !financeBodies.contains(bodyCode)) {
                //沒有权限查看
                return contracts;
            } else {
                contracts = contractRepository.findShareContranctByDate1(startDate, endDate, platform, bodyCode, serchName);
            }

        } else if (!StringUtils.isEmpty(bodyCode)) {
            if (financeBodies != null && !financeBodies.contains(bodyCode)) {
                //沒有权限查看
                return contracts;
            } else {
                contracts = contractRepository.findShareContranctByDate2(startDate, endDate, platform, bodyCode);
            }
        } else if (!StringUtils.isEmpty(serchName)) {
            if (financeBodies != null) {
                contracts = contractRepository.findShareContranctByDateSercheFinace(startDate, endDate, platform, serchName, financeBodies);
            } else {
                contracts = contractRepository.findShareContranctByDateSerche(startDate, endDate, platform, serchName);
            }
        } else {
            if (financeBodies != null) {
                contracts = contractRepository.findShareContranctByDateFinace(startDate, endDate, platform, financeBodies);
            } else {
                contracts = contractRepository.findShareContranctByDate3(startDate, endDate, platform);
            }
        }

        //contracts = new ArrayList<>();
        //contracts.add(contractRepository.findOne(1361L));

        List<ContractBody> bodies = contractBodyRepository.findAll();
        Map<String, String> bodiesNameMap = bodies.stream().collect(
                Collectors.toMap(ContractBody::getCode, ContractBody::getName, (v1, v2) -> v1));

        DateTime start = new DateTime(startDate);
        DateTime end = new DateTime(endDate);

        for (Contract contract : contracts) {

            this.caculateShareIncome(contract, start, end);
            contract.setMyBodyName(bodiesNameMap.get(contract.getMyBodyCode()));
        }

        return contracts;
    }

    private void caculateShareIncome(Contract contract, DateTime start, DateTime end) {

        DateTime create = new DateTime(new DateTime(contract.getCreateTime()).toString("yyyy-MM-dd"));
        DateTime contractStart = new DateTime(contract.getStartDate());
        DateTime contractEnd = new DateTime(contract.getEndDate());

        // 时间范围是否包含合同结束日期
        boolean containEnd = end.compareTo(contractEnd) >= 0;
        // 时间范围是否包含合同开始日期
        boolean containStart = start.compareTo(contractStart) <= 0;
        //所选结束时间包含合同结束时间 取合同结束时间 反之 取所选结束时间
        DateTime usedEnd = containEnd ? contractEnd : end;
        //所选开始时间包含合同开始时间 则取合同开始时间 反之 取所选开始时间
        DateTime usedStart = containStart ? contractStart : start;

        contract.setIntervalUseDays(Days.daysBetween(contractStart, usedEnd).getDays() + 1);//区间使用天数


        int allDay = Days.daysBetween(contractStart, contractEnd).getDays() + 1;
        Long excludTax = contract.getMoney() * 94;//不含税收入*100 ：contract.getMoney()*100 - contract.getMoney()*0.06*100 =  contract.getMoney()*94
        contract.setIncomeExcludingTax(excludTax);

        //每天的分摊收入
        //Long shareIncomDay = contract.getMoney() * 94 / allDay;
        //处理精度
        Long shareIncomDay = new BigDecimal(contract.getMoney() * 94 * 1.0 / allDay)
                .setScale(0, BigDecimal.ROUND_HALF_UP).longValue();

        DateTime creatMonth = create.dayOfMonth().withMinimumValue();//合同录入月1号

        int aferDays = 9;
        if (contractStart.monthOfYear().get() == 12) {
            // 12月份的合同 次月30号（包含）
            aferDays = 29;
        }
        DateTime nextMonth = null;

        Long adjustmentFund = 0L;

        int betweenMonth = create.getMonthOfYear() - contractStart.getMonthOfYear();

        if (ContractStatusEnum.CANCEL.getKey().equals(contract.getStatus()) || ContractStatusEnum.SUSPEND.getKey().equals(contract.getStatus())) {
            //合同作废

            boolean isCancel = ContractStatusEnum.CANCEL.getKey().equals(contract.getStatus()) ? true : false;
            String contentKey = isCancel ? ContractStatusEnum.CANCEL.getValue() : ContractStatusEnum.SUSPEND.getValue();
            ContractChange contractChange = contractChangeRepository.findByContentCode(contentKey, contract.getContractCode());

            if (contractChange == null) {
                contract.setAdjustmentFund(0L);
                contract.setIntervaIncomeShare(0L);
                contract.setIncomeShareAll(0L);
                return;
            }

            // 合同终止日 或 作废日
            DateTime cancelDate = new DateTime(contractChange.getDs());

            if (isCancel) {

                adjustmentFund = new BigDecimal((Days.daysBetween(contractStart, cancelDate).getDays() + 1) * excludTax * 1.0 / allDay)
                        .setScale(0, BigDecimal.ROUND_HALF_UP).longValue() * -1;

                usedEnd = usedEnd.compareTo(cancelDate) <= 0 ? usedEnd : cancelDate;
                int daysIncom = Days.daysBetween(usedStart, usedEnd).getDays() + 1;
                daysIncom = daysIncom < 0 ? 0 : daysIncom;
                //区间分摊总收入
                contract.setIntervaIncomeShare(shareIncomDay * daysIncom);

                boolean fullRange = Days.daysBetween(start, end).getDays()
                        >= Days.daysBetween(contractStart, cancelDate).getDays() ? true : false;

                if (fullRange) {
                    contract.setAdjustmentFund(-1 * contract.getIntervaIncomeShare());
                } else if (checkTwoTime(start, cancelDate) && checkTwoTime(cancelDate, end)) {
                    contract.setAdjustmentFund(adjustmentFund);
                } else {
                    contract.setAdjustmentFund(0L);
                }

                contract.setIncomeShareAll(contract.getIntervaIncomeShare() + contract.getAdjustmentFund());

            } else {
                //中止操作入库时间
                DateTime suspendDate = new DateTime(new DateTime(contractChange.getCreateTime()).toString("yyyy-MM-dd"));

                if (checkTwoTime(suspendDate, cancelDate)) {
                    adjustmentFund = 0L;
                } else {
                    adjustmentFund = new BigDecimal((Days.daysBetween(cancelDate, suspendDate).getDays() + 1) * excludTax * 1.0 / allDay)
                            .setScale(0, BigDecimal.ROUND_HALF_UP).longValue() * -1;
                }

                usedEnd = usedEnd.compareTo(cancelDate) <= 0 ? usedEnd : cancelDate;
                int daysIncom = Days.daysBetween(usedStart, usedEnd).getDays() + 1;
                daysIncom = daysIncom < 0 ? 0 : daysIncom;

                //区间分摊总收入
                contract.setIntervaIncomeShare(shareIncomDay * daysIncom);

                if (checkTwoTime(start, cancelDate) && checkTwoTime(cancelDate, end)) {
                    contract.setAdjustmentFund(adjustmentFund);
                } else {
                    contract.setAdjustmentFund(0L);
                }

                contract.setIncomeShareAll(contract.getIntervaIncomeShare() + contract.getAdjustmentFund());

            }

            //中止 取消 合同逻辑结束
            return;


        } else if (contractStart.dayOfMonth().withMaximumValue().plusDays(aferDays).isBefore(create)) {

            //录入时间在次月10以后 或次月30日以后
            if (betweenMonth == 1) {
                //相差一月
                nextMonth = contractStart.dayOfMonth().withMaximumValue().plusDays(1);//合同开始次月1号 与调整金对应
            } else if (betweenMonth > 1) {
                //相差多月
                nextMonth = creatMonth;//合同录入月1号 与调整金对应
            } else {
                //相差小于1月
                nextMonth = null;
            }

            if (nextMonth != null && end.isBefore(nextMonth.plusDays(betweenMonth > 1 ? -1 : 0))) {
                //当月（上月）及之前 无分摊收入
                contract.setIntervaIncomeShare(0L);
            } else if (nextMonth == null || (checkTwoTime(nextMonth, end))) {
                if (nextMonth == null) {
                    //执行期内的分摊金额开始时间
                    nextMonth = usedStart;
                }

                //筛选结束时间包含合同开始次月1号 则计算分摊收入
                //时间范围内用于计算分摊金额的天数
                DateTime shareStart = start.compareTo(nextMonth) <= 0 ? nextMonth : start;
                int daysIncom = Days.daysBetween(shareStart, usedEnd).getDays() + 1;
                //区间分摊收入
                contract.setIntervaIncomeShare(shareIncomDay * daysIncom);
            } else {
                contract.setIntervaIncomeShare(0L);
            }

            //调证金   筛选时间包含录入月1号 则计算调证金
            //调证金：（合同开始月最后一日 - 合同开始日期 + 1）* （不含税收入 / 合同总天数）

            if (betweenMonth == 1) {

                adjustmentFund = nextMonth == null ? 0 : new BigDecimal((contractStart.dayOfMonth().withMaximumValue().dayOfMonth().get()
                        - contractStart.getDayOfMonth() + 1) * excludTax * 1.0 / allDay)
                        .setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
            } else {
                adjustmentFund = nextMonth == null ? 0 :
                        new BigDecimal((Days.daysBetween(contractStart, creatMonth.plusDays(-1)).getDays() + 1) * 1.0 * excludTax / allDay)
                                .setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
            }


            if (nextMonth != null && checkTwoTime(start, nextMonth) && checkTwoTime(nextMonth, end)) {
                contract.setAdjustmentFund(adjustmentFund);
                //筛选开始时间包含次月1号，则分摊金需加上调证金
                contract.setIntervaIncomeShare(contract.getIntervaIncomeShare() + adjustmentFund);
                contract.setIncomeShareAll(contract.getIntervaIncomeShare());
            } else {
                contract.setAdjustmentFund(0L);
            }

        } else {

            //时间范围内用于计算分摊金额的天数
            int daysIncom = Days.daysBetween(start, usedEnd).getDays() + 1;
            //区间分摊总收入
            contract.setIntervaIncomeShare(shareIncomDay * daysIncom);
            contract.setAdjustmentFund(0L);
            contract.setIncomeShareAll(contract.getIntervaIncomeShare());
            adjustmentFund = 0L;


        }

        DateTime dayShareStartDate;

        dayShareStartDate = nextMonth == null ? contractStart : nextMonth;

        //最后一日  包含最后一日 时 分摊金处理
        //adjustmentFund = adjustmentFund < 0 ? 0 : adjustmentFund;

        Long lastDay = excludTax - adjustmentFund - shareIncomDay * (Days.daysBetween(dayShareStartDate, contractEnd).getDays());
        if (start.isEqual(end) && start.isEqual(contractEnd)) {
            //最后一日分摊金处理
            contract.setIntervaIncomeShare(lastDay);
            contract.setIncomeShareAll(contract.getIntervaIncomeShare());
        } else if (checkTwoTime(contractEnd, end)) {
            //包含最后一日 时
            contract.setIntervaIncomeShare(contract.getIntervaIncomeShare() - shareIncomDay + lastDay);
            contract.setIncomeShareAll(contract.getIntervaIncomeShare());
        }else{
            contract.setIncomeShareAll(contract.getIntervaIncomeShare());
        }

    }


    public boolean checkTwoTime(DateTime dateTime1, DateTime dateTime2) {
        return dateTime1.isBefore(dateTime2) || dateTime1.isEqual(dateTime2);
    }

    public static void main(String[] args) {
        DateTime contractStart = new DateTime("2020-05-15");
        DateTime create = new DateTime("2020-06-15");
        System.out.println(contractStart.monthOfYear().getDateTime());
        System.out.println(contractStart.dayOfMonth().withMaximumValue().plusDays(1));
        System.out.println(contractStart.dayOfMonth().withMaximumValue().plusDays(9).isBefore(create));
        System.out.println(contractStart.compareTo(create));

        long ss = new BigDecimal(94000 * 1.0 / 52)
                .setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
        System.out.println(ss);


    }
}
