package common.service.impl;

import common.model.AppInfo;
import common.repository.AppCategoryRepository;
import common.repository.AppInfoRepository;
import common.repository.CityRepository;
import common.service.AppService;
import common.task.ReportCallable;
import dmp.model.OtPkgDevStats;
import dmp.repository.OtPkgDevStatsRepository;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.collections.map.HashedMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import tkio.model.App;
import util.Constant;
import util.DBUtil;
import util.HttpClientUtil;
import util.StringUtil;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * Created by zxys on 2017/12/27.
 */
@Service
public class AppServiceImpl implements AppService
{

    @Autowired AppInfoRepository appInfoRepository;
    @Autowired AppCategoryRepository appCategoryRepository;
    @Autowired CityRepository cityRepository;
    @Autowired OtPkgDevStatsRepository otPkgDevStatsRepository;

    @Override
    public Map findAppList(AppInfo app, int pageNum, int pageSize, String sortString, Integer isASC, String searchString, String startDate, String endDate)
            throws ExecutionException, InterruptedException
    {
        pageNum = pageNum-1;
        ExecutorService pool = Executors.newFixedThreadPool(2);
        ReportCallable callableTotal = new ReportCallable(app,pageNum,pageSize,sortString,isASC,searchString,startDate,endDate, true);
        ReportCallable callableDimension = new ReportCallable(app,pageNum,pageSize,sortString,isASC,searchString,startDate,endDate, false);
        //执行任务并获取Future对象
        Future<Map<String, Object>> futureTotal = pool.submit(callableTotal);
        Future<Map<String, Object>> futureDimension = pool.submit(callableDimension);
        Map<String, Object> resultTotal = futureTotal.get();
        Map<String, Object> resultDimension = futureDimension.get();


        Map<String, Object> result = new HashMap<>();
        result.put("content", resultDimension.get("content"));
        result.put("totalElements", resultTotal.get("totalElements"));
        /*
        List<AppInfo> appList = new ArrayList<>();
        Page<AppInfo> appInfoPage = null;
        Specification<AppInfo> specification = getWhereClause(app, searchString);
        if (!StringUtil.isEmpty(sortString) && sortString.equals("new_device")) {
            appList = appInfoRepository.findAll(specification);
            result.put("totalElements", appList.size());
        } else {
            List<Sort.Order> orders = new ArrayList<Sort.Order>();
            if (StringUtil.isEmpty(sortString)) {
                sortString = "pkgName";
            }
            orders.add(new Sort.Order((isASC!=null && isASC==0)?Sort.Direction.DESC:Sort.Direction.ASC,sortString));
            Sort sort = new Sort(orders);
            Pageable pageable = new PageRequest(pageNum, pageSize, sort);
            appInfoPage = appInfoRepository.findAll(specification, pageable);
            result.put("content", appInfoPage.getContent());
            result.put("totalElements", appInfoPage.getTotalElements());
        }



        if (!StringUtil.isEmpty(sortString) && sortString.equals("new_device")) {
            List<String> pkgList = new ArrayList<>();
            Map<String, AppInfo> appMap = new HashMap<>();
            for (AppInfo appin : appList) {
                pkgList.add(appin.getPkgName());
                appMap.put(appin.getPkgName(), appin);
            }
            JSONArray values = findAppDataList(startDate, endDate, pkgList, isASC, pageNum*pageSize, pageSize);
            Map<String, Object> valueResult = new HashMap<>();
            List<String> pkgs = new ArrayList<>();
            for (int i=0; i<values.size(); i++) {
                JSONObject o = values.getJSONObject(i);
                valueResult.put(o.get("valueResult").toString(), o.get("new_device"));
                pkgs.add(o.get("valueResult").toString());
            }
            List<AppInfo> resultAppList = new ArrayList<>();

            for (String pkg : pkgs) {
                AppInfo ai = appMap.get(pkg);
                ai.setNewDevice(Long.getLong(valueResult.get(pkg).toString()));
                resultAppList.add(ai);
            }
            result.put("content", resultAppList);
            if (resultAppList.size() == 0) {
                result.put("totalElements", 0);
            }
        } else {

            List<String> pkgnameList = new ArrayList<>();
            for (AppInfo ai : appInfoPage) {
                pkgnameList.add(ai.getPkgName());
            }
            JSONArray values = findAppDataList(startDate, endDate, pkgnameList, null, null, null);
            Map<String, Object> valueResult = new HashMap<>();
            for (int i=0; i<values.size(); i++) {
                JSONObject o = values.getJSONObject(i);
                valueResult.put(o.get("valueResult").toString(), o.get("new_device"));
            }
            for (AppInfo ai : appInfoPage) {
                if (valueResult.containsKey(ai.getPkgName())) {
                    ai.setNewDevice(Long.getLong(valueResult.get(ai.getPkgName()).toString()));
                } else {
                    ai.setNewDevice(0L);
                }

            }
            result.put("content", appInfoPage.getContent());
            result.put("totalElements", appInfoPage.getTotalElements());
        }*/


        return result;
    }

