package common.service.impl;

import com.google.api.ads.adwords.lib.AdWordsProductFrameworkModule;
import common.model.*;
import common.repository.*;
import common.service.ContractService;
import common.service.UserService;
import dic.ContractStatusEnum;
import dic.ContractTypeEnum;
import dic.RoleEnum;
import dic.RoleTypeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tkio.model.Account;
import tkio.model.IncrementFlow;
import tkio.model.PackageType;
import tkio.repository.AccountRepository;
import tkio.repository.IncrementFlowRepository;
import tkio.repository.PackageTypeRepository;
import tkio.service.AccountService;
import tkio.service.TkioAccountService;
import userio.service.AccountIOService;
import userio.service.IOAccountService;
import util.DateUtil;
import util.ResultModel;
import util.ResultStatus;
import util.ValidateUtil;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

/**
 * Created by mxq on 2018/1/16.
 */
@Service
public class ContractServiceImpl implements ContractService{

    @Autowired
    ContractRepository contractRepository;
    @Autowired
    ContractBodyRepository contractBodyRepository;
    @Autowired
    Account4WebRepository account4WebRepository;
    @Autowired
    PackageTypeRepository packageTypeRepository;
    @Autowired
    PriceLevelMoneyRepository priceLevelMoneyRepository;
    @Autowired
    UserRepository userRepository;
    @Autowired
    ContractChangeRepository contractChangeRepository;
    @Autowired
    ContractMoneyRepository contractMoneyRepository;
    @Autowired
    AccountService accountService;
    @Autowired
    AccountIOService accountIOService;
    @Autowired
    IOAccount4WebRepository ioAccount4WebRepository;
    @Autowired
    ContractIncrementRepository contractIncrementRepository;
    @Autowired
    TkioAccountService tkioAccountService;
    @Autowired
    IOAccountService ioAccountService;
    @Autowired
    AccountRepository accountRepository;
    @Autowired
    UserService userService;
    @Autowired
    IncrementFlowRepository incrementFlowRepository;

    @Override
    public Map<String, Object> checkAccount(String email, String platfrom) {
        Map<String, Object> map = new HashMap<>();
        Account4Web account4Web = null;
        IOAccount4Web ioAccount4Web = null;
        if("tkio".equals(platfrom)){
            account4Web = account4WebRepository.findByEmail(email);
        }else if("io".equals(platfrom)){
            ioAccount4Web = ioAccount4WebRepository.findByEmail(email);
        }
        if(null == account4Web && null == ioAccount4Web){
            map.put("result", 0);
        }else{
            BigInteger integer = contractRepository.countNumByEmail(email,platfrom);
            map.put("result", 1);
            map.put("company", null == account4Web ? ioAccount4Web.getCompany() : account4Web.getCompany());
            map.put("num", integer.intValue());
            Contract contract = contractRepository.findByPlatformAndEmailLimitVaild(platfrom, email);
            if(null == contract){
                map.put("status", false);
            }else{
                map.put("status", true);
            }
        }

        return map;
    }

    @Override
    public Boolean checkTime(String email, String platfrom, String type, String product) {
        Boolean flag = false;
        if(ContractTypeEnum.MAIN.getKey().equals(type)){
            Contract contract = contractRepository.findByPlatformAndEmailLimit1(platfrom, email, type);
            if (null == contract){
                flag = true;
            }else{
                String beforeDay = DateUtil.getBeforeDays(180);
                if(beforeDay.compareTo(contract.getEndDate()) > 0){
                    flag = true;
                }
            }
        }else{
            ContractIncrement increment = contractIncrementRepository.findByCode(product);
            Contract contract = contractRepository.findByPlatformAndEmailAndPricelevelLimit1(platfrom, email, type, increment.getId());
            if (null == contract){
                flag = true;
            }else{
                String beforeDay = DateUtil.getBeforeDays(180);
                String endDate = contract.getEndDate() == null ? contract.getDs() : contract.getEndDate();
                if(beforeDay.compareTo(endDate) > 0){
                    flag = true;
                }
            }
        }
        return flag;
    }

    @Override
    public List<ContractBody> findBody() {
        return contractBodyRepository.findAll();
    }

