package shop.alien.second.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import shop.alien.entity.second.SecondRiskControlRecord;
import shop.alien.entity.second.SecondTradeOperation;
import shop.alien.entity.second.SecondTradeRecord;
import shop.alien.entity.second.vo.SecondTradeRecordVo;
import shop.alien.mapper.second.SecondRiskControlRecordMapper;
import shop.alien.mapper.second.SecondTradeOperationMapper;
import shop.alien.mapper.second.SecondTradeRecordMapper;
import shop.alien.second.service.PlatformSecondTradeService;
import shop.alien.second.service.SecondGoodsService;

import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
public class PlatformSecondTradeServiceImpl extends ServiceImpl<SecondTradeRecordMapper, SecondTradeRecord> implements PlatformSecondTradeService {

    @Autowired
    private SecondTradeRecordMapper secondTradeRecordMapper;
    @Autowired
    private SecondTradeOperationMapper secondTradeOperationMapper;
    @Autowired
    private SecondRiskControlRecordMapper secondRiskControlRecordMapper;
    @Lazy
    @Autowired
    private SecondGoodsService secondGoodsService;

    @Override
    public IPage<SecondTradeRecordVo> getTradeRecordPage(SecondTradeRecordVo vo) throws Exception {
        try {
            Page<SecondTradeRecord> page = new Page<>(vo.getPageNum(), vo.getPageSize());
            QueryWrapper<SecondTradeRecord> wrapper = new QueryWrapper<>();
            wrapper.like(null != vo.getGoodsId(), "trade.goods_id", vo.getGoodsId());
            wrapper.like(StringUtils.isNotBlank(vo.getTradeNo()), "trade.trade_no", vo.getTradeNo());
            wrapper.eq(null != vo.getTradeStatus(), "trade.trade_status", vo.getTradeStatus());
            wrapper.eq("trade.delete_flag", 0);
            wrapper.orderByDesc("trade.created_time");
            return secondTradeRecordMapper.getTradeRecordPage(page, wrapper);
        } catch (Exception e) {
            log.error("PlatformSecondTradeServiceImpl.getTradeRecordPage(): Error Msg={}", e.getMessage());
            throw new Exception(e);
        }
    }

    @Override
    public List<SecondTradeRecordVo> getTradeRecordList(Integer userId, String beginTime, String endTime) throws Exception {
        try {
            Page<SecondTradeRecord> page = new Page<>(1, 1000000);
            QueryWrapper<SecondTradeRecord> wrapper = new QueryWrapper<>();
            wrapper.eq("trade.delete_flag", 0);
            wrapper.eq("trade.trade_status", 4);
            wrapper.ge("trade.transaction_time", StringUtils.isEmpty(beginTime) ? "1970-01-01 00:00:00" : beginTime);
            wrapper.le("trade.transaction_time", StringUtils.isEmpty(endTime) ? "9999-12-31 23:59:59" : endTime);
            wrapper.apply(" (trade.buyer_id = " + userId + " or trade.seller_id = " + userId + ") ");
            wrapper.orderByDesc("trade.created_time");
            List<SecondTradeRecordVo> voList = secondTradeRecordMapper.getTradeRecordPage(page, wrapper).getRecords();
            for (SecondTradeRecordVo item : voList) {
                item.setOperationJsonList(getOperationJsonList(item.getId()));
            }
            return voList;
        } catch (Exception e) {
            log.error("PlatformSecondTradeServiceImpl.getTradeRecordList(): Error Msg={}", e.getMessage());
            throw new Exception(e);
        }
    }

    @Override
    public SecondTradeRecordVo getTradeRecordById(Integer id) throws Exception {
        try {
            // 交易信息
            SecondTradeRecordVo vo = secondTradeRecordMapper.getTradeRecordById(id);
            // 交易流程
            vo.setOperationJsonList(getOperationJsonList(id));
            // 商品信息
            vo.setGoodsInfo(secondGoodsService.dealSecondGoodsRecordInfo(vo.getGoodsRecordId()));
            return vo;
        } catch (Exception e) {
            log.error("PlatformSecondTradeServiceImpl.getTradeRecordById(): Error Msg={}", e.getMessage());
            throw new Exception(e);
        }
    }

