package userio.service.impl;

import common.model.*;
import common.repository.*;
import dic.ContractTypeEnum;
import tkio.model.*;
import userio.model.*;
import common.service.UserService;
import dic.RoleEnum;
import dic.RoleTypeEnum;
import org.apache.commons.collections4.list.TreeList;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import userio.model.Account;
import userio.model.PackageType;
import userio.model.SalesManLeader;
import userio.repository.IOAccountRepository;
import userio.repository.IOAppRepository;
import userio.repository.IOPackageTypeRepository;
import userio.repository.IOSalesManLeaderRepository;
import userio.service.IOAccountService;
import util.Constant;
import util.DateUtil;
import util.HttpClientUtil;
import util.ValidateUtil;

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

/**
 * Created by mxq on 2017/12/26.
 */
@Service
public class IOAccountServiceImpl implements IOAccountService {

    //查询URI
    private final static String URI_REPORT_BY_SQL = "/api/trackingio/bysql";

    @Autowired
    IOAccount4WebRepository account4WebRepository;
    @Autowired
    IOSalesManLeaderRepository salesManLeaderRepository;
    @Autowired
    IOAccountRepository accountRepository;
    @Autowired
    BackVisitRepository backVisitRepository;
    @Autowired
    PaymentRepository paymentRepository;
    @Autowired
    ReminderRepository reminderRepository;
    @Autowired
    IOAppRepository appRepository;
    @Autowired
    UserRepository userRepository;
    @Autowired
    ContractMoneyRepository contractMoneyRepository;
    @Autowired
    ContractRepository contractRepository;
    @Autowired
    ContractChangeRepository contractChangeRepository;
    @Autowired
    IOPackageTypeRepository packageTypeRepository;
    @Autowired
    UserService userService;
    @Autowired
    ReminderLevelRepository reminderLevelRepository;
    @Autowired
    PressMoneyRepository pressMoneyRepository;

