package com.friday.custody.service.basicService.impl;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.friday.custody.dao.FundIndexDailyQuoteInfoDao;
import com.friday.custody.entity.FundIndexDailyQuoteInfoEntity;
import com.friday.custody.enums.RetCodeEnum;
import com.friday.custody.exception.RRException;
import com.friday.custody.req.FundIndexDailyQuoteInfoReq;
import com.friday.custody.req.QueryDataReq;
import com.friday.custody.service.basicService.FundIndexDailyQuoteInfoService;
import com.friday.custody.service.basicService.PublicDataBasicService;
import com.friday.custody.service.logicService.DataProcessService;
import com.friday.custody.utils.PageUtil;
import com.friday.custody.utils.PageUtils;
import com.friday.custody.utils.Query;
import com.friday.custody.utils.R;
import com.friday.custody.vo.FundIndexDailyQuoteInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;


@Service("fundIndexDailyQuoteInfoService")
@Slf4j
public class FundIndexDailyQuoteInfoServiceImpl extends ServiceImpl<FundIndexDailyQuoteInfoDao, FundIndexDailyQuoteInfoEntity>
        implements FundIndexDailyQuoteInfoService, DataProcessService<FundIndexDailyQuoteInfoEntity>, PublicDataBasicService {

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<FundIndexDailyQuoteInfoEntity> page = this.page(
                new Query<FundIndexDailyQuoteInfoEntity>().getPage(params),
                new QueryWrapper<FundIndexDailyQuoteInfoEntity>()
        );
        return new PageUtils(page);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R saveData(String type, List<FundIndexDailyQuoteInfoEntity> datas) {
        if (CollectionUtils.isEmpty(datas)){
            return R.ok();
        }
        for (FundIndexDailyQuoteInfoEntity entity : datas) {
            entity.setUniqueKey(entity.getAdmin() + entity.getTrustNo() + entity.getTradingCode() + entity.getTradingDay());
        }
        List<FundIndexDailyQuoteInfoEntity> uniqueAccountInfoList = datas.stream().collect(Collectors.collectingAndThen
                (Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing
                        (FundIndexDailyQuoteInfoEntity::getUniqueKey))), ArrayList::new));

        List<String> rawUniqueKeyList = uniqueAccountInfoList
                .stream()
                .map(FundIndexDailyQuoteInfoEntity::getUniqueKey)
                .collect(Collectors.toList());

        String ukList = String.join("--", rawUniqueKeyList);
        if (CollectionUtils.isNotEmpty(rawUniqueKeyList)) {
            Set<String> uniqueKeySet = baseMapper.queryUniqueKeyList(rawUniqueKeyList);
            if (CollectionUtils.isNotEmpty(uniqueKeySet)) {
                baseMapper.deleteByUniqueKeys(uniqueKeySet);
            }
        }
        boolean saveStatus = this.saveBatch(uniqueAccountInfoList);
        if (!saveStatus) {
            log.error("save FundIndexDailyQuoteInfoEntity failed:{}", ukList);
        } else {
            log.info("save FundIndexDailyQuoteInfoEntity counts:{}", uniqueAccountInfoList.size());
        }
        return R.ok();
    }

    @Override
    public R queryData(QueryDataReq vo) {
        try {
            log.info("开始基金行情指数表...,租户信息为:{}", JSON.toJSONString(vo));
            //1 封装查询参数
            FundIndexDailyQuoteInfoReq fundIndexDailyQuoteInfoReq = JSON.parseObject(vo.getParams(), FundIndexDailyQuoteInfoReq.class);
            //1.1 封装分页查询参数
            Map<String, Object> pageParams = PageUtil.getPageParams(fundIndexDailyQuoteInfoReq);
            //1.2 封装查询参数
            QueryWrapper<FundIndexDailyQuoteInfoEntity> queryWrapper = new QueryWrapper<>();
            if (StringUtils.isNotBlank(fundIndexDailyQuoteInfoReq.getTradingCode())) {
                queryWrapper.eq("trading_code", fundIndexDailyQuoteInfoReq.getTradingCode());
            }
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
            Calendar c = Calendar.getInstance();
            //开始和结束时间都为空，默认为一年
            if (StringUtils.isBlank(fundIndexDailyQuoteInfoReq.getBeginDate()) && StringUtils.isBlank(fundIndexDailyQuoteInfoReq.getEndDate())) {
                c.setTime(new Date());
                c.add(Calendar.YEAR, -1);
                Date m = c.getTime();
                String beginYear = format.format(m);
                fundIndexDailyQuoteInfoReq.setBeginDate(beginYear);
                fundIndexDailyQuoteInfoReq.setEndDate(format.format(new Date()));
            }
            //开始不为空和结束时间为空，默认当天
            if (StringUtils.isBlank(fundIndexDailyQuoteInfoReq.getEndDate()) && StringUtils.isNotBlank(fundIndexDailyQuoteInfoReq.getBeginDate())) {
                c.setTime(format.parse(fundIndexDailyQuoteInfoReq.getBeginDate()));
                c.add(Calendar.YEAR, 1);
                Date m = c.getTime();
                String endYear = format.format(m);
                fundIndexDailyQuoteInfoReq.setBeginDate(fundIndexDailyQuoteInfoReq.getBeginDate());
                fundIndexDailyQuoteInfoReq.setEndDate(endYear);
            }
            //开始为空和结束时间不为空，默认结束时间往前推一年
            if (StringUtils.isNotBlank(fundIndexDailyQuoteInfoReq.getEndDate()) && StringUtils.isBlank(fundIndexDailyQuoteInfoReq.getBeginDate())) {
                c.setTime(format.parse(fundIndexDailyQuoteInfoReq.getEndDate()));
                c.add(Calendar.YEAR, -1);
                Date m = c.getTime();
                String beginYear = format.format(m);
                fundIndexDailyQuoteInfoReq.setBeginDate(beginYear);
            }
            try {
                LocalDate beginDate = LocalDate.parse(fundIndexDailyQuoteInfoReq.getBeginDate(), DateTimeFormatter.ofPattern("yyyyMMdd"));
                LocalDate endDate = LocalDate.parse(fundIndexDailyQuoteInfoReq.getEndDate(), DateTimeFormatter.ofPattern("yyyyMMdd"));
                Duration duration = Duration.between(beginDate.atTime(0, 0, 0), endDate.atTime(0, 0, 0));
                long days = duration.toDays(); //相差的天数
                if (days < 0) {
                    return R.error(RetCodeEnum.PARAM_ERROR.getCode(), "endDate早于beginDate");
                }
                if (days > 366) {
                    return R.error(RetCodeEnum.PARAM_ERROR.getCode(), "beginDate与endDate间隔的天数不能超过365天");
                }
            } catch (Exception e) {
                log.error("参数有误：beginDate :{" + fundIndexDailyQuoteInfoReq.getBeginDate() + "}, endDate :{" + fundIndexDailyQuoteInfoReq.getEndDate() + "}", e);
                return R.error(RetCodeEnum.PARAM_ERROR.getCode(), "beginDate或endDate格式不正确");
            }
            if (StringUtils.isNotBlank(fundIndexDailyQuoteInfoReq.getBeginDate())) {
                queryWrapper.ge("trading_day", fundIndexDailyQuoteInfoReq.getBeginDate());
            }
            if (StringUtils.isNotBlank(fundIndexDailyQuoteInfoReq.getEndDate())) {
                queryWrapper.lt("trading_day", fundIndexDailyQuoteInfoReq.getEndDate());
            }
            //（按交易代码tradingCode（若存在）、交易日期tradingDay（若存在）、托管人编码trustNo、admin 逆序排列）
            queryWrapper.orderBy(true, false, "trading_code", "trading_day", "trust_no", "admin");

            //2 执行检索
            IPage<FundIndexDailyQuoteInfoEntity> page = this.page(
                    new Query<FundIndexDailyQuoteInfoEntity>().getPage(pageParams),
                    queryWrapper
            );
            //封装数据
            PageUtils pageUtils = new PageUtils(page);
            List<FundIndexDailyQuoteInfoEntity> entities = page.getRecords();
            //entities 转vo;
            List<FundIndexDailyQuoteInfoVO> vos = new ArrayList<>();
            for (FundIndexDailyQuoteInfoEntity entity : entities) {
                vos.add(FundIndexDailyQuoteInfoVO.builder()
                        .windCode(entity.getWindCode())
                        .secuCode(entity.getSecuCode())
                        .tradingCode(entity.getTradingCode())
                        .secuAbbr(entity.getSecuAbbr())
                        .exchangeCode(entity.getExchangeCode())
                        .tradingDay(entity.getTradingDay())
                        .currency(entity.getCurrency())
                        .prevClosingPrice(Objects.isNull(entity.getPrevClosingPrice()) ? null : entity.getPrevClosingPrice().toString())
                        .openingPrice(Objects.isNull(entity.getOpeningPrice()) ? null : entity.getOpeningPrice().toString())
                        .highestPrice(Objects.isNull(entity.getHighestPrice()) ? null : entity.getHighestPrice().toString())
                        .lowestPrice(Objects.isNull(entity.getLowestPrice()) ? null : entity.getLowestPrice().toString())
                        .closingPrice(Objects.isNull(entity.getClosingPrice()) ? null : entity.getClosingPrice().toString())
                        .turnoverVol(Objects.isNull(entity.getTurnoverVol()) ? null : entity.getTurnoverVol().toString())
                        .turnoverVal(Objects.isNull(entity.getTurnoverVal()) ? null : entity.getTurnoverVal().toString())
                        .dayChange(Objects.isNull(entity.getDayChange()) ? null : entity.getDayChange().toString())
                        .dayChangeRate(Objects.isNull(entity.getDayChangeRate()) ? null : entity.getDayChangeRate().toString())
                        .pe(Objects.isNull(entity.getPe()) ? null : entity.getPe().toString())
                        .pb(Objects.isNull(entity.getPb()) ? null : entity.getPb().toString())
                        .afMarketVal(Objects.isNull(entity.getAfMarketVal()) ? null : entity.getAfMarketVal().toString())
                        .tMarketVal(Objects.isNull(entity.getTMarketVal()) ? null : entity.getTMarketVal().toString())
                        .marketFlag(entity.getMarketFlag())
                        .build());
            }
            pageUtils.setList(vos);
            log.info("基金行情指数表查询成功...");
            return R.ok("基金行情指数表查询成功").put("data", pageUtils);
        } catch (RRException rrException) {
            log.error("the QueryDataVo is :" + JSON.toJSONString(vo) + ".the fundIndexDailyQuoteInfoServiceImpl RRException is :", rrException);
            return R.error(RetCodeEnum.OPERATION_ERROR.getCode(), rrException.getMsg());
        } catch (Exception e) {
            log.error("the QueryDataVo is :" + JSON.toJSONString(vo) + ".the fundIndexDailyQuoteInfoServiceImpl Exception is :", e);
            return R.error(RetCodeEnum.OPERATION_ERROR.getCode(), "查询数据失败!");
        }
    }

    @Override
    public R updateData(String type, List<FundIndexDailyQuoteInfoEntity> datas) {
        return null;
    }
}