    @Override
    public String getContractCode(String code) {
        BigInteger integer = contractRepository.countNumByDs(DateUtil.getBeforeDays(0));
        String lastCode = "";
        if(integer.intValue() < 9){
            lastCode = "0" + (integer.intValue() + 1);
        }else{
            lastCode = "" + (integer.intValue() + 1);
        }
        String re = code + "-" + DateUtil.getDays2(0) + lastCode;
        return re;
    }

    @Override
    public List findSetmeal() {
        List list = new ArrayList();
        List<PackageType> packageTypeList = packageTypeRepository.findAll();
        for(PackageType p : packageTypeList){
            p.setType("main");
            list.add(p);
        }
        List<ContractIncrement> increments = contractIncrementRepository.findAll();

        list.addAll(increments);
        return list;
    }

    @Override
    public List<ContractIncrement> findIncrement() {
        return null;
    }

    @Override
    public Double getRebat(String product, Integer level, Long money) {
        Double rebat = 1d;
        try{
            PriceLevelMoney levelMoney = priceLevelMoneyRepository.getOne(product, level);
            rebat = money * 1.0  / levelMoney.getMoney();
        } catch (Exception e){
            e.printStackTrace();
        }
        return rebat;
    }

    @Override
    public List<User> getSales() {
        return userRepository.findSales();
    }
    @Override
    public Contract build(Contract contract) {
        User user = userRepository.findByEmail(contract.getSaleName());
        if(null != user){
            contract.setSale(user.getId());
        }
        Account account = accountRepository.findByEmail(contract.getEmail());
        contract.setCustomerBody(account.getCompany());
        contract.setType("increment");
        contract.setPlatform("tkio");
        contract.setStartDate(DateUtil.getBeforeDays(0));
        ContractIncrement contractIncrement = contractIncrementRepository.findByCode(contract.getPriceLevelName());
        contract.setPriceLevel(contractIncrement.getId());
        Contract contract1 = create(null, contract);
        return contract1;
    }
    @Override
    public Contract create(User loginUser, Contract resource) {
        String contractCode = getContractCode(resource.getMyBodyCode());

        if(!contractCode.equals(resource.getContractCode())){
            resource.setContractCode(contractCode);
        }

        resource.setPayMoney(0L);
        resource.setInvoice(0L);
        Long extraFlow = resource.getExtraFlow();
        if(resource.getType().equals("main")) {
            if(!(extraFlow.longValue() == 0)){
                if(resource.getPlatform().equals("tkio")){
                    IncrementFlow  flow = new IncrementFlow();
                    Account account = accountRepository.findByEmail(resource.getEmail());
                    flow.setAccount(account.getId());
                    flow.setFlow(extraFlow);
                    flow.setEndDate(resource.getEndDate());
                    flow.setStartDate(resource.getStartDate());
                    flow.setContractCode(resource.getContractCode());
                    incrementFlowRepository.save(flow);
                }
            }
            if (DateUtil.getBeforeDays(0).compareTo(resource.getStartDate()) < 0) {
                resource.setDs(DateUtil.getBeforeDays(0));
                resource.setStatus("wait");
            } else {
                resource.setDs(DateUtil.getBeforeDays(0));
                resource.setStatus("executing");
            }
        }else{
            resource.setDs(DateUtil.getBeforeDays(0));
            resource.setStatus("wait");
        }
        Double rebat = getRebat(resource.getProduct(), resource.getPriceLevel().intValue(), resource.getMoney());
        BigDecimal bg = new BigDecimal(rebat);
        double f1 = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        resource.setRebate(f1);

        if(null != loginUser) {
            resource.setCreateAccount(loginUser.getId());
        }
        resource.setCreateTime(new Date());

        //同步修改trackingio的数据
        if(resource.getPlatform().equals("tkio") && resource.getType().equals("main")){
            accountService.update(resource);
        }
        if(resource.getPlatform().equals("io") && resource.getType().equals("main")){
            accountIOService.update(resource);
        }

        if(resource.getType().equals(ContractTypeEnum.MAIN.getKey())
                || (resource.getType().equals(ContractTypeEnum.INCREMENT.getKey()) && resource.getPriceLevel().equals(1L))){
            List<Contract> contractList = contractRepository.findByPlatformAndEmail(resource.getPlatform(), resource.getEmail(),resource.getType());
            if(ValidateUtil.isValid(contractList)){
                List<Contract> list = new ArrayList<>();
                for(Contract contract : contractList){
                    if(contract.getType().equals(ContractTypeEnum.MAIN.getKey())
                            || (contract.getType().equals(ContractTypeEnum.INCREMENT.getKey()) && contract.getPriceLevel().equals(1L))){

                        if(contract.getStatus().equals(ContractStatusEnum.EXECUTING.getKey())
                                || contract.getStatus().equals(ContractStatusEnum.WAIT.getKey())){
                            contract.setStatus(ContractStatusEnum.CANCEL.getKey());
                        }
                        list.add(contract);
                    }

                }
                contractRepository.save(contractList);
            }
        }

        return contractRepository.save(resource);
    }