    @Override
    public List<IOAccount4Web> findAll(User user) {
        List<IOAccount4Web> result = new ArrayList<>();
        List<IOAccount4Web> account4WebList = null;
        if(user.getRole().equals(RoleEnum.MANAGER.getKey())){
            account4WebList = account4WebRepository.findAll();
        } else{
            List<Integer> idList = new ArrayList<>();
            if(user.getRoleType().equals(RoleTypeEnum.MANAGER.getKey())){
                List<User> userList = userRepository.findAllUserByRole(user.getRole());
                List<String> emialList = new ArrayList<>();
                for(User u : userList){
                    emialList.add(u.getEmail());
                }
                List<SalesManLeader> salesManLeaderList = salesManLeaderRepository.findAllByEmails(emialList);
                if (ValidateUtil.isValid(salesManLeaderList)){
                    for(SalesManLeader sml : salesManLeaderList){
                        idList.add(sml.getId());
                    }
                }
            }else{
                List<String> emailList = new ArrayList<>();
                emailList.add(user.getEmail());
                List<User> userList = userService.findAllSons(user.getId());
                if(ValidateUtil.isValid(userList)){
                    for(User u : userList){
                        emailList.add(u.getEmail());
                    }
                }
                List<SalesManLeader> manLeaderList = salesManLeaderRepository.findAllByEmails(emailList);
                if(ValidateUtil.isValid(manLeaderList)){
                    for(SalesManLeader a : manLeaderList){
                        idList.add(a.getId());
                    }
                }

            }
            if(ValidateUtil.isValid(idList)){
                List<Account> accountList = accountRepository.findBussnissMan(idList);
                List<String> emails = new ArrayList<>();
                if(ValidateUtil.isValid(accountList)){
                    for(Account ac : accountList){
                        emails.add(ac.getEmail());
                    }
                    account4WebList = account4WebRepository.findByEmails(emails);
                }
            }
        }

        List<SalesManLeader> roles = salesManLeaderRepository.findAll();
        Map<Long, String> busMap = new HashMap<>();
        for(SalesManLeader u : roles){
            busMap.put((long)u.getId(),u.getName());
        }
        List<User> users = userRepository.findAll();
        Map<String, Long> saleMap = new HashMap<>();
        for(User u : users){
            saleMap.put(u.getEmail(),u.getId());
        }


        List<Reminder> reminderList = reminderRepository.findAllDistinct("io");
        Map<Long, Boolean> reMap = new HashMap<>();
        if(ValidateUtil.isValid(reminderList)){
            for(Reminder re : reminderList){
                reMap.put(re.getAccountId(), re.getRemindStatus());
            }
        }

        List<PressMoney> allPress = pressMoneyRepository.findAllPress("io");
        Map<Long, Boolean> pressMap = new HashMap<>();
        if(ValidateUtil.isValid(allPress)){
            for(PressMoney re : allPress){
                pressMap.put(re.getAccountId(), re.getPressStatus());
            }
        }
        if(ValidateUtil.isValid(account4WebList)){
            Map<String, Integer> backTimeMap = getBackTime();
            Map<String, List<Contract>> payMap = getPay();
            for(IOAccount4Web aw : account4WebList){
                if(backTimeMap.containsKey(aw.getEmail())){
                    aw.setBackTime(backTimeMap.get(aw.getEmail()));
                } else{
                    aw.setBackTime(0);
                }

                if(busMap.containsKey(aw.getBussinessMan())){
                    aw.setSaleName(busMap.get(aw.getBussinessMan()));
                }else{
                    aw.setSaleName("");
                }
                if(pressMap.containsKey(aw.getAccountId())){
                    aw.setPressStatus(true);
                    aw.setContractStatus("stop");
                } else{
                    aw.setRemStatus(false);
                }
                if(payMap.containsKey(aw.getEmail())){
                    List<Contract> contractList = payMap.get(aw.getEmail());
                    aw.setMoney(contractList.get(contractList.size() - 1 ).getPayMoney());
                    aw.setContractStatus(contractRepository.findByPlatformAndEmailLimit1("io", aw.getEmail(), ContractTypeEnum.MAIN.getKey()).getStatus());
                    aw.setContractTime(contractList.size());
                } else{
                    aw.setContractTime(0);
                    aw.setContractStatus("empty");
                    aw.setMoney(0L);
                }
                if(reMap.containsKey(aw.getAccountId())){
                    aw.setRemStatus(reMap.get(aw.getAccountId()));
                } else{
                    aw.setRemStatus(true);
                }
                if(saleMap.containsKey(aw.getSaleEamil())){
                    aw.setSale(saleMap.get(aw.getSaleEamil()));
                }
                result.add(aw);
            }
        }
        return result;
    }
    @Override
    public IOAccount4Web findOne(String email) {
        List<Reminder> reminderList = reminderRepository.findAllDistinct("io");
        Map<Long, Boolean> reMap = new HashMap<>();
        if(ValidateUtil.isValid(reminderList)){
            for(Reminder re : reminderList){
                reMap.put(re.getAccountId(), re.getRemindStatus());
            }
        }
        IOAccount4Web aw = account4WebRepository.findByEmail(email);
        if(null == aw){
            return null;
        }
        List<BackVisit> backVisitList = backVisitRepository.findAllByPlatformAndEmail("io", email);
        if(ValidateUtil.isValid(backVisitList)){
            aw.setBackTime(backVisitList.size());
        } else{
            aw.setBackTime(0);
        }
        List<Contract> contractList = contractRepository.findByPlatformAndEmail("io", email,ContractTypeEnum.MAIN.getKey());
        if(ValidateUtil.isValid(contractList)){
            aw.setMoney(contractList.get(contractList.size() - 1 ).getPayMoney());
            aw.setContractStatus(contractList.get(contractList.size() - 1 ).getStatus());
            aw.setContractTime(contractList.size());
        } else{
            aw.setContractTime(0);
            aw.setContractStatus("empty");
            aw.setMoney(0L);
        }
        if(reMap.containsKey(aw.getAccountId())){
            aw.setRemStatus(reMap.get(aw.getAccountId()));
        } else{
            aw.setRemStatus(true);
        }

        List<SalesManLeader> roles = salesManLeaderRepository.findAll();
        Map<Long, String> busMap = new HashMap<>();
        for(SalesManLeader u : roles){
            busMap.put((long)u.getId(),u.getName());
        }

        if(busMap.containsKey(aw.getBussinessMan())){
            aw.setSaleName(busMap.get(aw.getBussinessMan()));
        }else{
            aw.setSaleName("");
        }
        return aw;
    }

    @Override
    public List<ReminderLevel> findReminderlevel() {
        return reminderLevelRepository.findAll();
    }

    @Override
    public Reminder forbiden(User user, Reminder resource) {
        resource.setUser(user.getId());
        resource.setModifyTime(new Date());
        resource.setPlatform("io");
        resource.setRemindStatus(false);
        resource.setDs(DateUtil.getBeforeDays(0));
        return reminderRepository.save(resource);
    }

    @Override
    public Reminder enable(User user, Reminder resource) {
        resource.setUser(user.getId());
        resource.setModifyTime(new Date());
        resource.setPlatform("io");
        resource.setRemindStatus(true);
        resource.setDs(DateUtil.getBeforeDays(0));
        return reminderRepository.save(resource);
    }