    @Override
    public List<JSONObject> getOperationJsonList(Integer tradeId) throws Exception {
        try {
            List<JSONObject> operationJsonList = new ArrayList<>();
            SecondTradeRecord record = secondTradeRecordMapper.selectById(tradeId);
            List<SecondTradeOperation> operationList = secondTradeOperationMapper.selectList(
                    new QueryWrapper<SecondTradeOperation>().eq("trade_id", tradeId).eq("delete_flag", 0));

            // 发起交易
            JSONObject createJson = new JSONObject();
            createJson.put("flag", 1);
            createJson.put("message", "发起交易");
            createJson.put("time", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(record.getCreatedTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()));
            operationJsonList.add(createJson);

            // 发起交易后取消交易
            if (operationList.size() == 2 && 7 == operationList.get(1).getType()) {
                JSONObject cancelJson = new JSONObject();
                cancelJson.put("flag", 1);
                cancelJson.put("message", "取消交易");
                cancelJson.put("time", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(operationList.get(1).getCreatedTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()));
                operationJsonList.add(cancelJson);
                return operationJsonList;
            }

            // 拒绝
            SecondTradeOperation refuse = operationList.stream().filter(item -> 2 == item.getType()).findFirst().orElse(null);
            if (null != refuse) {
                JSONObject refuseJson = new JSONObject();
                refuseJson.put("flag", 1);
                refuseJson.put("message", "拒绝交易");
                refuseJson.put("time", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(refuse.getCreatedTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()));
                operationJsonList.add(refuseJson);
                return operationJsonList;
            }

            // 确认
            SecondTradeOperation confirm = operationList.stream().filter(item -> 3 == item.getType()).findFirst().orElse(null);
            if (null != confirm) {
                JSONObject confirmJson = new JSONObject();
                confirmJson.put("flag", 1);
                confirmJson.put("message", "确认交易");
                confirmJson.put("time", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(confirm.getCreatedTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()));
                operationJsonList.add(confirmJson);
            } else {
                JSONObject confirmJson = new JSONObject();
                confirmJson.put("flag", 0);
                confirmJson.put("message", "等待确认交易");
                confirmJson.put("time", "");
                operationJsonList.add(confirmJson);
            }

            // 确认交易后取消交易
            if (operationList.size() == 3 && 7 == operationList.get(2).getType()) {
                JSONObject cancelJson = new JSONObject();
                cancelJson.put("flag", 1);
                cancelJson.put("message", "取消交易");
                cancelJson.put("time", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(operationList.get(2).getCreatedTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()));
                operationJsonList.add(cancelJson);
                return operationJsonList;
            }

            // 签到
            List<SecondTradeOperation> signIn = operationList.stream().filter(item -> 4 == item.getType()).sorted(Comparator.comparing(SecondTradeOperation::getCreatedTime)).collect(Collectors.toList());
            // 确认交易
            List<SecondTradeOperation> successFail = operationList.stream().filter(item -> (5 == item.getType() || 6 == item.getType()) && 0 != item.getUserId()).sorted(Comparator.comparing(SecondTradeOperation::getCreatedTime)).collect(Collectors.toList());
            // 系统确认的交易失败(超过交易时间12小时未确认成功失败,将自动视为失败)
            SecondTradeOperation systemFail = operationList.stream().filter(item -> 6 == item.getType() && 0 == item.getUserId()).findFirst().orElse(null);

            if (CollectionUtil.isEmpty(signIn)) {
                JSONObject signInJson = new JSONObject();
                signInJson.put("flag", CollectionUtil.isEmpty(successFail) && null == systemFail ? 0 : 2);
                signInJson.put("message", CollectionUtil.isEmpty(successFail) && null == systemFail ? "等待买方签到" : "买方未签到");
                signInJson.put("time", "");
                operationJsonList.add(signInJson);

                signInJson = new JSONObject();
                signInJson.put("flag", CollectionUtil.isEmpty(successFail) && null == systemFail ? 0 : 2);
                signInJson.put("message", CollectionUtil.isEmpty(successFail) && null == systemFail ? "等待卖方签到" : "卖方未签到");
                signInJson.put("time", "");
                operationJsonList.add(signInJson);
            } else {
                // 第一个人签到
                JSONObject signInJson = new JSONObject();
                signInJson.put("flag", 1);
                signInJson.put("message", (Objects.equals(record.getBuyerId(), signIn.get(0).getUserId()) ? "买家" : "卖家") + "已签到");
                signInJson.put("time", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(signIn.get(0).getCreatedTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()));
                operationJsonList.add(signInJson);

                // 第二个人签到
                if (signIn.size() > 1) {
                    JSONObject signInJson2 = new JSONObject();
                    signInJson2.put("flag", 1);
                    signInJson2.put("message", (Objects.equals(record.getBuyerId(), signIn.get(1).getUserId()) ? "买家" : "卖家") + "已签到");
                    signInJson2.put("time", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(signIn.get(1).getCreatedTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()));
                    operationJsonList.add(signInJson2);
                } else {
                    JSONObject signInJson2 = new JSONObject();
                    signInJson2.put("flag", CollectionUtil.isEmpty(successFail) ? 0 : 2);
                    signInJson2.put("message", (Objects.equals(record.getBuyerId(), signIn.get(0).getUserId()) ? "卖家" : "买家") + "未签到");
                    signInJson2.put("time", "");
                    operationJsonList.add(signInJson2);
                }
            }

            // 签到后取消交易
            if (CollectionUtil.isEmpty(successFail) && CollectionUtil.isNotEmpty(operationList) && 7 == operationList.get(operationList.size() - 1).getType()) {
                JSONObject cancelJson = new JSONObject();
                cancelJson.put("flag", 1);
                cancelJson.put("message", "取消交易");
                cancelJson.put("time", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(operationList.get(operationList.size() - 1).getCreatedTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()));
                operationJsonList.add(cancelJson);
                return operationJsonList;
            }

            // 确认交易
            if (CollectionUtil.isEmpty(successFail)) {
                JSONObject signInJson = new JSONObject();
                signInJson.put("flag", null == systemFail ? 0 : 2);
                signInJson.put("message", null == systemFail ? "等待买方确认交易" : "买方未确认交易");
                signInJson.put("time", "");
                operationJsonList.add(signInJson);

                signInJson = new JSONObject();
                signInJson.put("flag", null == systemFail ? 0 : 2);
                signInJson.put("message", null == systemFail ? "等待卖方确认交易" : "卖方未确认交易");
                signInJson.put("time", "");
                operationJsonList.add(signInJson);
            } else {
                // 第一个人确认交易
                JSONObject successFailJson = new JSONObject();
                successFailJson.put("flag", 1);
                successFailJson.put("message", (Objects.equals(record.getBuyerId(), successFail.get(0).getUserId()) ? "买家" : "卖家") + "确认交易" +
                        (5 == successFail.get(0).getType() ? "成功" : "失败"));
                successFailJson.put("time", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(successFail.get(0).getCreatedTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()));
                operationJsonList.add(successFailJson);

                // 第二个人确认交易
                if (successFail.size() > 1) {
                    JSONObject successFailJson2 = new JSONObject();
                    successFailJson2.put("flag", 1);
                    successFailJson2.put("message", (Objects.equals(record.getBuyerId(), successFail.get(1).getUserId()) ? "买家" : "卖家") + "确认交易" +
                            (5 == successFail.get(1).getType() ? "成功" : "失败"));
                    successFailJson2.put("time", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(successFail.get(1).getCreatedTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()));
                    operationJsonList.add(successFailJson2);
                } else {
                    JSONObject successFailJson2 = new JSONObject();
                    successFailJson2.put("flag", Objects.equals(record.getSellerId(), successFail.get(0).getUserId()) ? 2 : 0);
                    successFailJson2.put("message", (Objects.equals(record.getBuyerId(), successFail.get(0).getUserId()) ? "卖家" : "买家") + "未确认交易");
                    successFailJson2.put("time", "");
                    operationJsonList.add(successFailJson2);
                }
            }

            // 交易完成
            if (4 == record.getTradeStatus()) {
                JSONObject finishJson = new JSONObject();
                finishJson.put("flag", 1);
                finishJson.put("message", "交易成功");
                finishJson.put("time", "");
                operationJsonList.add(finishJson);
            } else if (5 == record.getTradeStatus()) {
                JSONObject finishJson = new JSONObject();
                finishJson.put("flag", 1);
                finishJson.put("message", "交易失败");
                finishJson.put("time", "");
                operationJsonList.add(finishJson);
            } else {
                JSONObject finishJson = new JSONObject();
                finishJson.put("flag", 0);
                finishJson.put("message", "交易成功");
                finishJson.put("time", "");
                operationJsonList.add(finishJson);
            }

            return operationJsonList;
        } catch (Exception e) {
            log.error("PlatformSecondTradeServiceImpl.getOperationJsonList Error Msg={}", e.getMessage());
            throw new Exception(e);
        }
    }