    @Override
    public Contract update(User loginUser, Contract resource) {
        Map<Long, String> packageMap = getPackageMap();
        Map<Long, String> saleMap = getSaleMap();
        Contract contract = contractRepository.findOne(resource.getId());

        ContractChange cc = new ContractChange();
        cc.setType("update");
        cc.setUser(loginUser.getId());
        cc.setDs(DateUtil.getBeforeDays(0));
        cc.setContent("");
        cc.setEmail(contract.getEmail());
        cc.setCompany(contract.getCustomerBody());
        cc.setContractCode(contract.getContractCode());


        if(!resource.getStartDate().equals(contract.getStartDate())){
            cc.setContent(cc.getContent() + "开始时间变更 : " + contract.getStartDate() + "-->" + resource.getStartDate());
            contract.setStartDate(resource.getStartDate());
            if(DateUtil.getBeforeDays(0).compareTo(resource.getStartDate()) < 0){
                contract.setStatus("wait");
            }else{
                contract.setStatus("executing");
            }
        }
        if(!resource.getEndDate().equals(contract.getEndDate())){
            cc.setContent(cc.getContent() + "   结束时间变更 : " + contract.getEndDate() + "-->" + resource.getEndDate());
            contract.setEndDate(resource.getEndDate());
        }

        boolean newRebat = false;
        if(contract.getType().equals(ContractTypeEnum.MAIN.getKey())){
            if(!resource.getPriceLevel().equals(contract.getPriceLevel())){
                cc.setContent(cc.getContent() +  "  套餐变更：" + packageMap.get(contract.getPriceLevel()) + "-->" + packageMap.get(resource.getPriceLevel()));
                newRebat = true;
                contract.setPriceLevel(resource.getPriceLevel());
            }
        }

        if(!resource.getMoney().equals(contract.getMoney())){
            cc.setContent(cc.getContent() + "   金额变更： " + contract.getMoney() + "-->" + resource.getMoney());
            newRebat = true;
            contract.setMoney(resource.getMoney());
        }

        if(!resource.getSale().equals(contract.getSale())){
            cc.setContent(cc.getContent() + "销售变更：" + saleMap.get(contract.getSale()) + "-->" + saleMap.get(resource.getSale()));
            contract.setSale(resource.getSale());
        }

        if(newRebat){
            Double rebat = getRebat(contract.getProduct(), contract.getPriceLevel().intValue(), contract.getMoney());
            BigDecimal bg = new BigDecimal(rebat);
            double f1 = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            contract.setRebate(f1);
        }
        cc.setPlatform(contract.getPlatform());
        contractChangeRepository.save(cc);

        //同步修改trackingio的数据
        if(contract.getPlatform().equals("tkio") && resource.getType().equals("main")){
            accountService.update(contract);
        }
        if(contract.getPlatform().equals("io") && resource.getType().equals("main")){
            accountIOService.update(resource);
        }

        if(contract.getPlatform().equals("tkio")){
            IncrementFlow flow = incrementFlowRepository.findOne(resource.getContractCode());
            if(null != flow){
                flow.setEndDate(resource.getEndDate());
                flow.setStartDate(resource.getStartDate());
                if(contract.getExtraFlow() != resource.getExtraFlow() ){
                    flow.setFlow(resource.getExtraFlow());
                    incrementFlowRepository.save(flow);
                }
            } else if(resource.getExtraFlow().longValue() > 0){
                IncrementFlow  flow1 = new IncrementFlow();
                Account account = accountRepository.findByEmail(contract.getEmail());
                flow1.setAccount(account.getId());
                flow1.setFlow(resource.getExtraFlow());
                flow1.setEndDate(resource.getEndDate());
                flow1.setStartDate(resource.getStartDate());
                flow1.setContractCode(resource.getContractCode());
                incrementFlowRepository.save(flow1);
            }

        }
        contract.setExtraFlow(resource.getExtraFlow());

        return contractRepository.save(contract);
    }

