package com.boot.security.server.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.boot.security.server.dao.AdvertDao;
import com.boot.security.server.dto.LoginUser;
import com.boot.security.server.model.AdvertiserData;
import com.boot.security.server.page.table.PageTableRequest;
import com.boot.security.server.service.AdvertiserService;
import com.boot.security.server.utils.ConnectionJDBC;
import com.boot.security.server.utils.UserUtil;
import com.boot.security.server.utils.redis.JedisHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class AdvertiserServiceImpl implements AdvertiserService {

    @Autowired
    private AdvertDao advertDao;

    @Override
    public JSONObject getAdvertiserData(PageTableRequest request) {
        String today = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String startTime = request.getStartTime();
        String endTime = request.getEndTime();
        Integer advertiserId = request.getAdvertiserId();
        String advertId = request.getAdvertId();
        List<AdvertiserData> advertiser=new ArrayList<>();
        List<AdvertiserData> advert=new ArrayList<>();
        AdvertiserData schema=new AdvertiserData();
        JSONObject jsonObject = new JSONObject();
        LoginUser loginUser = UserUtil.getLoginUser();

        if(startTime.equals(endTime)&&startTime.equals(today)){
            if(advertiserId==null&&advertId.equals("all")){
                advertiser=advertDao.getAdvertiserByUserId(loginUser.getId());
                advert=advertDao.getAdvertDataById(advertiser.get(0).getAdvertiserId());
                schema=advertDao.getAdvertiserDataById(advertiser.get(0).getAdvertiserId());
                JSONObject chartInfo = getRedisChartInfo(advertiser.get(0).getAdvertiserId(), advertId);
                jsonObject.put("dataTime",chartInfo.get("dataTime"));
                jsonObject.put("exposure",chartInfo.get("exposure"));
                jsonObject.put("click",chartInfo.get("click"));
            }else if(advertiserId!=null&&advertId!=null){
                advert=advertDao.getAdvertDataById(advertiserId);
                schema=advertDao.getAdvertiserDataById(advertiserId);
                JSONObject chartInfo = getRedisChartInfo(advertiserId, advertId);
                jsonObject.put("dataTime",chartInfo.get("dataTime"));
                jsonObject.put("exposure",chartInfo.get("exposure"));
                jsonObject.put("click",chartInfo.get("click"));
            }
        }else if(startTime.equals(endTime)&&!startTime.equals(today)){
            if(advertiserId==null&&advertId.equals("all")){
                advertiser=advertDao.getAdvertiserByUserId(loginUser.getId());
                advert=advertDao.getAdvertDataById(advertiser.get(0).getAdvertiserId());
                schema=advertDao.getAdvertiserDataById(advertiser.get(0).getAdvertiserId());
                List<AdvertiserData> advertExCl = advertDao.getAdvertExCl(advertiser.get(0).getAdvertiserId(), startTime);
                JSONObject mysqlChartInfo = getMysqlChartInfo(advertExCl);
                jsonObject.put("dataTime",mysqlChartInfo.get("dataTime"));
                jsonObject.put("exposure",mysqlChartInfo.get("exposure"));
                jsonObject.put("click",mysqlChartInfo.get("click"));
            }else if(advertiserId!=null&&advertId!=null){
                advert=advertDao.getAdvertDataById(advertiserId);
                schema=advertDao.getAdvertiserDataById(advertiserId);
                List<AdvertiserData> advertExCl=null;
                if(advertId.equals("all")){
                    advertExCl = advertDao.getAdvertExCl(advertiserId,startTime);
                }else {
                    advertExCl = advertDao.getAdvertExCls(advertiserId,advertId,startTime);
                }
                JSONObject mysqlChartInfo = getMysqlChartInfo(advertExCl);
                jsonObject.put("dataTime",mysqlChartInfo.get("dataTime"));
                jsonObject.put("exposure",mysqlChartInfo.get("exposure"));
                jsonObject.put("click",mysqlChartInfo.get("click"));
            }
        }else {
            if(advertId.equals("all")){
                advert=advertDao.getAdvertDataById(advertiserId);
                schema=advertDao.getAdvertiserDataById(advertiserId);
                List<AdvertiserData> advertExClDays = advertDao.getAdvertExClDay(advertiserId, startTime, endTime);
                JSONObject mysqlChartInfo = getMysqlChartInfo(advertExClDays);
                jsonObject.put("dataTime",mysqlChartInfo.get("dataTime"));
                jsonObject.put("exposure",mysqlChartInfo.get("exposure"));
                jsonObject.put("click",mysqlChartInfo.get("click"));
            }else {
                advert=advertDao.getAdvertDataById(advertiserId);
                schema=advertDao.getAdvertiserDataById(advertiserId);
                List<AdvertiserData> advertExClDays = advertDao.getAdvertExClDays(advertiserId, advertId,startTime, endTime);
                JSONObject mysqlChartInfo = getMysqlChartInfo(advertExClDays);
                jsonObject.put("dataTime",mysqlChartInfo.get("dataTime"));
                jsonObject.put("exposure",mysqlChartInfo.get("exposure"));
                jsonObject.put("click",mysqlChartInfo.get("click"));
            }
        }
        jsonObject.put("advertiser",advertiser);
        jsonObject.put("advert",advert);
        jsonObject.put("schema",schema);
        return jsonObject;
    }

    @Override
    public JSONObject getAdvertiserManagerData(PageTableRequest request) {
        List<AdvertiserData> data = advertDao.getAdvertiserDataByUserId(UserUtil.getLoginUser().getId());
        Integer count = advertDao.getAdvertiserDataByUserIdCount(UserUtil.getLoginUser().getId());
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("data",data);
        jsonObject.put("count",count);
        jsonObject.put("code",0);
        return jsonObject;
    }

    @Override
    public void updateAdvertiserManagerData(AdvertiserData advertiserData) {
        advertDao.updateAdvertiserData(advertiserData.getAdvertiserId(),advertiserData.getBalance(),advertiserData.getExposureView(),advertiserData.getClickView());
    }

    //同步cms广告主和广告数据
    @Override
    public void syncAdvertiserAndAdvert() {
        //读cms广告商和广告信息(广告商id、广告商名称、广告id、广告名称、平台id)
        List<AdvertiserData> dataList = ConnectionJDBC.getInstance("SELECT b.advertiser_id,a.name,b.code_id,b.name,b.platform_id FROM advertiser a LEFT JOIN advert b ON a.id=b.advertiser_id WHERE TYPE=2");
        //插入advert_list表里面(用duplicate)
        advertDao.insertAdvertList(dataList);
        //插入advertiser_data_count表(用duplicate，广告商id、广告商名称、曝光和点击系数默认为1)
        List<AdvertiserData> advertiserData = advertDao.getAdvertiserData();
        advertDao.insertAdvertiserData(advertiserData);
        //插入advertiser_user_map表(用duplicate，用户id、广告商id、广告商名称)
        List<AdvertiserData> advertiserUserList=new ArrayList<>();
        List<AdvertiserData> advertiserUserMap = advertDao.getAdvertiserUserMap();
        for (AdvertiserData advertiser : advertiserData) {
            for (AdvertiserData user : advertiserUserMap) {
                AdvertiserData data = new AdvertiserData();
                data.setAdvertiserId(advertiser.getAdvertiserId());
                data.setAdvertiserName(advertiser.getAdvertiserName());
                data.setUserId(user.getUserId());
                advertiserUserList.add(data);
            }
        }
        advertDao.insertAdvertiserUserMap(advertiserUserList);
    }

    //从redis取数据存到mysql
    public void syncRedisMysql(){
        //从redis把所有广告商的总曝光和总点击取出来，存到advertiser_data_count
            //查所有的广告商id
        List<AdvertiserData> advertiserData = advertDao.getAdvertiserData();
            //从redis查点击和曝光
        for (AdvertiserData data : advertiserData) {
            getRedisExCli(data);
        }
        advertDao.insertAdvertiserDataCount(advertiserData);

        //从redis把所有广告商的分时广告查出来，存到advertiser_data_minutes
        advertiserData = advertDao.getAdvertiserData();
        for (AdvertiserData data : advertiserData) {
            List<AdvertiserData> exFromRedis = getExFromRedis(data);
            if(exFromRedis!=null){
                advertDao.insertAdvertDataMinuteEx(exFromRedis);
            }
            List<AdvertiserData> clFromRedis = getCliFromRedis(data);
            if(clFromRedis!=null){
                advertDao.insertAdvertDataMinuteCl(clFromRedis);
            }

        }
    }

    public void getRedisExCli(AdvertiserData advertiserData){
        String key="redisAdvertData:"+advertiserData.getAdvertiserId();
        Integer exposure=JedisHelper.hget(Integer.class,key,"exposure");
        Integer click=JedisHelper.hget(Integer.class,key,"click");
        advertiserData.setExposure(exposure);
        advertiserData.setClick(click);
    }

    //根据广告商id，从redis把该广告商下面的所有广告的曝光拿到
    public List<AdvertiserData> getExFromRedis(AdvertiserData advertiserData){
        String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String exposureKey="redisAdvertDataDayExposure:"+date+":"+advertiserData.getAdvertiserId();
        Map<String, Integer> exposureMap = JedisHelper.hgetAll(Integer.class, exposureKey);
        if(exposureMap.isEmpty()){
            return null;
        }
        List<String> minutesCodeIdExposure = mapToList(exposureMap);
        List<AdvertiserData> list=new ArrayList<>();
        for (String s : minutesCodeIdExposure) {
            AdvertiserData data = new AdvertiserData();
            data.setReportDate(date);
            data.setAdvertiserId(advertiserData.getAdvertiserId());
            data.setAdvertiserName(advertiserData.getAdvertiserName());
            data.setMinutes(s.split(",")[0]);
            data.setCodeId(s.split(",")[1]);
            data.setExposure(Integer.valueOf(s.split(",")[2]));
            list.add(data);
        }
        return list;
    }

    //根据广告商id，从redis把该广告商下面的所有点击拿到
    public List<AdvertiserData> getCliFromRedis(AdvertiserData advertiserData){
        String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String clickKey="redisAdvertDataDayClick:"+date+":"+advertiserData.getAdvertiserId();
        Map<String, Integer> clickMap = JedisHelper.hgetAll(Integer.class, clickKey);
        if(clickMap.isEmpty()){
            return null;
        }
        List<String> minutesCodeIdClick = mapToList(clickMap);
        List<AdvertiserData> list=new ArrayList<>();
        for (String s : minutesCodeIdClick) {
            AdvertiserData data = new AdvertiserData();
            data.setReportDate(date);
            data.setAdvertiserId(advertiserData.getAdvertiserId());
            data.setAdvertiserName(advertiserData.getAdvertiserName());
            data.setMinutes(s.split(",")[0]);
            data.setCodeId(s.split(",")[1]);
            data.setClick(Integer.valueOf(s.split(",")[2]));
            list.add(data);
        }
        return list;
    }

    private JSONObject getRedisChartInfo(Integer advertiserId,String advertId){
        JSONObject jsonObject = new JSONObject();
        String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String clickKey="redisAdvertDataDayClick:"+date+":"+advertiserId;
        Map<String, Integer> clickMap = JedisHelper.hgetAll(Integer.class, clickKey);
        List<String> minutesCodeIdClick = mapToList(clickMap);
        String exposureKey="redisAdvertDataDayExposure:"+date+":"+advertiserId;
        Map<String, Integer> exposureMap = JedisHelper.hgetAll(Integer.class, exposureKey);
        List<String> minutesCodeIdExposure = mapToList(exposureMap);
        if(advertId.equals("all")){
            Map<String, List<String>> click = minutesCodeIdClick.stream().collect(Collectors.groupingBy(x -> x.split(",")[0]));
            Map<String, List<String>> exposure = minutesCodeIdExposure.stream().collect(Collectors.groupingBy(x -> x.split(",")[0]));
            JSONObject resultClick = sumByKey(click);
            JSONObject resultExposure = sumByKey(exposure);
            Map emap=resultExposure.getObject("map",Map.class);
            Map cmap=resultClick.getObject("map",Map.class);
            Set keySet = emap.keySet();
            for (Object o : keySet) {
                if(!cmap.containsKey(o)){
                    cmap.put(o,0);
                }
            }
            jsonObject.put("dataTime",resultExposure.get("dataTime"));
            jsonObject.put("click",sortMap(cmap));
            jsonObject.put("exposure",resultExposure.get("sum"));
        }else {
            Map<String, List<String>> click = minutesCodeIdClick.stream().filter(x->x.split(",")[1].equals(advertId)).collect(Collectors.groupingBy(x -> x.split(",")[0]));
            Map<String, List<String>> exposure = minutesCodeIdExposure.stream().filter(x->x.split(",")[1].equals(advertId)).collect(Collectors.groupingBy(x -> x.split(",")[0]));
            JSONObject resultClick = sumByKey(click);
            JSONObject resultExposure = sumByKey(exposure);
            Map emap=resultExposure.getObject("map",Map.class);
            Map cmap=resultClick.getObject("map",Map.class);
            Set keySet = emap.keySet();
            for (Object o : keySet) {
                if(!cmap.containsKey(o)){
                    cmap.put(o,0);
                }
            }
            jsonObject.put("dataTime",resultExposure.get("dataTime"));
            jsonObject.put("click",sortMap(cmap));
            jsonObject.put("exposure",resultExposure.get("sum"));
        }
        return jsonObject;
    }

    public static List mapToList(Map<String, Integer> map){
        List<String> list=new ArrayList();
        Iterator it=map.keySet().iterator();
        while(it.hasNext()){
            String key=it.next().toString();
            Integer value = map.get(key);
            list.add(key+","+value);
        }
        return list;
    }

    public static List<Integer> sortMap(Map map){
        Object[] objects = map.keySet().toArray();
        Arrays.sort(objects);
        List<Integer> sum=new ArrayList<>();
        for(Object obj:objects){
            String key=obj.toString();
            Integer count=0;
            sum.add(Integer.valueOf(map.get(key).toString()));
        }
        return sum;
    }

    public static JSONObject sumByKey(Map<String, List<String>> map){
        Object[] objects = map.keySet().toArray();
        Arrays.sort(objects);
        JSONObject jsonObject = new JSONObject();
        List<String> dataTime=new ArrayList<>();
        List<Integer> sum=new ArrayList<>();
        //Iterator it=map.keySet().iterator();
        for(Object obj:objects){
            String key=obj.toString();
            dataTime.add(key.split(",")[0]);
            Integer count=0;
            List<String> list = map.get(key);
            for (String s : list) {
                Integer i = Integer.valueOf(s.split(",")[2]);
                count+=i;
            }
            sum.add(count);
        }
        HashMap<String, Integer> hashMap = new HashMap<>();
        for (int i=0;i<dataTime.size();i++){
            hashMap.put(dataTime.get(i),sum.get(i));
        }
        jsonObject.put("dataTime",dataTime);
        jsonObject.put("sum",sum);
        jsonObject.put("map",hashMap);
        return jsonObject;
    }

    public static JSONObject getMysqlChartInfo(List<AdvertiserData> advertExCl){
        JSONObject jsonObject = new JSONObject();
        List<String> dataTime=new ArrayList<>();
        List<Integer> exposure=new ArrayList<>();
        List<Integer> click=new ArrayList<>();
        for (AdvertiserData advertiserData : advertExCl) {
            if(advertiserData.getMinutes()!=null){
                dataTime.add(advertiserData.getMinutes());
            }else {
                dataTime.add(advertiserData.getReportDate());
            }
            exposure.add(advertiserData.getExposure());
            click.add(advertiserData.getClick());
        }
        jsonObject.put("dataTime",dataTime);
        jsonObject.put("exposure",exposure);
        jsonObject.put("click",click);
        return jsonObject;
    }
}
