package com.bizzan.bitrade.controller;

import com.bizzan.bitrade.entity.StakingConfig;
import com.bizzan.bitrade.entity.StakingOrder;
import com.bizzan.bitrade.entity.StakingRecord;
import com.bizzan.bitrade.entity.StakingWallet;
import com.bizzan.bitrade.entity.transform.AuthMember;
import com.bizzan.bitrade.service.LocaleMessageSourceService;
import com.bizzan.bitrade.service.MemberWalletService;
import com.bizzan.bitrade.service.StakingService;
import com.bizzan.bitrade.util.MessageResult;
import com.bizzan.bitrade.vo.StakingWalletVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.bizzan.bitrade.constant.SysConstant.SESSION_MEMBER;

/**
 * 用户质押接口，提供质押、查询订单和流水功能
 *
 * @author auto
 * @date 2026-05-17
 */
@Api(value = "StakingController", tags = "用户质押接口")
@RestController
@RequestMapping("/staking")
@Slf4j
public class StakingController {

    @Autowired
    private StakingService stakingService;

    @Autowired
    private MemberWalletService memberWalletService;

    @Autowired
    private LocaleMessageSourceService msService;

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 查询现货最新价（Redis ExchangeNew2:latestPrice，与 IDO 闪兑、质押折算同源）
     */
    @ApiOperation(value = "查询质押币现货价", notes = "从 Redis 读取 coinUnit 对 USDT 价格，如 IBIT → ibitusdt")
    @GetMapping("/spot-price")
    public MessageResult getSpotPrice(@RequestParam("coinUnit") String coinUnit) {
        if (coinUnit == null || coinUnit.trim().isEmpty()) {
            return MessageResult.error(msService.getMessage("PARAMETER_ERROR"));
        }
        BigDecimal price = stakingService.resolveSpotPriceUsdt(coinUnit.trim());
        if (price == null || price.compareTo(BigDecimal.ZERO) <= 0) {
            return MessageResult.error(msService.getMessage("STAKING_PRICE_UNAVAILABLE"));
        }
        Map<String, Object> data = new HashMap<>(2);
        data.put("coinUnit", coinUnit.trim().toUpperCase());
        data.put("price", price.toPlainString());
        return MessageResult.success("success", data);
    }

    /**
     * 查询启用中的质押配置列表，供用户选择质押产品
     *
     * @return 启用中的质押配置
     */
    @ApiOperation(value = "查询质押配置列表", notes = "获取所有启用中的质押配置，包含锁定天数、最小质押额等信息")
    @PostMapping("/config/list")
    public MessageResult getConfigList() {
        List<StakingConfig> configs = stakingService.getEnabledConfigs();
        return MessageResult.success("success", configs);
    }

    /**
     * 获取 ID 最小且启用中的质押配置，供 IDO 预售页默认展示
     *
     * @return 单条启用配置
     */
    @ApiOperation(value = "查询默认质押配置", notes = "返回 status=1 且 id 最小的 staking_config，供 IDO 预售页使用")
    @PostMapping("/config/min-open")
    public MessageResult getMinOpenConfig() {
        StakingConfig config = stakingService.getMinIdEnabledConfig();
        if (config == null) {
            return MessageResult.error(msService.getMessage("STAKING_NO_PRODUCT"));
        }
        return MessageResult.success("success", config);
    }

    /**
     * 查询当前用户质押钱包余额，返回原始数量及 USDT 折算值
     *
     * @param member   当前登录用户
     * @param coinUnit 币种，如 IBIT
     * @return StakingWalletVo：可用、不可用原始数量及各自 USDT 折算
     */
    @ApiOperation(value = "查询质押钱包余额", notes = "返回指定币种的可用/锁定原始数量及折合 USDT 值")
    @PostMapping("/wallet")
    public MessageResult getStakingWallet(@SessionAttribute(SESSION_MEMBER) AuthMember member,
                                          @RequestParam String coinUnit) {
        if (coinUnit == null || coinUnit.trim().isEmpty()) {
            return MessageResult.error(msService.getMessage("PARAMETER_ERROR"));
        }
        // 1. 查询质押钱包
        StakingWallet wallet = memberWalletService.findStakingWallet(member.getId(), coinUnit.trim());

        // 2. 从 Redis 读取现货价格（ExchangeNew2:latestPrice，field 格式如 ibitusdt）
        java.math.BigDecimal price = stakingService.resolveSpotPriceUsdt(coinUnit.trim());
        if (price == null) {
            price = java.math.BigDecimal.ZERO;
        }

        // 3. 构建响应 VO
        StakingWalletVo vo = buildStakingWalletVo(member.getId(), wallet, coinUnit.trim(), price);
        return MessageResult.success("success", vo);
    }

