package com.m2pool.manage.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.m2pool.common.core.Result.R;
import com.m2pool.common.core.constant.HttpStatus;
import com.m2pool.common.core.utils.DateUtils;
import com.m2pool.common.core.utils.StringUtils;
import com.m2pool.common.core.web.page.TableDataInfo;
import com.m2pool.manage.dto.*;
import com.m2pool.manage.mapper.ManageBroadcastMapper;
import com.m2pool.manage.mapper.ManageWalletOutInMapper;
import com.m2pool.manage.service.ManageUserService;
import com.m2pool.manage.utils.PowerUnitUtils;
import com.m2pool.manage.vo.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;


/**
 * @Description 广播信息 服务实现类
 */
@Service
public class ManageUserServiceImpl implements ManageUserService {

    @Resource
    private ManageBroadcastMapper manageBroadcastMapper;

    @Resource
    private ManageWalletOutInMapper manageWalletOutInMapper;

    @Resource
    private JavaMailSenderImpl javaMailSender;

    @Value("${spring.mail.username}")
    private String sendMailer;
    @Override
    public TableDataInfo<ManageUserDto> listInfo(ManageUserVo manageUserVo) {
        PageHelper.startPage(manageUserVo.getPageNum(), manageUserVo.getPageSize());
        List<ManageUserDto> manageUserDtos = manageBroadcastMapper.selectUserListByPage(manageUserVo.getCoin(), manageUserVo.getUser(), manageUserVo.getMinerUser());
        return getDataTable(manageUserDtos);
    }

    private TableDataInfo<ManageUserDto> getDataTable(List<ManageUserDto> list)
    {
        TableDataInfo<ManageUserDto> rspData = new TableDataInfo<>();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setRows(list);
        rspData.setMsg("查询成功");
        PageInfo<ManageUserDto> pageInfo = new PageInfo<>(list);
        rspData.setTotal(pageInfo.getTotal());
        rspData.setTotalPage(pageInfo.getPages());
        PageHelper.clearPage();
        return rspData;
    }

    private static final Pattern EMAIL_PATTERN = Pattern.compile("^[\\w-.]+@([\\w-]+\\.)+[\\w-]{2,4}$");
    @Override
    public R<String> sendTextMailMessage(String to,String subject,String text){
        try {
            //true 代表支持复杂的类型
            MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(javaMailSender.createMimeMessage(),true);
            //邮件发信人
            mimeMessageHelper.setFrom(sendMailer);
            String[] split = to.split("[,;；，\\s]+");
            for (String s : split) {
                if (!EMAIL_PATTERN.matcher(s).matches()) {
                    return R.fail("邮箱格式错误"+s);
                }
            }
            //邮件收信人  1或多个
            mimeMessageHelper.setTo(split);

            //邮件主题
            mimeMessageHelper.setSubject(subject);
            //邮件内容
            mimeMessageHelper.setText(text);
            //邮件发送时间
            mimeMessageHelper.setSentDate(new Date());

            //发送邮件
            javaMailSender.send(mimeMessageHelper.getMimeMessage());
            //System.out.println("发送邮件成功："+sendMailer+"->"+to);
            return R.success("发送成功");
        } catch (Exception e) {
            e.printStackTrace();
            return R.fail("发送失败"+e.getMessage());
            //System.out.println("发送邮件失败："+e.getMessage());
        }
    }

    @Override
    public R<WalletEarningsInfoDto> getUserInfo(ManageUserInfoVo manageUserInfoVo) {
        //获取账户余额 = 收入 - 支出
        BigDecimal accountIncome = manageBroadcastMapper.getAccountIncome(manageUserInfoVo.getMinerUser(), manageUserInfoVo.getCoin());
        BigDecimal accountExpend = manageBroadcastMapper.getAccountExpend(manageUserInfoVo.getMinerUser(), manageUserInfoVo.getCoin());
        BigDecimal accountBalance = accountIncome.subtract(accountExpend);

        //获取挖矿账户历史收益记录
        List<ManageUserInfoDto> walletInInfo = manageBroadcastMapper.getUserInfo(manageUserInfoVo.getMinerUser(), manageUserInfoVo.getCoin(), manageUserInfoVo.getStartDate(), manageUserInfoVo.getEndDate());
        //获取挖矿账户历史地址
        List<HistoryBalanceDto> historyBalance = manageBroadcastMapper.getHistoryBalance(manageUserInfoVo.getMinerUser(), manageUserInfoVo.getCoin());
        WalletEarningsInfoDto manageUserInfoDto = new WalletEarningsInfoDto(accountBalance,historyBalance,walletInInfo);
        return R.success(manageUserInfoDto);
    }


