package com.backendsys.service.Ai.Aiivh;

import cn.hutool.core.convert.Convert;
import com.backendsys.aspect.HttpRequestAspect;
import com.backendsys.entity.Ai.Aiivh.AiivhQuotaDTO;
import com.backendsys.entity.Ai.Aiivh.AiivhQuotaHistoryDTO;
import com.backendsys.entity.Ai.Aiivh.AiivhQuotaOrderDTO;
import com.backendsys.entity.System.SysResourcePointsDTO;
import com.backendsys.entity.System.SysUserPointsDTO;
import com.backendsys.enums.IvhQuotaActiveEvent;
import com.backendsys.enums.UserPointActivityType;
import com.backendsys.enums.UserPointOperatorType;
import com.backendsys.exception.CustException;
import com.backendsys.mapper.Ai.Aiivh.AiivhQuotaHistoryMapper;
import com.backendsys.mapper.Ai.Aiivh.AiivhQuotaMapper;
import com.backendsys.mapper.Ai.Aiivh.AiivhQuotaOrderMapper;
import com.backendsys.mapper.System.SysResourcePointsMapper;
import com.backendsys.mapper.System.SysUserPointsHistoryMapper;
import com.backendsys.modules.system.dao.SysUserInfoDao;
import com.backendsys.modules.system.entity.SysUserInfo;
import com.backendsys.modules.system.service.SysUserService;
import com.backendsys.service.System.SysResourceService;
import com.backendsys.utils.CommonUtil;
import com.backendsys.utils.DateUtil;
import com.backendsys.utils.ListUtil;
import com.backendsys.utils.response.PageInfoResult;
import com.github.pagehelper.PageHelper;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
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 java.text.ParseException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

@Service
public class AiivhQuotaServiceImpl implements AiivhQuotaService{

    @Lazy
    @Autowired
    RedissonClient redissonClient;

    @Autowired
    private HttpRequestAspect httpRequestAspect;


    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysUserInfoDao sysUserInfoDao;

    @Autowired
    private SysUserPointsHistoryMapper sysUserPointsHistoryMapper;
    @Autowired
    private SysResourcePointsMapper sysResourcePointsMapper;

    @Autowired
    private SysResourceService sysResourceService;

    @Autowired
    private AiivhQuotaMapper aiivhQuotaMapper;
    @Autowired
    private AiivhQuotaOrderMapper aiivhQuotaOrderMapper;
    @Autowired
    private AiivhQuotaHistoryMapper aiivhQuotaHistoryMapper;


    /**
     * [方法] 1.1.入参，通过读取其他数据，计算并返回更丰富的入参
     */
    private AiivhQuotaOrderDTO loadQuotaOrderParam(AiivhQuotaOrderDTO aiivhQuotaOrderDTO) {
        // 1.通过 {order_type} 和 {quantity} 计算出积分
        // - order_type 兑换类型 (1形象+音色, 2形象, 3音色)
        // - quantity 兑换数量 (限制长度1-10)
        Integer quantity = aiivhQuotaOrderDTO.getQuantity();

        // [Get] 获得全部积分资源(规则) (转为对象)
        SysResourcePointsDTO sysResourcePointsDTO = new SysResourcePointsDTO();
        sysResourcePointsDTO.setResource_type("IvhVirtualman");
        List<Map<String, Object>> resourcePointsList = sysResourcePointsMapper.queryResourcePointsList(sysResourcePointsDTO);
        Map<String, Object> resourcePoints = ListUtil.convertListToMap(resourcePointsList, "resource_tag", "resource_points");
        // 获得积分单价
        Float anchorPoint = (Float) resourcePoints.get("Anchor");
        Float timbrePoint = (Float) resourcePoints.get("Timbre");

        // 入参
        aiivhQuotaOrderDTO.setOrder_code(CommonUtil.generateUniqueRandomOrderCode("OR"));     // 兑换随机订单号
        aiivhQuotaOrderDTO.setUser_id(aiivhQuotaOrderDTO.getUser_id());               // 兑换用户ID (当前用户)

        // 小计积分
        Float anchor_subtotal_point = (float) 0;
        Float timbre_subtotal_point = (float) 0;
        switch (aiivhQuotaOrderDTO.getOrder_type()) {
            case 1:
                anchor_subtotal_point = anchorPoint * quantity;
                timbre_subtotal_point = timbrePoint * quantity;
                break;
            case 2:
                anchor_subtotal_point = anchorPoint * quantity;
                break;
            case 3:
                timbre_subtotal_point = timbrePoint * quantity;
                break;
            default:
                throw new CustException("orderType 不匹配");
        }
        // 总计积分
        Float total_point = anchor_subtotal_point + timbre_subtotal_point;
        // 入参
        aiivhQuotaOrderDTO.setAnchor_subtotal_point(anchor_subtotal_point);
        aiivhQuotaOrderDTO.setTimbre_subtotal_point(timbre_subtotal_point);
        aiivhQuotaOrderDTO.setTotal_point(total_point);
        return aiivhQuotaOrderDTO;
    }