    @Override
    public List<Contract> findAll(User loginAccount, String startDate, String endDate, String platfrom) {
        List<Contract> result = new ArrayList<>();
        List<User> sales = userRepository.findAll();
        Map<Long, String> saleMap = new HashMap<>();
        if(ValidateUtil.isValid(sales)){
            for(User s: sales){
                saleMap.put(s.getId(), s.getName());
            }
        }
        List<PackageType> typeList = packageTypeRepository.findAll();
        Map<Long, String> typeMap = new HashMap<>();
        if(ValidateUtil.isValid(typeList)){
            for(PackageType s: typeList){
                typeMap.put(s.getId(), s.getPackageName());
            }
        }
        List<ContractIncrement> incrementList = contractIncrementRepository.findAll();
        Map<Long, String> incremenMap = new HashMap<>();
        if(ValidateUtil.isValid(incrementList)){
            for(ContractIncrement s: incrementList){
                incremenMap.put(s.getId(), s.getPackageName());
            }
        }
        List<Contract> contractList = null;
        if(loginAccount.getRole().equals(RoleEnum.SOUTH_BUSSINUSS.getKey()) || loginAccount.getRole().equals(RoleEnum.NORTH_BUSSINUSS.getKey())){

            List<User> userList = userService.findAllSons(loginAccount.getId());
            List<Long> idList = new ArrayList<>();
            idList.add(loginAccount.getId());
            for(User u : userList){
                idList.add(u.getId());
            }

            contractList = contractRepository.findByDsAndRoile(startDate, endDate, platfrom, idList);
        }else{
            contractList = contractRepository.findByDs(startDate, endDate, platfrom);
        }

        if(ValidateUtil.isValid(contractList)){
            for(Contract c : contractList){
                c.setSaleName(saleMap.containsKey(c.getSale()) ? saleMap.get(c.getSale()) : "");
                if(c.getType().equals(ContractTypeEnum.MAIN.getKey())){
                    c.setPriceLevelName(typeMap.containsKey(c.getPriceLevel()) ? typeMap.get(c.getPriceLevel()) : "");
                } else{
                    c.setPriceLevelName(incremenMap.containsKey(c.getPriceLevel()) ? incremenMap.get(c.getPriceLevel()) : "");
                }

                c.setCreateName(saleMap.containsKey(c.getCreateAccount()) ? saleMap.get(c.getCreateAccount()) : "");
                result.add(c);
            }
        }
        return result;
    }

    @Override
    public Contract findOne(String code) {

        List<Contract> result = new ArrayList<>();
        List<User> sales = userRepository.findAll();
        Map<Long, String> saleMap = new HashMap<>();
        if(ValidateUtil.isValid(sales)){
            for(User s: sales){
                saleMap.put(s.getId(), s.getName());
            }
        }
        List<PackageType> typeList = packageTypeRepository.findAll();
        Map<Long, String> typeMap = new HashMap<>();
        if(ValidateUtil.isValid(typeList)){
            for(PackageType s: typeList){
                typeMap.put(s.getId(), s.getPackageName());
            }
        }
        List<ContractIncrement> incrementList = contractIncrementRepository.findAll();
        Map<Long, String> incremenMap = new HashMap<>();
        if(ValidateUtil.isValid(incrementList)){
            for(ContractIncrement s: incrementList){
                incremenMap.put(s.getId(), s.getPackageName());
            }
        }
        Contract contract = contractRepository.findByCode(code);
        contract.setSaleName(saleMap.containsKey(contract.getSale()) ? saleMap.get(contract.getSale()) : "");
        if(contract.getType().equals(ContractTypeEnum.MAIN.getKey())){
            contract.setPriceLevelName(typeMap.containsKey(contract.getPriceLevel()) ? typeMap.get(contract.getPriceLevel()) : "");
        } else{
            contract.setPriceLevelName(incremenMap.containsKey(contract.getPriceLevel()) ? incremenMap.get(contract.getPriceLevel()) : "");
        }
        contract.setCreateName(saleMap.containsKey(contract.getCreateAccount()) ? saleMap.get(contract.getCreateAccount()) : "");

        Boolean flag = null;
        if(contract.getPriceLevel().longValue() == 1l){
            flag = checkTime(contract.getEmail(), contract.getPlatform(),contract.getType(), "black");
        }else{
            flag = checkTime(contract.getEmail(), contract.getPlatform(),contract.getType(), "analysis");
        }

        if(flag){
            contract.setContractType("0");
        }else{
            contract.setContractType("1");
        }

        return contract;
    }