    @Override
    public R<List<ManageMiningUserDto>> getMiningUserInfo(ManageMiningUserVo manageMiningUserVo) {
        List<ManageMiningUserDto> miningUserInfo = manageBroadcastMapper.getMiningUserInfo(manageMiningUserVo.getUser());
        return R.success(miningUserInfo);
    }

    @Override
    public R<List<ManageMiningUserPowerDto>> getMiningPowerInfo(ManageMiningUserPowerVo manageMiningUserPowerVo) {
        List<ManageMiningUserPowerDto> list = manageBroadcastMapper.getMiningPowerInfo(manageMiningUserPowerVo.getMinerUser()
                , manageMiningUserPowerVo.getCoin(), manageMiningUserPowerVo.getStartDate(), manageMiningUserPowerVo.getEndDate());
        ManageMiningUserPowerDto maxPv = list.stream().max(Comparator.comparing(ManageMiningUserPowerDto::getPv)).orElse(new ManageMiningUserPowerDto());
        PowerUnitUtils.NetPowerUnit powerUnit;
        if (!list.isEmpty()){
            powerUnit = PowerUnitUtils.getPowerUnit(maxPv.getPv().multiply(BigDecimal.valueOf(1000 * 1000)));
        }else{
            powerUnit = new PowerUnitUtils.NetPowerUnit("GH/S", BigDecimal.valueOf(1000 * 1000 * 1000));
        }
        changeUnit(powerUnit, list,BigDecimal.valueOf(1000 * 1000));
        Date endDate = manageMiningUserPowerVo.getEndDate();
        Date startDate = manageMiningUserPowerVo.getStartDate();
        if (manageMiningUserPowerVo.getStartDate()==null || manageMiningUserPowerVo.getEndDate()==null){
             endDate = DateUtils.getPreviousHalfHourOrFullHour(new Date());
             startDate = DateUtils.getOneMonthAgo(endDate);
        }

        list = fillMissingData(list,powerUnit.getUnit(),manageMiningUserPowerVo.getMinerUser(),startDate,endDate);
        return R.success(list);
    }

    /**
     * 单位转换
     * @param netPowerUnit
     * @param list
     * @param factor
     * @return
     */
    private void changeUnit(PowerUnitUtils.NetPowerUnit netPowerUnit, List<ManageMiningUserPowerDto> list,BigDecimal factor) {
        list.forEach(e -> {
            if(StringUtils.isNotNull(e.getPv())){
                e.setUnit(netPowerUnit.getUnit());
                e.setPv(e.getPv().multiply(factor).divide(netPowerUnit.getUnitValue(),2, RoundingMode.HALF_UP).stripTrailingZeros());
            }else {
                e.setUnit(netPowerUnit.getUnit());
                e.setPv(BigDecimal.valueOf(0));
            }
        });
    }

    /**
     * 数据补零 30分钟时间端
     * @param dataList
     * @return
     */
    public static List<ManageMiningUserPowerDto> fillMissingData(List<ManageMiningUserPowerDto> dataList,String unit,String minerUser,Date startTime,Date endTime) {
        List<ManageMiningUserPowerDto> resultList = new ArrayList<>();
        Calendar calendar = Calendar.getInstance();

        calendar.setTime(startTime);
        Map<Long, ManageMiningUserPowerDto> timeDataMap = new HashMap<>();
        for (ManageMiningUserPowerDto data : dataList) {
            timeDataMap.put(data.getDate().getTime(), data);
        }

        while (calendar.getTime().getTime() <= endTime.getTime()) {
            long currentTime = calendar.getTime().getTime();
            ManageMiningUserPowerDto data = timeDataMap.get(currentTime);
            if (data != null) {
                resultList.add(data);
            } else {
                resultList.add(new ManageMiningUserPowerDto(minerUser,calendar.getTime(), BigDecimal.valueOf(0), unit));
            }
            // 增加 30 分钟
            calendar.add(Calendar.MINUTE, 30);
        }

        return resultList;
    }