    /**
     * 构建质押钱包余额 VO，包含原始锁定数量及 USDT 折算值
     *
     * @param wallet   质押钱包实体（可能为空余额对象）
     * @param coinUnit 币种
     * @param price    当前 coinUnit/USDT 价格，无价格传 ZERO
     * @return StakingWalletVo
     */
    private StakingWalletVo buildStakingWalletVo(Long memberId, StakingWallet wallet, String coinUnit, java.math.BigDecimal price) {
        java.math.BigDecimal locked = wallet.getLockedBalance() != null ? wallet.getLockedBalance() : java.math.BigDecimal.ZERO;
        java.math.BigDecimal released = stakingService.getUserReleasedAmount(memberId, coinUnit);

        // 有行情则折算 USDT，否则为 0
        java.math.BigDecimal lockedUsdt = price.compareTo(java.math.BigDecimal.ZERO) > 0 ? locked.multiply(price) : java.math.BigDecimal.ZERO;

        StakingWalletVo vo = new StakingWalletVo();
        vo.setCoinUnit(coinUnit.toUpperCase());
        vo.setLockedBalance(locked);
        vo.setLockedBalanceUsdt(lockedUsdt);
        vo.setReleasedTotal(released);
        return vo;
    }

    /**
     * 用户发起质押，从资金账户冻结指定金额
     *
     * @param member   当前登录用户
     * @param configId 质押配置ID
     * @param amount   质押金额
     * @return 操作结果
     */
    @ApiOperation(value = "发起质押", notes = "选择质押配置并指定金额进行质押，资金将从可用余额冻结")
    @PostMapping("/stake")
    public MessageResult stake(@SessionAttribute(SESSION_MEMBER) AuthMember member,
                               @RequestParam Long configId,
                               @RequestParam(required = false) BigDecimal amount,
                               @RequestParam(required = false) BigDecimal usdtAmount) {
        MessageResult result;
        if (usdtAmount != null && usdtAmount.compareTo(BigDecimal.ZERO) > 0) {
            result = stakingService.stakeWithUsdt(member.getId(), configId, usdtAmount);
        } else {
            if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
                return MessageResult.error(msService.getMessage("STAKING_AMOUNT_INVALID"));
            }
            result = stakingService.stake(member.getId(), configId, amount);
        }
        // 事务提交后发送 MQ 通知，避免消费方读到事务未提交的旧数据
        if (result.getCode() == 0) {
            kafkaTemplate.send("trading-account-change", member.getId() + "");
        }
        return result;
    }

    /**
     * 分页查询当前用户的质押订单列表
     *
     * @param member   当前登录用户
     * @param pageNo   页码（从1开始）
     * @param pageSize 每页条数
     * @param status   状态，支持单个值或逗号分隔，如 0 或 0,1
     * @return 质押订单分页数据
     */
    @ApiOperation(value = "查询我的质押订单", notes = "分页查询当前用户的质押订单，status 支持单个值或逗号分隔，如 0,1")
    @PostMapping("/orders")
    public MessageResult getMyOrders(@SessionAttribute(SESSION_MEMBER) AuthMember member,
                                     @RequestParam(defaultValue = "1") int pageNo,
                                     @RequestParam(defaultValue = "10") int pageSize,
                                     @RequestParam(required = false) String status) {
        List<Integer> statuses;
        try {
            statuses = parseStatusList(status);
        } catch (NumberFormatException e) {
            return MessageResult.error(msService.getMessage("PARAMETER_ERROR"));
        }
        Page<StakingOrder> page = stakingService.getUserStakingOrders(member.getId(), pageNo, pageSize, statuses);
        return MessageResult.success("success", page);
    }

    private List<Integer> parseStatusList(String status) {
        if (status == null || status.trim().isEmpty()) {
            return null;
        }
        List<Integer> statuses = new ArrayList<>();
        String[] parts = status.split(",");
        for (String part : parts) {
            String value = part.trim();
            if (!value.isEmpty()) {
                statuses.add(Integer.valueOf(value));
            }
        }
        return statuses.isEmpty() ? null : statuses;
    }

    /**
     * 分页查询当前用户的质押和释放流水记录
     *
     * @param member   当前登录用户
     * @param pageNo   页码（从1开始）
     * @param pageSize 每页条数
     * @return 质押流水分页数据
     */
    @ApiOperation(value = "查询我的质押流水", notes = "分页查询当前用户的质押和解冻释放流水记录")
    @PostMapping("/records")
    public MessageResult getMyRecords(@SessionAttribute(SESSION_MEMBER) AuthMember member,
                                      @RequestParam(defaultValue = "1") int pageNo,
                                      @RequestParam(defaultValue = "10") int pageSize) {
        Page<StakingRecord> page = stakingService.getUserStakingRecords(member.getId(), pageNo, pageSize);
        return MessageResult.success("success", page);
    }
}
