package shop.alien.second.service.impl;

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.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import shop.alien.entity.result.BusinessException;
import shop.alien.entity.second.SecondGoods;
import shop.alien.entity.second.SecondGoodsRecord;
import shop.alien.entity.second.SecondTradeOperation;
import shop.alien.entity.second.SecondTradeRecord;
import shop.alien.entity.second.vo.SecondTradeRecordVo;
import shop.alien.entity.store.LifeMessage;
import shop.alien.entity.store.LifeUser;
import shop.alien.entity.store.StoreDictionary;
import shop.alien.entity.store.vo.WebSocketVo;
import shop.alien.mapper.LifeMessageMapper;
import shop.alien.mapper.LifeUserMapper;
import shop.alien.mapper.StoreDictionaryMapper;
import shop.alien.mapper.second.SecondGoodsMapper;
import shop.alien.mapper.second.SecondGoodsRecordMapper;
import shop.alien.mapper.second.SecondTradeOperationMapper;
import shop.alien.mapper.second.SecondTradeRecordMapper;
import shop.alien.second.feign.AlienStoreFeign;
import shop.alien.second.service.SecondTradeRecordService;
import shop.alien.util.common.JwtUtil;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 二手交易记录表 服务实现类
 * </p>
 *
 * @author qrs
 * @since 2025-07-07
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordMapper, SecondTradeRecord> implements SecondTradeRecordService {

    private final SecondTradeRecordMapper secondTradeRecordMapper;
    private final SecondTradeOperationMapper secondTradeOperationMapper;
    private final SecondGoodsMapper secondGoodsMapper;
    private final SecondGoodsRecordMapper secondGoodsRecordMapper;
    private final LifeMessageMapper lifeMessageMapper;
    private final LifeUserMapper lifeUserMapper;
    private final AlienStoreFeign alienStoreFeign;
    private final StoreDictionaryMapper storeDictionaryMapper;

    private final Object lock = new Object();

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createTrade(SecondTradeRecord trade) throws Exception {
        try {
            synchronized (lock) {
                LocalDate now = LocalDate.now();
                LambdaQueryWrapper<SecondTradeRecord> wrapper = new LambdaQueryWrapper<>();
                wrapper.between(SecondTradeRecord::getCreatedTime, now + " 00:00:00", now + " 23:59:59");
                int count = secondTradeRecordMapper.selectCount(wrapper);
                String tradeNo = "S" + now.toString().replace("-", "") + String.format("%05d", count + 1);
                trade.setTradeNo(tradeNo);
            }
            LambdaQueryWrapper<SecondGoodsRecord> goodsWrapper = new LambdaQueryWrapper<>();
            goodsWrapper.eq(SecondGoodsRecord::getGoodsId, trade.getGoodsId());
            goodsWrapper.eq(SecondGoodsRecord::getGoodsStatus, "3");
            goodsWrapper.orderByDesc(SecondGoodsRecord::getCreatedTime);
            goodsWrapper.last(" limit 1 ");
            SecondGoodsRecord goodsRecord = secondGoodsRecordMapper.selectOne(goodsWrapper);
            if (null != goodsRecord) trade.setGoodsRecordId(goodsRecord.getId());
            // 保存交易记录
            secondTradeRecordMapper.insert(trade);

            // 保存交易操作表
            SecondTradeOperation operation = new SecondTradeOperation();
            operation.setTradeId(trade.getId());
            operation.setUserId(Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId"));
            operation.setType(1);
            operation.setCreatedTime(new Date());
            secondTradeOperationMapper.insert(operation);

            // 商品更新交易id
            SecondGoods goods = new SecondGoods();
            goods.setId(trade.getGoodsId());
            goods.setTradeId(trade.getId());
            secondGoodsMapper.updateById(goods);

            // 查询商品
            goods = secondGoodsMapper.selectById(trade.getGoodsId());

            // 发送消息
            sendMsg(goods, trade, 1, "4");

            return true;
        } catch (Exception e) {
            log.error("SecondTradeRecordServiceImpl.createTrade(): Error Msg={}", e.getMessage());
            throw new Exception(e);
        }
    }

    /**
     * 发送消息
     * @param goods        商品信息
     * @param trade        交易信息
     * @param tradeStatus  1-待确认  2-已拒绝  3-待交易  6-交易取消
     * @param messageType  4-二手交易创建/确认/拒绝/取消  5-二手交易签到提醒  6-二手交易已签到
     */
    @Transactional(rollbackFor = Exception.class)
    public void sendMsg(SecondGoods goods, SecondTradeRecord trade, Integer tradeStatus, String messageType) {
        // 封装交易信息
        JSONObject message = new JSONObject();
        message.put("title", goods.getTitle());
        message.put("goodsId", goods.getId());
        message.put("homeImage", goods.getHomeImage());
        message.put("tradeId", trade.getId());
        message.put("transactionAmount", trade.getTransactionAmount());
        message.put("transactionLatitudeLongitude", trade.getTransactionLatitudeLongitude());
        message.put("transactionLatitudeLongitudeAddress", trade.getTransactionLatitudeLongitudeAddress());
        message.put("transactionLocation", trade.getTransactionLocation());
        message.put("transactionTime", trade.getTransactionTime());
        message.put("tradeStatus", tradeStatus);
        if (6 == tradeStatus) {
            message.put("cancelUserId", trade.getCancelUserId());
            message.put("cancelReason", trade.getCancelReason());
            message.put("cancelReasonSupplement", trade.getCancelReasonSupplement());

            // 查询字典表
            LambdaQueryWrapper<StoreDictionary> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(StoreDictionary::getTypeName, "cancelTradeReason");
            wrapper.eq(StoreDictionary::getDictId, trade.getCancelReason());
            StoreDictionary storeDictionary = storeDictionaryMapper.selectOne(wrapper);
            message.put("cancelReasonName", null == storeDictionary ? "" : storeDictionary.getDictDetail());
        }

        // 发起交易人信息
        Integer userId = Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId");
        String phoneId = JwtUtil.getCurrentUserInfo().getString("userType") + "_" + JwtUtil.getCurrentUserInfo().getString("phone");

        // 获取交易对方信息
        LifeUser lifeUser = lifeUserMapper.selectById(Objects.equals(userId, trade.getBuyerId()) ? trade.getSellerId() : trade.getBuyerId());
        String receiverId = "user_" + lifeUser.getUserPhone();

        // 消息
        LifeMessage lifeMessage = new LifeMessage();
        lifeMessage.setSenderId(phoneId);
        lifeMessage.setReceiverId(receiverId);
        lifeMessage.setType(messageType);
        lifeMessage.setContent(message.toJSONString());
        lifeMessageMapper.insert(lifeMessage);
        message.put("createdTime", lifeMessage.getCreatedTime());

        // 给买家与卖家发送交易消息
        WebSocketVo webSocketVo = new WebSocketVo();
        webSocketVo.setSenderId(phoneId);
        webSocketVo.setReceiverId(receiverId);
        webSocketVo.setCategory("message");
        webSocketVo.setType(messageType);
        webSocketVo.setIsRead(0);
        webSocketVo.setText(message.toJSONString());
        webSocketVo.setMessageId(lifeMessage.getId());

        alienStoreFeign.sendMsgToClientByPhoneId(phoneId, JSONObject.from(webSocketVo).toJSONString());
        alienStoreFeign.sendMsgToClientByPhoneId(receiverId, JSONObject.from(webSocketVo).toJSONString());
    }

    @Override
    public boolean goodsTradeConfirm(int goodsId) throws Exception {
        try {
            LambdaQueryWrapper<SecondTradeRecord> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(SecondTradeRecord::getGoodsId, goodsId);
            queryWrapper.in(SecondTradeRecord::getTradeStatus, 3, 4);
            return secondTradeRecordMapper.selectCount(queryWrapper) == 0;
        } catch (Exception e) {
            log.error("SecondTradeRecordServiceImpl.goodsTrade(): Error Msg={}", e.getMessage());
            throw new Exception(e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean tradeConfirm(int tradeId, int messageId, int type) throws BusinessException, Exception {
        try {
            // 交易信息
            SecondTradeRecord trade = secondTradeRecordMapper.selectById(tradeId);
            if (trade.getTradeStatus() == 6) throw new BusinessException("该交易已取消,不可操作");

            // 修改交易状态
            SecondTradeRecord tradeRecord = new SecondTradeRecord();
            tradeRecord.setId(tradeId);
            tradeRecord.setTradeStatus(type == 1 ? 3 : 2);
            secondTradeRecordMapper.updateById(tradeRecord);

            // 保存交易操作表
            SecondTradeOperation operation = new SecondTradeOperation();
            operation.setTradeId(trade.getId());
            operation.setUserId(Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId"));
            operation.setType(type == 1 ? 3 : 2);
            secondTradeOperationMapper.insert(operation);

            // 商品信息
            SecondGoods goods = secondGoodsMapper.selectById(trade.getGoodsId());

            // 修改待确认的消息
            LifeMessage lastMessage = lifeMessageMapper.selectById(messageId);

            JSONObject lastMessageContent = JSONObject.parseObject(lastMessage.getContent());
            lastMessageContent.put("messageId", lastMessage.getId());
            lastMessageContent.put("tradeStatus", type == 1 ? 3 : 2);
            LifeMessage message = new LifeMessage();
            message.setId(lastMessage.getId());
            message.setContent(lastMessageContent.toJSONString());
            lifeMessageMapper.updateById(message);

            // 发送消息
            trade.setTradeStatus(type == 1 ? 3 : 2);
            sendMsg(goods, trade, trade.getTradeStatus(), "4");

            // 发起交易人信息
            Integer userId = Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId");
            String phoneId = JwtUtil.getCurrentUserInfo().getString("userType") + "_" + JwtUtil.getCurrentUserInfo().getString("phone");

            // 获取交易对方信息
            LifeUser lifeUser = lifeUserMapper.selectById(Objects.equals(userId, trade.getBuyerId()) ? trade.getSellerId() : trade.getBuyerId());
            String receiverId = "user_" + lifeUser.getUserPhone();

            // 给买家与卖家发送交易消息
            WebSocketVo webSocketVo = new WebSocketVo();
            webSocketVo.setSenderId(phoneId);
            webSocketVo.setReceiverId(receiverId);
            webSocketVo.setCategory("message");
            webSocketVo.setType("4");
            webSocketVo.setIsRead(0);
            webSocketVo.setText(lastMessageContent.toJSONString());
            webSocketVo.setMessageId(lastMessage.getId());

            alienStoreFeign.sendMsgToClientByPhoneId(phoneId, JSONObject.from(webSocketVo).toJSONString());
            alienStoreFeign.sendMsgToClientByPhoneId(receiverId, JSONObject.from(webSocketVo).toJSONString());

            return true;
        } catch (BusinessException e) {
            throw new BusinessException(e);
        } catch (Exception e) {
            log.error("SecondTradeRecordServiceImpl.tradeConfirm(): Error Msg={}", e.getMessage());
            throw new Exception(e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelTrade(int tradeId, String cancelReason, String cancelReasonSupplement) throws Exception {
        try {
            // 发起交易人信息
            Integer userId = Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId");

            // 修改交易状态
            SecondTradeRecord tradeRecord = new SecondTradeRecord();
            tradeRecord.setId(tradeId);
            tradeRecord.setTradeStatus(6);
            tradeRecord.setCancelUserId(userId);
            tradeRecord.setCancelReason(cancelReason);
            tradeRecord.setCancelReasonSupplement(cancelReasonSupplement);
            secondTradeRecordMapper.updateById(tradeRecord);

            // 保存交易操作表
            SecondTradeOperation operation = new SecondTradeOperation();
            operation.setTradeId(tradeId);
            operation.setUserId(Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId"));
            operation.setType(7);
            operation.setCreatedTime(new Date());
            secondTradeOperationMapper.insert(operation);

            // 交易信息
            SecondTradeRecord trade = secondTradeRecordMapper.selectById(tradeId);

            // 发送消息
            sendMsg(secondGoodsMapper.selectById(trade.getGoodsId()), trade, 6, "4");

            return true;
        } catch (Exception e) {
            log.error("SecondTradeRecordServiceImpl.cancelTrade(): Error Msg={}", e.getMessage());
            throw new Exception(e);
        }
    }

    @Override
    public boolean whetherCanSignIn(int tradeId) throws Exception {
        try {
            int userId = Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId");
            SecondTradeRecord trade = secondTradeRecordMapper.selectById(tradeId);
            if (null == trade) return false;

            if (userId == trade.getBuyerId() && 0 == trade.getBuyerSignIn()) return true;
            if (userId == trade.getSellerId() && 0 == trade.getSellerSignIn()) return true;
        } catch (Exception e) {
            log.error("SecondTradeRecordServiceImpl.whetherCanSignIn(): Error Msg={}", e.getMessage());
            throw new Exception(e);
        }
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean tradeSignIn(int tradeId, int messageId, String signInLatitudeLongitude, String signInLatitudeLongitudeAddress) throws BusinessException, Exception {
        try {
            SecondTradeRecord trade = secondTradeRecordMapper.selectById(tradeId);
            if (null == trade) return false;
            if (trade.getTradeStatus() != 3) return false;

            // 发起交易人信息
            int userId = Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId");
            String phoneId = JwtUtil.getCurrentUserInfo().getString("userType") + "_" + JwtUtil.getCurrentUserInfo().getString("phone");

            // 获取交易对方信息
            LifeUser lifeUser = lifeUserMapper.selectById(Objects.equals(userId, trade.getBuyerId()) ? trade.getSellerId() : trade.getBuyerId());
            String receiverId = "user_" + lifeUser.getUserPhone();

            // 保存交易签到信息
            SecondTradeRecord record = new SecondTradeRecord();
            record.setId(tradeId);
            Date now = Date.from(LocalDateTime.now().withSecond(0).withNano(0).atZone(ZoneId.systemDefault()).toInstant());
            if (userId == trade.getBuyerId()) {
                if (1 == trade.getBuyerSignIn()) throw new BusinessException("该交易已签到,无需再次签到");
                record.setBuyerSignIn(1);
                record.setBuyerSignInTime(now);
                record.setBuyerSignInLatitudeLongitude(signInLatitudeLongitude);
                record.setBuyerSignInLatitudeLongitudeAddress(signInLatitudeLongitudeAddress);
            } else if (userId == trade.getSellerId()) {
                if (1 == trade.getSellerSignIn()) throw new BusinessException("该交易已签到,无需再次签到");
                record.setSellerSignIn(1);
                record.setSellerSignInTime(now);
                record.setSellerSignInLatitudeLongitude(signInLatitudeLongitude);
                record.setSellerSignInLatitudeLongitudeAddress(signInLatitudeLongitudeAddress);
            } else {
                log.error("SecondTradeRecordServiceImpl.tradeSignIn(): Error Msg={}", "userId无效");
                throw new Exception();
            }
            secondTradeRecordMapper.updateById(record);

            // 保存交易操作表
            SecondTradeOperation operation = new SecondTradeOperation();
            operation.setTradeId(tradeId);
            operation.setUserId(userId);
            operation.setType(4);
            operation.setCreatedTime(new Date());
            secondTradeOperationMapper.insert(operation);

            // 删除签到提醒消息
            LifeMessage signInMessage = lifeMessageMapper.selectById(messageId);
            if (null == signInMessage) throw new BusinessException("该交易已签到,无需再次签到");
            lifeMessageMapper.deleteById(messageId);

            // 发送已签到消息
            JSONObject messageContent = JSONObject.parseObject(signInMessage.getContent());
            messageContent.put("tradeId", tradeId);
            messageContent.put("signInTime", now.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
            messageContent.put("signInLatitudeLongitude", signInLatitudeLongitude);
            messageContent.put("signInLatitudeLongitudeAddress", signInLatitudeLongitudeAddress);
            LifeMessage message = new LifeMessage();
            message.setSenderId(phoneId);
            message.setReceiverId(receiverId);
            message.setContent(messageContent.toJSONString());
            message.setType("6");
            lifeMessageMapper.insert(message);

            // 推送已签到消息
            WebSocketVo webSocketVo = new WebSocketVo();
            webSocketVo.setSenderId(phoneId);
            webSocketVo.setReceiverId(receiverId);
            webSocketVo.setCategory("message");
            webSocketVo.setType("6");
            webSocketVo.setIsRead(0);
            webSocketVo.setText(messageContent.toJSONString());
            webSocketVo.setMessageId(message.getId());

            alienStoreFeign.sendMsgToClientByPhoneId(phoneId, JSONObject.from(webSocketVo).toJSONString());
            alienStoreFeign.sendMsgToClientByPhoneId(receiverId, JSONObject.from(webSocketVo).toJSONString());

            return true;
        } catch (BusinessException e) {
            throw new BusinessException(e);
        }  catch (Exception e) {
            log.error("SecondTradeRecordServiceImpl.tradeSignIn(): Error Msg={}", e.getMessage());
            throw new Exception(e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SecondTradeRecordVo getUserTradeStatus(int tradeId) throws Exception {
        try {
            SecondTradeRecordVo recordVo = new SecondTradeRecordVo();
            int userId = Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId");
            SecondTradeRecord tradeRecord = secondTradeRecordMapper.selectById(tradeId);
            if (null == tradeRecord) return new SecondTradeRecordVo();

            if (userId == tradeRecord.getBuyerId()) {
                recordVo.setUserTransactionStatus(tradeRecord.getBuyerTransactionStatus());
                recordVo.setUserEvaluate(tradeRecord.getBuyerEvaluate());
            } else if (userId == tradeRecord.getSellerId()) {
                recordVo.setUserTransactionStatus(tradeRecord.getSellerTransactionStatus());
                recordVo.setUserEvaluate(tradeRecord.getSellerEvaluate());
            }
            return recordVo;
        } catch (Exception e) {
            log.error("SecondTradeRecordServiceImpl.getUserTradeStatus(): Error Msg={}", e.getMessage());
            throw new Exception(e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean tradeCompleteConfirm(int tradeId, int type, String evaluate) throws Exception {
        try {
            int userId = Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId");
            SecondTradeRecord tradeRecord = secondTradeRecordMapper.selectById(tradeId);
            SecondTradeRecord record = new SecondTradeRecord();
            record.setId(tradeId);
            // 买家
            if (userId == tradeRecord.getBuyerId()) {
                if (0 != tradeRecord.getBuyerTransactionStatus()) return false;
                record.setBuyerTransactionStatus(type);
                record.setBuyerEvaluate(evaluate);
            // 卖家
            } else if (userId == tradeRecord.getSellerId()) {
                if (0 != tradeRecord.getSellerTransactionStatus()) return false;
                record.setSellerTransactionStatus(type);
                record.setSellerEvaluate(evaluate);
                record.setTradeStatus(1 == type ? 4 : 5);
                // 卖家如果选择交易成功  同步修改商品表
                if (1 == type) {
                    SecondGoods goods = new SecondGoods();
                    goods.setId(tradeRecord.getGoodsId());
                    goods.setGoodsStatus(5);
                    secondGoodsMapper.updateById(goods);
                }
            } else {
                return false;
            }
            secondTradeRecordMapper.updateById(record);

            // 保存交易操作表
            SecondTradeOperation operation = new SecondTradeOperation();
            operation.setTradeId(tradeId);
            operation.setUserId(userId);
            operation.setType(1 == type ? 5 : 6);
            operation.setCreatedTime(new Date());
            secondTradeOperationMapper.insert(operation);

            return true;
        } catch (Exception e) {
            log.error("SecondTradeRecordServiceImpl.tradeCompleteConfirm(): Error Msg={}", e.getMessage());
            throw new Exception(e);
        }
    }

    @Override
    public List<SecondTradeRecordVo> getTradeRecord(int sideId) throws Exception {
        try {
            int userId = Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getInteger("userId");
            QueryWrapper<SecondTradeRecord> wrapper = new QueryWrapper<>();
            wrapper.eq("trade.delete_flag", 0);
            wrapper.apply("((trade.buyer_id = '" + sideId + "' and trade.seller_id = '" + userId + "') || (trade.buyer_id = '" + userId + "' and trade.seller_id = '" + sideId + "'))");
            wrapper.orderByDesc("trade.created_time");
            return secondTradeRecordMapper.getTradeRecord(wrapper);
        } catch (Exception e) {
            log.error("SecondTradeRecordServiceImpl.getTradeRecord(): Error Msg={}", e.getMessage());
            throw new Exception(e);
        }
    }
}
