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 lwby_novel.advertiser a LEFT JOIN lwby_novel.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 date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String key="redisAdvertData:"+advertiserData.getAdvertiserId()+":"+date;
        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);
            List<String> dataTime = getDataTime();
            for (String s : dataTime) {
                String hour = s.split(":")[0];
                String key="";
                if(hour.equals("0")||hour.equals("1")||hour.equals("2")||hour.equals("3")||hour.equals("4")||hour.equals("5")||hour.equals("6")||hour.equals("7")||hour.equals("8")||hour.equals("9")){
                    key="0"+hour+":"+s.split(":")[1];
                }
                if(cmap.containsKey(key)){
                    Integer o = (Integer)cmap.get(key);
                    cmap.remove(key);
                    cmap.put(s,o);
                }
                if(emap.containsKey(key)){
                    Integer o = (Integer)emap.get(key);
                    emap.remove(key);
                    emap.put(s,o);
                }
                if(!cmap.containsKey(s)){
                    cmap.put(s,0);
                }
                if(!emap.containsKey(s)){
                    emap.put(s,0);
                }
            }
            jsonObject.put("dataTime",dataTime);
            jsonObject.put("click",sortMap(cmap));
            //jsonObject.put("exposure",resultExposure.get("sum"));
            jsonObject.put("exposure",sortMap(emap));
        }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);
            List<String> dataTime = getDataTime();
            for (String s : dataTime) {
                String hour = s.split(":")[0];
                String key="";
                if(hour.equals("0")||hour.equals("1")||hour.equals("2")||hour.equals("3")||hour.equals("4")||hour.equals("5")||hour.equals("6")||hour.equals("7")||hour.equals("8")||hour.equals("9")){
                    key="0"+hour+":"+s.split(":")[1];
                }
                if(cmap.containsKey(key)){
                    Integer o = (Integer)cmap.get(key);
                    cmap.remove(key);
                    cmap.put(s,o);
                }
                if(emap.containsKey(key)){
                    Integer o = (Integer)emap.get(key);
                    emap.remove(key);
                    emap.put(s,o);
                }
                if(!cmap.containsKey(s)){
                    cmap.put(s,0);
                }
                if(!emap.containsKey(s)){
                    emap.put(s,0);
                }
            }
            jsonObject.put("dataTime",dataTime);
            jsonObject.put("click",sortMap(cmap));
            jsonObject.put("exposure",sortMap(emap));
        }
        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();
        String[] stringArray = Arrays.copyOf(objects,objects.length, String[].class);
        bubblingSort(stringArray);
        //Arrays.sort(objects);
        List<Integer> sum=new ArrayList<>();
        for(String obj:stringArray){
            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();
        String[] stringArray = Arrays.copyOf(objects,objects.length, String[].class);
        bubblingSort(stringArray);
        //Arrays.sort(stringArray);
        JSONObject jsonObject = new JSONObject();
        List<String> dataTime=new ArrayList<>();
        List<Integer> sum=new ArrayList<>();
        //Iterator it=map.keySet().iterator();
        for(String obj:stringArray){
            String key=obj;
            dataTime.add(key);
            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<>();
        if(advertExCl.size()==0){
            dataTime=getDataTime();
            for (String s : dataTime) {
                exposure.add(0);
                click.add(0);
            }
            jsonObject.put("dataTime",dataTime);
            jsonObject.put("exposure",exposure);
            jsonObject.put("click",click);
            return jsonObject;
        }
        if(advertExCl.get(0).getMinutes()!=null){
            advertExCl.sort(new Comparator<AdvertiserData>() {
                @Override
                public int compare(AdvertiserData o1, AdvertiserData o2) {
                    return o1.compareTo(o2);
                }
            });
        }
        Map<String,Integer> emap=new HashMap<>();
        Map<String,Integer> cmap=new HashMap<>();

        for (AdvertiserData advertiserData : advertExCl) {
            if(advertiserData.getMinutes()!=null){
                String hour = advertiserData.getMinutes().split(":")[0];
                if(hour.equals("00")||hour.equals("01")||hour.equals("02")||hour.equals("03")||hour.equals("04")||hour.equals("05")||hour.equals("06")||hour.equals("07")||hour.equals("08")||hour.equals("09")){
                    if(hour.equals("00")){
                        emap.put("0:"+advertiserData.getMinutes().split(":")[1],advertiserData.getExposure());
                        cmap.put("0:"+advertiserData.getMinutes().split(":")[1],advertiserData.getClick());
                    }else {
                        emap.put(hour.split("0")[1]+":"+advertiserData.getMinutes().split(":")[1],advertiserData.getExposure());
                        cmap.put(hour.split("0")[1]+":"+advertiserData.getMinutes().split(":")[1],advertiserData.getClick());
                    }

                }else {
                    emap.put(advertiserData.getMinutes(),advertiserData.getExposure());
                    cmap.put(advertiserData.getMinutes(),advertiserData.getClick());
                }
            }else {
                dataTime.add(advertiserData.getReportDate());
            }
            exposure.add(advertiserData.getExposure());
            click.add(advertiserData.getClick());
        }
        if(advertExCl.get(0).getMinutes()!=null){
            dataTime=getDataTime();
            for (String s : dataTime) {
                if(!cmap.containsKey(s)){
                    cmap.put(s,0);
                }
                if(!emap.containsKey(s)){
                    emap.put(s,0);
                }
            }

            jsonObject.put("dataTime",dataTime);
            jsonObject.put("exposure",sortMap(emap));
            jsonObject.put("click",sortMap(cmap));
        }else {
            jsonObject.put("dataTime",dataTime);
            jsonObject.put("exposure",exposure);
            jsonObject.put("click",click);
        }

        return jsonObject;
    }

    public static List<String> getDataTime(){
        List<String> list = new ArrayList<>();
        for (int i=0;i<24;i++){
            for (int j=0;j<=55;j+=5){
                if(j==0||j==5){
                    list.add(i+":"+"0"+j);
                }else {
                    list.add(i+":"+j);
                }

            }
        }
        return list;
    }

    public static void bubblingSort(String[] arr) {
        int size = arr.length;
        for(int i = 0; i<size-1; i++) {
            for (int j = i+1; j<arr.length; j++) {
                if(compare(arr[i],arr[j])) {
                    String temp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = temp;
                }
            }
        }
    }

    public static boolean compare(String s1,String s2){
        Integer hour= Integer.valueOf(s1.split(":")[0]);
        Integer minute= Integer.valueOf(s1.split(":")[1]);
        Integer hour1= Integer.valueOf(s2.split(":")[0]);
        Integer minute1= Integer.valueOf(s2.split(":")[1]);
        if(hour>hour1){
            return true;
        }else if(hour<hour1){
            return false;
        }else if(hour==hour1&&minute>minute1){
            return true;
        }else {
            return false;
        }

    }

    public void calculationSchema(){
        //根据advert_data_count计算总收入、昨日收入、七日收入、30日收入插入到advertiser_data_count
        List<AdvertiserData> advertiserDataIncome = advertDao.getAdvertiserDataIncome();
        List<AdvertiserData> advertiserData = advertDao.getAdvertiserData();
        List<AdvertiserData> ad0=new ArrayList<>();
        boolean flag;
        for (AdvertiserData advertiserDatum : advertiserData) {
            flag=false;
            if(advertiserDataIncome.size()==0){
                ad0=advertiserData;
                break;
            }else {
                for (AdvertiserData data : advertiserDataIncome) {
                    if(data.getAdvertiserId().equals(advertiserDatum.getAdvertiserId())){
                        flag=true;
                    }
                }
                if(flag==false){
                    advertiserDatum.setIncome(0.0);
                    ad0.add(advertiserDatum);
                }
            }
        }
        if(advertiserDataIncome.size()>0){
            advertDao.insertAdvertiserDataIncome(advertiserDataIncome);
        }
        if(ad0.size()>0){
            advertDao.insertAdvertiserDataIncome(ad0);
        }


        List<AdvertiserData> advertiserDataTotalIncome = advertDao.getAdvertiserDataTotalIncome();
        if(advertiserDataTotalIncome.size()>0){
            advertDao.insertAdvertiserDataTotalIncome(advertiserDataTotalIncome);
        }

        List<AdvertiserData> advertiserDataSevenIncome = advertDao.getAdvertiserDataSevenIncome();
        if(advertiserDataSevenIncome.size()>0){
            advertDao.insertAdvertiserDataSevenIncome(advertiserDataSevenIncome);
        }
        ad0.clear();
        for (AdvertiserData advertiserDatum : advertiserData) {
            flag=false;
            if(advertiserDataSevenIncome.size()==0){
                ad0=advertiserData;
                break;
            }else {
                for (AdvertiserData data : advertiserDataSevenIncome) {
                    if(data.getAdvertiserId().equals(advertiserDatum.getAdvertiserId())){
                        flag=true;
                    }
                }
                if(flag==false){
                    advertiserDatum.setIncomeSeven(0.0);
                    ad0.add(advertiserDatum);
                }
            }
        }
        if(ad0.size()>0){
            advertDao.insertAdvertiserDataSevenIncome(ad0);
        }


        List<AdvertiserData> advertiserDataThirtyIncome = advertDao.getAdvertiserDataThirtyIncome();
        if(advertiserDataThirtyIncome.size()>0){
            advertDao.insertAdvertiserDataThirtyIncome(advertiserDataThirtyIncome);
        }
        ad0.clear();
        for (AdvertiserData advertiserDatum : advertiserData) {
            flag=false;
            if(advertiserDataThirtyIncome.size()==0){
                ad0=advertiserData;
                break;
            }else {
                for (AdvertiserData data : advertiserDataThirtyIncome) {
                    if(data.getAdvertiserId().equals(advertiserDatum.getAdvertiserId())){
                        flag=true;
                    }
                }
                if(flag==false){
                    advertiserDatum.setIncomeThirty(0.0);
                    ad0.add(advertiserDatum);
                }
            }
        }
        if(ad0.size()>0){
            advertDao.insertAdvertiserDataThirtyIncome(ad0);
        }

    }
}