    /**
     * [方法] 2.1.增加 形象/音色配额记录 (批量)
     */
    private AiivhQuotaHistoryDTO increaseQuotaHistory(String QuotaType, Integer quantity, Long user_id) {
        AiivhQuotaHistoryDTO dto = new AiivhQuotaHistoryDTO();
        dto.setUser_id(user_id);
        dto.setQuota_adjustment(quantity);
        switch (QuotaType) {
            case "Anchor":
                dto.setActivity_type(IvhQuotaActiveEvent.MAKE_ANCHOR.getCode());
                dto.setActivity_type_description(IvhQuotaActiveEvent.MAKE_ANCHOR.getDescription());
                dto.setQuota_type("Anchor");
                break;
            case "Timbre":
                dto.setActivity_type(IvhQuotaActiveEvent.MAKE_ANCHOR.getCode());
                dto.setActivity_type_description(IvhQuotaActiveEvent.MAKE_ANCHOR.getDescription());
                dto.setQuota_type("Timbre");
                break;
            default:
                throw new CustException("increaseQuota is no match");
        }
        return dto;
    }
    private List<AiivhQuotaHistoryDTO> loadQuotaHistoryParam(AiivhQuotaOrderDTO aiivhQuotaOrderDTO) {
        List<AiivhQuotaHistoryDTO> aiivhQuotaHistoryDTOList = new ArrayList<>();
        // 兑换类型 (1形象+音色, 2形象, 3音色)
        // - 如果是 1 形象+音色，则是批量插入 两条配额操作记录
        // - 如果是 2,3 则是插入 单条配额操作记录
        switch (aiivhQuotaOrderDTO.getOrder_type()) {
            case 1:
                // 2.1.增加 形象/音色配额记录
                aiivhQuotaHistoryDTOList.add(increaseQuotaHistory("Anchor", aiivhQuotaOrderDTO.getQuantity(), aiivhQuotaOrderDTO.getUser_id()));
                aiivhQuotaHistoryDTOList.add(increaseQuotaHistory("Timbre", aiivhQuotaOrderDTO.getQuantity(), aiivhQuotaOrderDTO.getUser_id()));
                break;
            case 2:
                aiivhQuotaHistoryDTOList.add(increaseQuotaHistory("Anchor", aiivhQuotaOrderDTO.getQuantity(), aiivhQuotaOrderDTO.getUser_id()));
                break;
            case 3:
                aiivhQuotaHistoryDTOList.add(increaseQuotaHistory("Timbre", aiivhQuotaOrderDTO.getQuantity(), aiivhQuotaOrderDTO.getUser_id()));
                break;
            default:
                throw new CustException("orderType 不匹配");
        }
        return aiivhQuotaHistoryDTOList;
    }