    @Override
    public List<String> findAllCategoryByLevel(int level)
    {
        return appCategoryRepository.findCategoryByLevel(level);
    }

    @Override
    public List<String> findCity()
    {
        return cityRepository.findCitys();
    }

    @Override
    public JSONArray findAppDataList(String startDate, String endDate, List<String> pkgNameList, Integer isASC, Integer startNum, Integer size)
    {
//        Specification<OtPkgDevStats> specification = getWhereClause(pkgNameList, startDate, endDate);
//        List<Sort.Order> orders = new ArrayList<Sort.Order>();
//        orders.add(new Sort.Order((isASC!=null && isASC==0)?Sort.Direction.DESC:Sort.Direction.ASC,"devnum"));
//        Sort sort = new Sort(orders);
//        Pageable pageable = new PageRequest(pageNum-1, pageSize, sort);
//        otPkgDevStatsRepository.findAll(specification, pageable);


        Map<String, String> conditions = new HashedMap();
        String url = Constant.reportUrl + "/api/dmp/newdevicebypkgname/test";
        conditions.put("datatype", "list");
        conditions.put("startdate", startDate);
        conditions.put("enddate", endDate);
        if (startNum != null) {
            conditions.put("startnum", startNum.toString());
        }
        if (size != null) {
            conditions.put("size", size.toString());
        }

        if (pkgNameList != null && pkgNameList.size()>0) {
            conditions.put("pkgname", String.join(",", pkgNameList));
        }
        if (isASC != null) {
            conditions.put("isasc", isASC.toString());
        }
        String responseJson = HttpClientUtil.doHttpPostRequest(url, "manager", conditions);
        System.out.println(responseJson);
        JSONArray array = new JSONArray();
        JSONObject object = JSONObject.fromObject(responseJson);
        if (object.containsKey("content")) {
            JSONObject content = object.getJSONObject("content");
            if (content != null && content.containsKey("val")) {
                array = content.getJSONArray("val");
            }
        }

        return array;
    }

    /**
     * 动态生成where语句
     * @param appInfo
     * @return
     */
    private Specification<AppInfo> getWhereClause(final AppInfo appInfo, String searchString){
        return new Specification<AppInfo>() {
            @Override
            public Predicate toPredicate(Root<AppInfo> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicate = new ArrayList<>();
                if (appInfo.getReyun() != null) {
                    predicate.add(cb.equal(root.get("reyun").as(Integer.class), appInfo.getReyun()));
                }
                if (!StringUtil.isEmpty(appInfo.getLocation())) {
                    predicate.add(cb.equal(root.get("location").as(String.class), appInfo.getLocation()));
                }
                if (!StringUtil.isEmpty(appInfo.getFirstCate())) {
                    predicate.add(cb.equal(root.get("firstCate").as(String.class), appInfo.getFirstCate()));
                }
                if (!StringUtil.isEmpty(appInfo.getSecondCate())) {
                    predicate.add(cb.equal(root.get("secondCate").as(String.class), appInfo.getSecondCate()));
                }

                if (!StringUtil.isEmpty(searchString)) {
                    List<Predicate> innerPredicate = new ArrayList<>();
                    innerPredicate.add(cb.like(root.get("name").as(String.class), "%"+searchString+"%"));
                    innerPredicate.add(cb.like(root.get("company").as(String.class), "%"+searchString+"%"));
                    innerPredicate.add(cb.like(root.get("pkgName").as(String.class), "%"+searchString+"%"));
                    Predicate p = cb.or(innerPredicate.toArray(new Predicate[innerPredicate.size()]));
                    predicate.add(p);
                }
                Predicate[] pre = new Predicate[predicate.size()];
                query.where(predicate.toArray(pre));
                return query.getRestriction();
            }
        };
    }

    /**
     * 动态生成where语句
     * @param
     * @return
     */
    private Specification<OtPkgDevStats> getWhereClause(List<String> pkgList, String startDate, String endDate){
        return new Specification<OtPkgDevStats>() {
            @Override
            public Predicate toPredicate(Root<OtPkgDevStats> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicate = new ArrayList<>();



                CriteriaBuilder.In<String> in = cb.in(root.get("pkgname").as(String.class));
                for (String pkg : pkgList) {
                    in.value(pkg);
                }
                predicate.add(in);

                if (!StringUtil.isEmpty(startDate)) {
                    predicate.add(cb.greaterThanOrEqualTo(root.get("ds").as(String.class), startDate));
                }
                if (!StringUtil.isEmpty(endDate)) {
                    predicate.add(cb.lessThanOrEqualTo(root.get("ds").as(String.class), endDate));
                }
                Predicate[] pre = new Predicate[predicate.size()];
                query.multiselect(root.get("pkgname").as(String.class), cb.sum(root.get("devNum").as(Long.class)).alias("devnum"));
                query.where(predicate.toArray(pre));
                query.groupBy(root.get("pkgname").as(String.class));
                return query.getRestriction();
            }
        };
    }


}