    @Override
    public ContractMoney pay(User loginUser, ContractMoney resource) {
        Contract contract = contractRepository.findByCode(resource.getContractCode());
        if(resource.getType().equals("pay")){
            contract.setPayMoney(contract.getPayMoney() + resource.getMoney());
        } else {
            contract.setInvoice(contract.getInvoice() + resource.getMoney());
        }

        if(contract.getType().equals(ContractTypeEnum.INCREMENT.getKey())){
            contract.setStatus("end");
        }
        contractRepository.save(contract);

        resource.setPlatform(contract.getPlatform());
        resource.setCreateAccount(loginUser.getId());
        resource.setCreateTime(new Date());
        resource.setUser(loginUser.getId());

        if(resource.getType().equals("pay") && contract.getPlatform().equals("tkio")){
            tkioAccountService.contractPay(loginUser, resource);
        }else if(resource.getType().equals("pay") && contract.getPlatform().equals("io")){
            ioAccountService.contractPay(loginUser, resource);
        }
        return contractMoneyRepository.save(resource);
    }

    @Override
    public Contract change(User loginUser, ContractChange resource) {
        Map<Long, String> packageMap = getPackageMap();
        Map<Long, String> saleMap = getSaleMap();
        Contract contract = contractRepository.findByCode(resource.getContractCode());
        if(resource.getType().equals("price")){
            resource.setContent("套餐变更 ：" + packageMap.get(contract.getPriceLevel()) + "-->" + packageMap.get(resource.getLevel())
                    + " 金额变更 ：" + contract.getMoney() + "-->" +(resource.getMoney() + contract.getMoney()));

            contract.setMoney(resource.getMoney() + contract.getMoney());
            contract.setPriceLevel(resource.getLevel());
            Double rebat = getRebat(contract.getProduct(), contract.getPriceLevel().intValue(), contract.getMoney());
            BigDecimal bg = new BigDecimal(rebat);
            double f1 = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            contract.setRebate(f1);

            //同步修改trackingio的数据
            if(contract.getPlatform().equals("tkio")){
                accountService.update(contract);
            }else if(contract.getPlatform().equals("io")){
                accountIOService.update(contract);
            }
        }else{
            //同步修改trackingio的数据
            if(contract.getPlatform().equals("tkio")){
                accountService.forbiden(contract);
            }else if(contract.getPlatform().equals("io")){
                accountIOService.update(contract);
            }
            contract.setStatus("cancel");
        }
        resource.setPlatform(contract.getPlatform());
        resource.setCreateAccount(loginUser.getId());
        resource.setCreateTime(new Date());
        resource.setDs(DateUtil.getBeforeDays(0));
        resource.setUser(loginUser.getId());
        contractChangeRepository.save(resource);

        return contractRepository.save(contract);
    }

    @Override
    public List<ContractMoney> findPay(String startDate, String endDate, String code) {
        List<User> sales = userRepository.findAll();
        Map<Long, String> saleMap = new HashMap<>();
        if(ValidateUtil.isValid(sales)){
            for(User s: sales){
                saleMap.put(s.getId(), s.getName());
            }
        }

        List<ContractMoney> result  = new ArrayList<>();
        List<ContractMoney> list = contractMoneyRepository.findByDs(startDate, endDate,code);
        if(ValidateUtil.isValid(list)){
            for(ContractMoney cm : list){
                cm.setCreateName(saleMap.containsKey(cm.getUser()) ? saleMap.get(cm.getUser()) : "");
                result.add(cm);
            }
        }
        return result;
    }

