package com.liangjian.dataplatform.member.service.impl;

import com.liangjian.dataplatform.member.dao.secondary.UserPointDescRepository;
import com.liangjian.dataplatform.member.dao.elasticsearch.UserPointLogRepository;
import com.liangjian.dataplatform.member.entity.po.secondary.UserPointDesc;
import com.liangjian.dataplatform.member.entity.po.elasticsearch.UserPointLog;
import com.liangjian.dataplatform.member.entity.pojo.BirdGirdFilter;
import com.liangjian.dataplatform.member.entity.vo.request.BirdGirdRequest;
import com.liangjian.dataplatform.member.entity.vo.response.BirdGirdTableResponse2;
import com.liangjian.dataplatform.member.service.BirdGirdQueryRequest;
import com.liangjian.dataplatform.member.service.IUserPointLogService;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
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.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.Predicate;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: 黄子奇
 * @Date: 2019/11/15
 */
@Service
public class UserPointLogService implements IUserPointLogService, BirdGirdQueryRequest<UserPointLog> {
    @Autowired
    private UserPointLogRepository userPointLogRepository;
    @Autowired
    private UserPointDescRepository userPointDescRepository;
    @Autowired
    private ElasticsearchRestTemplate elasticsearchTemplate;
    @Autowired
    private SecretEncodeDecodeService secretEncodeDecodeService;

    @PersistenceContext
    private EntityManager em;

    @Override
    public UserPointDesc getUserPointDesc() {
        List<UserPointDesc> descs = userPointDescRepository.findAll();
        if(descs.isEmpty()) {
            return new UserPointDesc();
        } else {
            return descs.get(0);
        }
    }