    @Override
    public PressMoney forbidenPress(User user, PressMoney resource) {
        resource.setUser(user.getId());
        resource.setModifyTime(new Date());
        resource.setPlatform("io");
        resource.setPressStatus(false);
        resource.setDs(DateUtil.getBeforeDays(0));
        return pressMoneyRepository.save(resource);
    }

    @Override
    public PressMoney enablePress(User user, PressMoney resource) {
        resource.setUser(user.getId());
        resource.setModifyTime(new Date());
        resource.setPlatform("io");
        resource.setPressStatus(true);
        resource.setDs(DateUtil.getBeforeDays(0));
        return pressMoneyRepository.save(resource);
    }

    @Override
    public Payment pay(User user, Payment resource) {
        resource.setUser(user.getId());
        resource.setPayDate(new Date());
        resource.setPlatform("io");
        resource.setDs(DateUtil.getBeforeDays(0));

        Reminder re = new Reminder();
        re.setUser(user.getId());
        re.setModifyTime(new Date());
        re.setPlatform("io");
        re.setRemindStatus(true);
        re.setDs(DateUtil.getBeforeDays(0));
        reminderRepository.save(re);

        return paymentRepository.save(resource);
    }

    @Override
    public BackVisit visit(User user, BackVisit resource) {
        resource.setUser(user.getId());
        resource.setVisitDate(new Date());
        resource.setPlatform("io");
        resource.setDs(DateUtil.getBeforeDays(0));
        return backVisitRepository.save(resource);
    }

    @Override
    public Map<String, Integer> findFunTimes(Long account, String startDate, String endDate) {
        Map<String, Integer> result = new HashMap<>();
        List<Account> accountList = accountRepository.findByRootParent(account);
        List<Long> idList = new ArrayList<>();
        for(Account ac : accountList){
            idList.add(ac.getId());
        }
        List<String> appkeys = appRepository.findAppkeys(idList);
        String appkeyStr = String.join("','", appkeys);

        BigInteger numAccount = accountRepository.countByRootParent(account, startDate, endDate);
        BigInteger numApp = appRepository.countByAccount(idList, startDate, endDate);

   result.put("numAccount", numAccount.intValue());
        result.put("numApp", numApp.intValue());
        return result;
    }