    @Override
    public List<ContractChange> findChange(String startDate, String endDate, String code) {

        List<User> sales = userRepository.findAll();
        Map<Long, String> saleMap = new HashMap<>();
        if(ValidateUtil.isValid(sales)){
            for(User s: sales){
                saleMap.put(s.getId(), s.getName());
            }
        }

        List<ContractChange> result  = new ArrayList<>();
        List<ContractChange> list = contractChangeRepository.findByDs(startDate, endDate,code);
        if(ValidateUtil.isValid(list)){
            for(ContractChange cm : list){
                cm.setCreateName(saleMap.containsKey(cm.getUser()) ? saleMap.get(cm.getUser()) : "");
                result.add(cm);
            }
        }
        return result;
    }

    @Override
    public Contract updatePay(User loginUser, ContractMoney resource) {
        ContractMoney contractMoney = contractMoneyRepository.findOne(resource.getId());
        Contract contract = contractRepository.findByCode(resource.getContractCode());
        if(contractMoney.getType().equals("pay")){
            contract.setPayMoney(contract.getPayMoney() + resource.getMoney() - contractMoney.getMoney());
        } else {
            contract.setInvoice(contract.getInvoice() + resource.getMoney() - contractMoney.getMoney());
        }
        Contract save = contractRepository.save(contract);

        contractMoney.setModifyAccount(loginUser.getId());
        contractMoney.setModifyTime(new Date());
        contractMoney.setMoney(resource.getMoney());
        contractMoney.setDs(resource.getDs());
        contractMoneyRepository.save(contractMoney);

        List<User> sales = userRepository.findAll();
        Map<Long, String> saleMap = new HashMap<>();
        if(ValidateUtil.isValid(sales)){
            for(User s: sales){
                saleMap.put(s.getId(), s.getName());
            }
        }
        List<PackageType> typeList = packageTypeRepository.findAll();
        Map<Long, String> typeMap = new HashMap<>();
        if(ValidateUtil.isValid(typeList)){
            for(PackageType s: typeList){
                typeMap.put(s.getId(), s.getPackageName());
            }
        }

        save.setSaleName(saleMap.containsKey(save.getSale()) ? saleMap.get(save.getSale()) : "");
        save.setPriceLevelName(typeMap.containsKey(save.getPriceLevel()) ? typeMap.get(save.getPriceLevel()) : "");
        save.setCreateName(saleMap.containsKey(save.getSale()) ? saleMap.get(save.getSale()) : "");
        return save;
    }

    @Override
    public List<ContractMoney> findPayAll(String startDate, String endDate, String platfrom) {
        List<User> sales = userRepository.findAll();
        Map<Long, String> saleMap = new HashMap<>();
        if(ValidateUtil.isValid(sales)){
            for(User s: sales){
                saleMap.put(s.getId(), s.getName());
            }
        }

        List<ContractMoney> result  = new ArrayList<>();
        List<ContractMoney> list = contractMoneyRepository.findByDsAll(startDate, endDate, platfrom);
        if(ValidateUtil.isValid(list)){
            for(ContractMoney cm : list){
                cm.setCreateName(saleMap.containsKey(cm.getUser()) ? saleMap.get(cm.getUser()) : "");
                result.add(cm);
            }
        }
        return result;
    }



    public Map<Long, String> getPackageMap(){
        List<PackageType> typeList = packageTypeRepository.findAll();
        Map<Long, String> typeMap = new HashMap<>();
        if(ValidateUtil.isValid(typeList)){
            for(PackageType s: typeList){
                typeMap.put(s.getId(), s.getPackageName());
            }
        }
        return typeMap;
    }

    public Map<Long, String> getSaleMap(){
        List<User> sales = userRepository.findAll();
        Map<Long, String> saleMap = new HashMap<>();
        if(ValidateUtil.isValid(sales)){
            for(User s: sales){
                saleMap.put(s.getId(), s.getName());
            }
        }
        return saleMap;
    }
}