    @Override
    public boolean setUserPointDesc(UserPointDesc userPointDesc) {
        List<UserPointDesc> all = userPointDescRepository.findAll();
        try {
            if (all.isEmpty()) {
                userPointDescRepository.saveWithCycle(userPointDesc);
            } else {
                userPointDesc.setId(all.get(0).getId());
                userPointDescRepository.saveWithCycle(userPointDesc);
            }
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }

    @Override
    public BirdGirdTableResponse2<UserPointLog> queryByCondition(BirdGirdRequest request) {
        Integer page = request.getPageIndex();
        Integer size = request.getPageSize();
        Pageable pageable = PageRequest.of(page,size, Sort.Direction.DESC,"crtDate");

        List<BirdGirdFilter> filters = request.getFilters().stream()
                .filter(i -> i.getValue() != null && !i.getValue().isEmpty())
                .peek(i -> {
                    if(i.getField().equals("secretPhone")) {
                        //有传上来的话就是个明文的
                        String secretPhone = secretEncodeDecodeService.encode(i.getValue());
                        i.setValue(secretPhone);
                    }
                })
                .collect(Collectors.toList());
        request.setFilters(filters);
        BoolQueryBuilder qb = request.filtersToEsQuery();
        SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(qb).withPageable(pageable).build();
        Page<UserPointLog> paged = elasticsearchTemplate.queryForPage(searchQuery,UserPointLog.class);
        BirdGirdTableResponse2<UserPointLog> response2 = new BirdGirdTableResponse2<>(paged.getContent(),paged.getTotalElements());
        return response2;
    }

    @Override
    @Deprecated
    public Page<UserPointLog> queryByCondition( String terminal, String terminalCode, String action, Date startTime, Date endTime, Integer page, Integer size) {
//        Pageable pageable = PageRequest.of(page,size, Sort.Direction.DESC,"crtDate");
//
//        Specification<UserPointLog> specification = (Specification<UserPointLog>) (root, criteriaQuery, criteriaBuilder) -> {
//            List<Predicate> list = new ArrayList<>();
//            if(terminal != null) {
//                list.add(criteriaBuilder.like(root.get("terminalNName").as(String.class),"%"+terminal+"%"));
//            }
//            if(terminalCode != null) {
//                list.add(criteriaBuilder.equal(root.get("terminalCode").as(String.class), terminalCode));
//            }
//            if(action != null) {
//                list.add(criteriaBuilder.like(root.get("action").as(String.class), action));
//            }
//            if(startTime != null && endTime != null)  {
//                list.add(criteriaBuilder.ge(root.get("crtDate").as(Long.class), startTime.getTime()));
//                list.add(criteriaBuilder.le(root.get("crtDate").as(Long.class), endTime.getTime()));
//            }
//            return criteriaBuilder.and(list.toArray(new Predicate[list.size()]));
//        };
//        Page<UserPointLog> logs = userPointLogRepository.findAll(specification,pageable);
//        return logs;
        return null;
    }

    @Override
    public Page<UserPointLog> queryBySecretPhone(String secretPhone, Integer page, Integer size) {
        Pageable pageable = PageRequest.of(page,size, Sort.Direction.DESC,"crtDate");
        return userPointLogRepository.findBySecretPhone(secretPhone,pageable);
    }

    @Override
    public Page<UserPointLog> queryBySecretPhoneAndIncrease(String secretPhone, boolean increase, Integer page, Integer size) {
        Pageable pageable = PageRequest.of(page,size, Sort.Direction.DESC,"crtDate");
        return userPointLogRepository.findBySecretPhoneAndIncrease(secretPhone,increase,pageable);
    }

    @Override
    public UserPointLog getLastLog(String secretPhone) {
        Page<UserPointLog> page = queryBySecretPhone(secretPhone,0,1);
        List<UserPointLog> list = page.getContent();
        return list.isEmpty() ? null : list.get(0);
    }

    @Override
    public Integer getPointBalance(String secretPhone) {
        UserPointLog log = getLastLog(secretPhone);
        return log == null ? 0 : log.getBalance();
    }

    @Override
    public boolean addLog(UserPointLog log) {
        try {
            log.setLastUpdate(new Date());
            userPointLogRepository.save(log);
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }

    private List<UserPointLog> getLastDayLogs(String secretPhone) {
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH) + 1;
        int day = calendar.get(Calendar.DATE) + 1;
        String todayStr = year + "/" + month + "/" + day;
        Date today = new Date(todayStr);
        Long yesterdayTime = today.getTime() - (1000 * 60 * 60 * 24L);
        Date yesterday = new Date(yesterdayTime);

        List<UserPointLog> logs = userPointLogRepository.findBySecretPhoneAndCrtDateAfterAndCrtDateBeforeOrderByCrtDateDesc(secretPhone,yesterday.getTime(),today.getTime());
        return logs;
    }

    @Override
    public UserPointLog getLastDayLog(String secretPhone) {
        List<UserPointLog> logs = getLastDayLogs(secretPhone);
        if(logs.isEmpty()) {
            return null;
        } else {
            return logs.get(logs.size() - 1);
        }
    }

    @Override
    public List<UserPointLog> getLastDayLogList(String secretPhone) {
        List<UserPointLog> logs = getLastDayLogs(secretPhone);
        if(logs.isEmpty()) {
            return logs;
        } else {
            return logs.subList(0, logs.size() - 1);
        }
    }

    @Override
    public List<UserPointLog> queryBySecretPhones(List<String> secretPhones) {
        String sql = "SELECT *, max(crt_date) from mem_user_point_log where secret_phone in (%s) group by secret_phone";
        String phones = secretPhones.stream().reduce((i,j) -> i+","+j).orElse("no_phone_code");
        sql = String.format(sql,phones);
        return em.createNativeQuery(sql, UserPointLog.class).getResultList();
    }

    @Override
    @Deprecated
    public List<Map<String, Object>> relatedWithMember(List<Map<String, Object>> members, List<UserPointLog> logs) {
        Map<String, UserPointLog> map = logs.stream().collect(Collectors.toMap(l -> l.getSecretPhone(), l -> l));
        members = members.stream().peek(member -> {
            String phone = (String) member.get("MemPhone");
            UserPointLog log = map.get(phone);
            Integer balance = log.getBalance();
            if(balance == null)
                balance = 0;
            member.put("creditBalance", balance.toString());
        }).collect(Collectors.toList());

        return members;
    }

    @Override
    @Deprecated
    public List<Map<String, Object>> relatedWithMember(List<Map<String, Object>> members) {
        List<String> phones = members.stream()
                .flatMap(i -> {
                    List<String> accountPhone = new ArrayList<>();
                    accountPhone.add((String) i.getOrDefault("MemPhone1",""));
                    accountPhone.add((String) i.getOrDefault("MemPhone2",""));
                    accountPhone.add((String) i.getOrDefault("MemPhone3",""));
                    accountPhone.add((String) i.getOrDefault("PatientPhone",""));
                    accountPhone.add((String) i.getOrDefault("Phone1",""));
                    accountPhone.add((String) i.getOrDefault("Phone2",""));
                    accountPhone.add((String) i.getOrDefault("Phone3",""));
                    return accountPhone.stream();
                })
                .filter(i -> i != null && !i.isEmpty())
                .collect(Collectors.toList());
        List<UserPointLog> userPointLogs = queryBySecretPhones(phones);
        return relatedWithMember(members, userPointLogs);
    }

    @Override
    public Page<UserPointLog> queryByConditionOneUser(String secretPhone) {

        Page<UserPointLog> logs = userPointLogRepository.findBySecretPhone(secretPhone,PageRequest.of(0,1));

        return logs;
    }

    @Override
    public Page<UserPointLog> queryByConditionOneUserV3(String secretPhone,Integer pageIndex,Integer pageSize) {

        Pageable pageable = PageRequest.of(pageIndex,pageSize, Sort.Direction.DESC,"crtDate");
        Page<UserPointLog> logs = userPointLogRepository.findBySecretPhone(secretPhone,pageable);

        return logs;
    }

    @Override
    public boolean addPointLog(UserPointLog log) {
        log.setId(null);
        UserPointLog lastLog = getLastLog(log.getSecretPhone());
        log.setBalance(log.getValue() + lastLog.getBalance());
        log.setOrigin(lastLog.getBalance());
        return addLog(log);
    }

}