    @Override
    public List<Map<String, Object>> findPv(Long account, String startDate, String endDate) {
        List<Map<String, Object>>  result = new ArrayList<>();
        List<Account> accountList = accountRepository.findByRootParent(account);
        List<Long> idList = new ArrayList<>();
        for(Account ac : accountList){
            idList.add(ac.getId());
        }
        List<String> appkeys = appRepository.findAppkeys(idList);
        String appkeyStr = String.join("','", appkeys);

        String querySql = "select menu, count(*) as pv, count(distinct(xwho)) as uv, count(*)/count(distinct(xwho)) as puv " +
                "from tkio_bigtable_view.event_f0f251af10e66a0c94d2e923d8863105 where user_appkey in ('" + appkeyStr + "') " +
                "AND ds >= '" + startDate + "' AND ds <= '" + endDate + "'  group by menu;";
        String url = Constant.reportUrl + URI_REPORT_BY_SQL;

        Map<String, String> conditions = new HashMap<>();
        conditions.put("sql", querySql);
        conditions.put("dbtype", "presto");
        conditions.put("datatype", "list");
        conditions.put("iscache", "0");

        String responseJson = HttpClientUtil.doHttpPostRequest(url, "trackingio", conditions);
        if(responseJson.contains("val")){
            try {
                JSONObject jsonObject = new JSONObject(responseJson);
                JSONArray valArr = jsonObject.getJSONArray("val");
                if(null != valArr && valArr.length() > 0){
                    for(int i = 0; i < valArr.length(); i++){
                        JSONObject val = valArr.getJSONObject(i);
                        Map<String, Object> map = new HashMap<>();
                        map.put("menu", val.getString("menu"));
                        map.put("pv", val.getInt("pv"));
                        map.put("uv", val.getInt("uv"));
                        map.put("puv", val.getInt("puv"));

                        result.add(map);
                    }
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    @Override
    public List<Reminder> findRed(Long account, String startDate, String endDate) {
        List<Reminder> result = new ArrayList<>();
        List<User> userList = userRepository.findAll();
        Map<Long, String> userMap = new HashMap<>();
        for(User u : userList){
            userMap.put(u.getId(), u.getName());
        }
        List<Reminder> list = reminderRepository.findAll(account, startDate, endDate, "io");
        if (ValidateUtil.isValid(list)) {
            for(Reminder re : list){
                re.setUserName(userMap.get(re.getUser()));
                result.add(re);
            }
        }
        return result;
    }

    @Override
    public List<BackVisit> findVisit(Long account, String startDate, String endDate) {
        List<BackVisit> result = new ArrayList<>();
        List<User> userList = userRepository.findAll();
        Map<Long, String> userMap = new HashMap<>();
        for(User u : userList){
            userMap.put(u.getId(), u.getName());
        }
        List<BackVisit> list = backVisitRepository.findAll(account, startDate, endDate, "io");
        if (ValidateUtil.isValid(list)) {
            for(BackVisit re : list){
                re.setUserName(userMap.get(re.getUser()));
                result.add(re);
            }
        }
        return result;
    }

    @Override
    public List<ContractMoney> findPay(String email, String startDate, String endDate) {
        List<ContractMoney> result = new ArrayList<>();
        List<User> userList = userRepository.findAll();
        Map<Long, String> userMap = new HashMap<>();
        for(User u : userList){
            userMap.put(u.getId(), u.getName());
        }
        List<ContractMoney> list = contractMoneyRepository.findByDs(startDate, endDate, email,"io");
        if(ValidateUtil.isValid(list)){
            for(ContractMoney cm : list){
                Long user = null == cm.getModifyAccount() ? cm.getUser() : cm.getModifyAccount();
                cm.setCreateName(userMap.containsKey(user) ? userMap.get(user) : "");
                result.add(cm);
            }
        }
        return result;
    }

    @Override
    public List<Contract> findContract(String email) {
        List<Contract> result = new ArrayList<>();
        List<User> userList = userRepository.findAll();
        Map<Long, String> userMap = new HashMap<>();
        for(User u : userList){
            userMap.put(u.getId(), u.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<Contract> contractList = contractRepository.findByPlatformAndEmail("io", email,ContractTypeEnum.MAIN.getKey());
        if(ValidateUtil.isValid(contractList)){
            for(Contract cm : contractList){
                cm.setSaleName(userMap.containsKey(cm.getSale()) ? userMap.get(cm.getSale()) : "");
                cm.setPriceLevelName(typeMap.containsKey(cm.getPriceLevel()) ? typeMap.get(cm.getPriceLevel()) : "");
                result.add(cm);
            }
        }
        return result;
    }

    @Override
    public List<ContractChange> findContractChange(String email, String startDate, String endDate) {
        List<ContractChange> result = new ArrayList<>();
        List<User> userList = userRepository.findAll();
        Map<Long, String> userMap = new HashMap<>();
        for(User u : userList){
            userMap.put(u.getId(), u.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<ContractChange> contractChangeList = contractChangeRepository.findByPlatformAndEmail("io", email, startDate, endDate);
        if(ValidateUtil.isValid(contractChangeList)){
            for(ContractChange cm : contractChangeList){
                Long user = null == cm.getModifyAccount() ? cm.getUser() : cm.getModifyAccount();
                cm.setCreateName(userMap.containsKey(user) ? userMap.get(user) : "");
                cm.setLevelName(typeMap.containsKey(cm.getLevel()) ? typeMap.get(cm.getLevel()) : "");
                result.add(cm);
            }
        }
        return result;
    }
    @Override
    public void contractPay(User loginUser, ContractMoney resource) {
        Contract contract = contractRepository.findByCode(resource.getContractCode());
        //增值服务
        if(contract.getType().equals(ContractTypeEnum.INCREMENT.getKey())){
            if(contract.getPriceLevel().longValue() == 1l){

            }
        }else{//基础套餐
            Account account = accountRepository.findByEmail(resource.getEmail());
            PressMoney press = pressMoneyRepository.findOnePress("io",account.getId());
            //如果被催款了，恢复状态
            if(press != null){
                account.setStatus(1);
                accountRepository.save(account);

                contract.setStatus("executing");
                contractRepository.save(contract);
            }

        }

    }


    public Map<String, Integer> getBackTime(){
        Map<String, Integer> map = new HashMap<>();
        List<BackVisit> all = backVisitRepository.findAllByPlatform("io");
        if (ValidateUtil.isValid(all)){
            for(BackVisit bv : all){
                if(map.containsKey(bv.getEmail())){
                    map.put(bv.getEmail(), map.get(bv.getEmail()) + 1);
                } else{
                    map.put(bv.getEmail(), 1);
                }
            }
        }
        return map;
    }



    public Map<String, List<Contract>> getPay(){
        Map<String, List<Contract>> map = new HashMap<>();
        List<Contract> contractList = contractRepository.findByPlatform("io");
        if (ValidateUtil.isValid(contractList)){
            for(Contract pa : contractList){
                if(map.containsKey(pa.getEmail())){
                    List<Contract> list = map.get(pa.getEmail());
                    list.add(pa);
                    map.put(pa.getEmail(), list);
                } else{
                    List<Contract> list = new TreeList<>();
                    list.add(pa);
                    map.put(pa.getEmail(), list);
                }
            }
        }
        return map;
    }

}