    @Override
    public List<JSONObject> getRankingList(String beginTime, String endTime) throws Exception {
        try {
            if (StringUtils.isBlank(beginTime)) beginTime = "1970-01-01 00:00:00";
            if (StringUtils.isBlank(endTime)) endTime = "9999-12-31 23:59:59";
            return secondTradeRecordMapper.getRankingList(beginTime, endTime);
        } catch (Exception e) {
            log.error("PlatformSecondTradeServiceImpl.getRankingList Error Msg={}", e.getMessage());
            throw new Exception(e);
        }
    }

    @Override
    public void setTradeFailure(Integer tradeId, String failureReason) throws Exception {
        try {
            LambdaUpdateWrapper<SecondTradeRecord> wrapper = new LambdaUpdateWrapper<>();
            wrapper.eq(SecondTradeRecord::getId, tradeId);
            wrapper.set(SecondTradeRecord::getFailureFlag, 1);
            wrapper.set(SecondTradeRecord::getFailureReason, failureReason);
            secondTradeRecordMapper.update(null, wrapper);
        } catch (Exception e) {
            log.error("PlatformSecondTradeServiceImpl.setTradeFailure Error Msg={}", e.getMessage());
            throw new Exception(e);
        }
    }

    @Override
    public List<SecondTradeRecordVo> getTradeRecordListByRiskId(Integer id) throws Exception {
        try {
            SecondRiskControlRecord record = secondRiskControlRecordMapper.selectById(id);
            Page<SecondTradeRecord> page = new Page<>(1, 1000000);
            QueryWrapper<SecondTradeRecord> wrapper = new QueryWrapper<>();
            wrapper.in("trade.id", JSONArray.parseArray(record.getDetailInfo()));
            List<SecondTradeRecordVo> voList = secondTradeRecordMapper.getTradeRecordPage(page, wrapper).getRecords();
            for (SecondTradeRecordVo item : voList) {
                item.setOperationJsonList(getOperationJsonList(item.getId()));
            }
            return voList;
        } catch (Exception e) {
            log.error("PlatformSecondTradeServiceImpl.getTradeRecordListByRiskId(): Error Msg={}", e.getMessage());
            throw new Exception(e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void bannedAccountCancelTrade(Integer userId) throws Exception {
        try {
            // 查询封禁信息
            LambdaQueryWrapper<SecondRiskControlRecord> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(SecondRiskControlRecord::getUserId, userId);
            wrapper.eq(SecondRiskControlRecord::getRuleType, 1);
            wrapper.eq(SecondRiskControlRecord::getRiskStatus, 0);
            List<SecondRiskControlRecord> list = secondRiskControlRecordMapper.selectList(wrapper);
            List<String> infoList = list.stream().map(SecondRiskControlRecord::getDetailInfo).collect(Collectors.toList());
            List<JSONArray> array = infoList.stream().map(JSONArray::parseArray).collect(Collectors.toList());
            List<Integer> idList = new ArrayList<>();
            for (JSONArray item : array) {
                idList.addAll(item.toJavaList(Integer.class));
            }
            idList = idList.stream().distinct().collect(Collectors.toList());

            // 查询需要取消的交易信息
            LambdaQueryWrapper<SecondTradeRecord> wrapper1 = new LambdaQueryWrapper<>();
            List<Integer> finalIdList = idList;
            wrapper1.eq(SecondTradeRecord::getTradeStatus, 3)
                    .and(item -> item.in(SecondTradeRecord::getId, finalIdList)
                            .or(io -> io.eq(SecondTradeRecord::getSellerId, userId)
                                    .between(SecondTradeRecord::getTransactionTime, LocalDate.now() + " 00:00:00", LocalDate.now().plusDays(7) + " 23:59:59")));
//                    .or(item -> item.eq(SecondTradeRecord::getSellerId, userId)
//                            .between(SecondTradeRecord::getTransactionTime, LocalDate.now() + " 00:00:00", LocalDate.now().plusDays(7) + " 23:59:59"));
            List<SecondTradeRecord> tradeList = secondTradeRecordMapper.selectList(wrapper1);
            List<Integer> tradeIds = tradeList.stream().map(SecondTradeRecord::getId).distinct().collect(Collectors.toList());

            if (CollectionUtil.isEmpty(tradeIds)) return;

            // 取消交易
            LambdaUpdateWrapper<SecondTradeRecord> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.in(SecondTradeRecord::getId, tradeIds);
            updateWrapper.set(SecondTradeRecord::getTradeStatus, 6);
            secondTradeRecordMapper.update(null, updateWrapper);

            // 添加交易操作记录
            for (Integer id : tradeIds) {
                SecondTradeOperation operation = new SecondTradeOperation();
                operation.setTradeId(id);
                operation.setUserId(0);
                operation.setType(7);
                secondTradeOperationMapper.insert(operation);
            }
        } catch (Exception e) {
            log.error("PlatformSecondTradeServiceImpl.bannedAccountCancelTrade(): Error Msg={}", e.getMessage());
            throw new Exception(e);
        }
    }

}