    /**
     * [方法] 2.1.增加 配额 (批量)
     */
    private AiivhQuotaDTO increaseQuota(String QuotaType, Long userId, String orderCode) throws ParseException {
        AiivhQuotaDTO dto = new AiivhQuotaDTO();
        dto.setUser_id(userId);
        dto.setOrder_code(orderCode);
        dto.setQuota_code(CommonUtil.generateUniqueRandomOrderCode("QC"));

        dto.setQuota_status(1);
        switch (QuotaType) {
            case "Anchor":
                dto.setQuota_type("Anchor");
                break;
            case "Timbre":
                dto.setQuota_type("Timbre");
                break;
            default:
                throw new CustException("increaseQuota is no match");
        }

        dto.setExpire_date(DateUtil.getAfterYear(1));

        return dto;
    }
    private List<AiivhQuotaDTO> loadQuotaParam(AiivhQuotaOrderDTO aiivhQuotaOrderDTO, Integer quantity) {
        List<AiivhQuotaDTO> aiivhQuotaDTOList = new ArrayList<>();

        IntStream.rangeClosed(1, quantity).forEach(index -> {
            try {
                // 兑换类型 (1形象+音色, 2形象, 3音色)
                // - 如果是 1 形象+音色，则是批量插入 两条配额操作记录
                // - 如果是 2,3 则是插入 单条配额操作记录
                switch (aiivhQuotaOrderDTO.getOrder_type()) {
                    case 1:
                        // 2.1.增加 形象/音色配额记录
                        aiivhQuotaDTOList.add(increaseQuota("Anchor", aiivhQuotaOrderDTO.getUser_id(), aiivhQuotaOrderDTO.getOrder_code()));
                        aiivhQuotaDTOList.add(increaseQuota("Timbre", aiivhQuotaOrderDTO.getUser_id(), aiivhQuotaOrderDTO.getOrder_code()));
                        break;
                    case 2:
                        aiivhQuotaDTOList.add(increaseQuota("Anchor", aiivhQuotaOrderDTO.getUser_id(), aiivhQuotaOrderDTO.getOrder_code()));
                        break;
                    case 3:
                        aiivhQuotaDTOList.add(increaseQuota("Timbre", aiivhQuotaOrderDTO.getUser_id(), aiivhQuotaOrderDTO.getOrder_code()));
                        break;
                    default:
                        throw new CustException("orderType 不匹配");
                }
            } catch (RuntimeException | ParseException e) {
                throw new RuntimeException(e);
            }
        });
        return aiivhQuotaDTOList;
    }