    @Override
    public R<List<ManageMiningUserOnlineDto>> getMinerUserOnlineStatus(ManageMiningUserPowerVo manageMiningUserPowerVo) {
        //查询挖矿账户对应的所有矿工在离线情况
        List<ManageMiningUserOnlineDto> minerUserOnlineStatus = manageBroadcastMapper.getMinerUserOnlineStatus(
                manageMiningUserPowerVo.getMinerUser(),
                manageMiningUserPowerVo.getCoin(),
                manageMiningUserPowerVo.getStartDate(),
                manageMiningUserPowerVo.getEndDate());
        Date endDate = manageMiningUserPowerVo.getEndDate();
        Date startDate = manageMiningUserPowerVo.getStartDate();
        if (manageMiningUserPowerVo.getStartDate()==null || manageMiningUserPowerVo.getEndDate()==null){
            endDate = DateUtils.getPreviousHalfHourOrFullHour(new Date());
            startDate = DateUtils.getOneMonthAgo(endDate);
        }

        return R.success(fillMissingOnlineData(minerUserOnlineStatus, startDate, endDate));
    }


    /**
     * 数据补零 30分钟时间端
     * @param dataList
     * @return
     */
    public static List<ManageMiningUserOnlineDto> fillMissingOnlineData(List<ManageMiningUserOnlineDto> dataList,Date startTime,Date endTime) {

        List<ManageMiningUserOnlineDto> resultList = new ArrayList<>();
        Calendar calendar = Calendar.getInstance();


        calendar.setTime(startTime);
        Map<Long, ManageMiningUserOnlineDto> timeDataMap = new HashMap<>();
        for (ManageMiningUserOnlineDto data : dataList) {
            timeDataMap.put(data.getDate().getTime(), data);
        }

        while (calendar.getTime().getTime() <= endTime.getTime()) {
            long currentTime = calendar.getTime().getTime();
            ManageMiningUserOnlineDto data = timeDataMap.get(currentTime);
            if (data != null) {
                resultList.add(data);
            } else {
                resultList.add(new ManageMiningUserOnlineDto(calendar.getTime(),0, 0));
            }
            // 增加 30 分钟
            calendar.add(Calendar.MINUTE, 30);
        }

        return resultList;
    }

    @Override
    public TableDataInfo<SummaryOfPendingPaymentsDto> summaryOfPendingPayments(PageVo pageVo) {
        PageHelper.startPage(pageVo.getPageNum(), pageVo.getPageSize());
        List<SummaryOfPendingPaymentsDto> summaryOfPendingPaymentsList = manageWalletOutInMapper.summaryOfPendingPayments();
        System.out.println("起付额:"+summaryOfPendingPaymentsList);
        //查询起付额
        List<SummaryOfPendingPaymentsDto> startPayments = manageBroadcastMapper.getStartPayments(summaryOfPendingPaymentsList);

        // 创建一个 Map 用于存储第二个集合中元素的 user 和 coin 组合对应的 startPayAmount  . 这里可以优化一下，防止多key报错，不过一般不出这个问题
        Map<String, BigDecimal> startPayAmountMap = startPayments.stream()
                .collect(Collectors.toMap(
                        dto -> dto.getUser() + "_" + dto.getCoin(),
                        SummaryOfPendingPaymentsDto::getStartPayAmount
                ));
        System.out.println("起付额22:"+startPayAmountMap);
        // 遍历第一个集合，根据 user 和 coin 从 Map 中查找对应的 startPayAmount 并填充
        for (SummaryOfPendingPaymentsDto dto : summaryOfPendingPaymentsList) {
            String key = dto.getUser() + "_" + dto.getCoin();
            dto.setStartPayAmount(startPayAmountMap.getOrDefault(key, BigDecimal.ZERO));
        }
        return getPageData(summaryOfPendingPaymentsList);
    }

    private TableDataInfo<SummaryOfPendingPaymentsDto> getPageData(List<SummaryOfPendingPaymentsDto> list)
    {
        TableDataInfo<SummaryOfPendingPaymentsDto> rspData = new TableDataInfo<>();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setRows(list);
        rspData.setMsg("查询成功");
        PageInfo<SummaryOfPendingPaymentsDto> pageInfo = new PageInfo<>(list);
        rspData.setTotal(pageInfo.getTotal());
        rspData.setTotalPage(pageInfo.getPages());
        PageHelper.clearPage();
        return rspData;
    }
}