    /**
     * 积分兑换配额
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> pointToVirtualmanQuota(AiivhQuotaOrderDTO aiivhQuotaOrderDTO) {

        RLock lock = redissonClient.getLock("pointToVirtualmanQuota");
        try {
            lock.tryLock(3, TimeUnit.SECONDS);
            // ------------------------------------------------------------

            Map<String, Object> result = new LinkedHashMap<>();

            // [查询] 自身 UserId
            Long user_id = httpRequestAspect.getUserId();
            aiivhQuotaOrderDTO.setUser_id(user_id);

            // 来源 (POINT:积分兑换)
            aiivhQuotaOrderDTO.setOrder_origin("POINT");
            // 有效期 (1年)
            aiivhQuotaOrderDTO.setValidity_year(1);
            // 过期时间 (1年后的时间)
            aiivhQuotaOrderDTO.setExpire_date(DateUtil.getAfterYear(1));


            // 1.[新增] 用户配额订单记录 (ai_ivh_quota_order 用户配额订单记录表) -------------------------------------------------
            aiivhQuotaOrderDTO = loadQuotaOrderParam(aiivhQuotaOrderDTO);
            aiivhQuotaOrderMapper.insertAiivhQuotaOrder(aiivhQuotaOrderDTO);

            // 2.[新增] 用户配额操作记录 (sys_user_points_history 用户配额操作记录表) --------------------------------------------
            List<AiivhQuotaHistoryDTO> aiivhQuotaHistoryDTOList = loadQuotaHistoryParam(aiivhQuotaOrderDTO);
            aiivhQuotaHistoryMapper.insertAiivhQuotaHistoryBatch(aiivhQuotaHistoryDTOList);

            // 3.[更新] 用户配额 (ai_ivh_quota AI数智人-用户配额表) -------------------------------------------------
            List<AiivhQuotaDTO> aiivhQuotaDTOList = loadQuotaParam(aiivhQuotaOrderDTO, aiivhQuotaOrderDTO.getQuantity());
            aiivhQuotaMapper.insertAiivhQuotaBatch(aiivhQuotaDTOList);

//            // 消耗积分 (查询对应积分，查询我的积分，更新我的积分，新增积分记录)
//            sysResourceService.consumptionPoint(resource_type, resource_tag, detail)

            // 此处因为积分需要计算，所以不使用封装方法

            // 获得当前用户详情 (sys_user_info) (需要先获得 total_point) -----------------------------------------------------------

//            Map<String, Object> userInfo = sysUserService.queryUserById(user_id);
//            Float origin_point_balance = (Float) userInfo.get("point_balance");

            SysUserInfo userInfo = sysUserService.selectUserInfo(user_id);
            Float origin_point_balance = Convert.toFloat(userInfo.getPoint_balance());

            Float new_point_balance = origin_point_balance - aiivhQuotaOrderDTO.getTotal_point();

            // 判断用户积分是否足够扣除
            if (origin_point_balance < aiivhQuotaOrderDTO.getTotal_point()) {
                throw new CustException("用户积分不足，当前积分: " + origin_point_balance + ", 需要积分: " + aiivhQuotaOrderDTO.getTotal_point());
            }

            // 4.[扣除] 用户信息中的积分字段 (sys_user_info 用户信息)
            userInfo.setPoint_balance(Convert.toDouble(new_point_balance));
            sysUserInfoDao.updateById(userInfo);

            // 5.[新增] 系统用户积分历史记录
            SysUserPointsDTO sysUserPointsDTO = new SysUserPointsDTO();
            sysUserPointsDTO.setTarget_user_id(user_id);
            sysUserPointsDTO.setPoint_balance(new_point_balance);
            sysUserPointsDTO.setPoint_adjustment(-(aiivhQuotaOrderDTO.getTotal_point()));
            sysUserPointsDTO.setActivity_type(UserPointActivityType.USED.getCode());
            sysUserPointsDTO.setActivity_type_description(UserPointActivityType.USED.getDescription());
            sysUserPointsDTO.setActivity_detail("积分兑换配额");
            sysUserPointsDTO.setOperator_type(UserPointOperatorType.SYSTEM.getCode());
            sysUserPointsHistoryMapper.insertUserPointsHistory(sysUserPointsDTO);

            // 返回结果 ----------------------------------------------------------------------------------------------------
            System.out.println(aiivhQuotaOrderDTO);
            result.put("order_code", aiivhQuotaOrderDTO.getOrder_code());
            result.put("order_type", aiivhQuotaOrderDTO.getOrder_type());
            result.put("order_origin", aiivhQuotaOrderDTO.getOrder_origin());
            result.put("quantity", aiivhQuotaOrderDTO.getQuantity());
            result.put("anchor_subtotal_point", aiivhQuotaOrderDTO.getAnchor_subtotal_point());
            result.put("timbre_subtotal_point", aiivhQuotaOrderDTO.getTimbre_subtotal_point());
            result.put("total_point", aiivhQuotaOrderDTO.getTotal_point());
            result.put("validity_year", aiivhQuotaOrderDTO.getValidity_year());
            result.put("expire_date", aiivhQuotaOrderDTO.getExpire_date());
            result.put("create_time", CommonUtil.getCurrentTime());

            return result;
            // ------------------------------------------------------------

        } catch (InterruptedException e) { throw new RuntimeException(e);
        } finally { lock.unlock(); }
    }




    /**
     * 获取配额积分规则 (AI数智人形象)
     */
    @Override
    public List<Map<String, Object>> getResourceOfQuoa(SysResourcePointsDTO sysResourcePointsDTO) {
        // 选择资源类型
        sysResourcePointsDTO.setResource_type("IvhVirtualman");
        return sysResourcePointsMapper.queryResourcePointsList(sysResourcePointsDTO);
    }


    /**
     * [AI数智人] 我的配额列表
     */
    @Override
    public Map<String, Object> getMyQuotaList(Integer pageNum, Integer pageSize, AiivhQuotaDTO aiivhQuotaDTO) {
        // 分页查询
        if (pageNum != null && pageSize != null) {
            PageHelper.startPage(pageNum, pageSize);
            PageHelper.getLocalPage().setPageSizeZero(true);
        }
        // 分页输出 (自定义)
        List<Map<String, Object>> list = aiivhQuotaMapper.queryAiivhQuotaList(aiivhQuotaDTO);

        PageInfoResult pageInfoResult = new PageInfoResult(list);
        return pageInfoResult.toMap();
    }


}
