package com.spot.controller;

import com.spot.constant.SysConstant;
import com.spot.enums.MessageCode;
import com.spot.exception.BizException;
import com.spot.req.TransferReq;
import com.spot.resp.AccountListResp;
import com.spot.resp.ApiResultVo;
import com.spot.service.AccountAssetService;
import com.spot.service.AssetChangeMqService;
import com.spot.service.TransferService;
import com.spot.utils.Constant;
import com.spot.utils.RequestUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

/**
 * 账户控制器，提供资产查询与划转接口
 *
 * @author jean
 * @date 2026-05-06
 */
@Slf4j
@RestController
@RequestMapping("/v1")
public class AccountController {

    @Autowired
    private AccountAssetService accountAssetService;

    @Autowired
    private TransferService transferService;

    @Autowired
    private AssetChangeMqService assetChangeMqService;

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;


    /**
     * 获取用户资产列表
     *
     * @param hideZero true=隐藏余额为0的账户（默认），false=展示所有开启币种（余额为0时显示0）
     * @param request  HTTP请求
     * @return 资产列表（按USDT价值降序）
     */
    @GetMapping("/account/asset/list")
    @ResponseBody
    public ApiResultVo<AccountListResp> getAssetList(
            @RequestParam(value = "hideZero", defaultValue = "true") boolean hideZero,
            HttpServletRequest request) {
        String lang = RequestUtils.getLangFromHeader(request);
        try {
            Long uid = (Long) request.getAttribute(SysConstant.REQUEST_ATTR_MEMBER_ID);
            AccountListResp resp = accountAssetService.getUserAssetList(uid, hideZero);
            return ApiResultVo.success(lang, resp);
        } catch (BizException e) {
            log.warn("获取资产列表失败 - {}", e.getMessage());
            return ApiResultVo.fail(lang, e.getMessageCode(), e.getMessage(lang));
        } catch (Exception e) {
            log.error("获取资产列表失败", e);
            return ApiResultVo.fail(lang, MessageCode.UNKNOWN_ERROR);
        }
    }

    /**
     * 账户间划转：资金账户 ↔ 现货账户
     * <p>
     * direction=1：资金账户 → 现货账户（充值到现货）<br>
     * direction=2：现货账户 → 资金账户（从现货提回资金）
     *
     * @param req     划转请求（symbol、amount、direction）
     * @param request HTTP请求
     * @return 操作结果
     */
    @PostMapping("/account/transfer")
    @ResponseBody
    public ApiResultVo<Void> transfer(@RequestBody TransferReq req, HttpServletRequest request) {
        String lang = RequestUtils.getLangFromHeader(request);
        try {
            Long uid = (Long) request.getAttribute(SysConstant.REQUEST_ATTR_MEMBER_ID);
            // 1. 事务内执行划转
            ApiResultVo<Void> result = transferService.transfer(uid, req, lang);
            // 2. 划转成功后，事务外发送缓存更新通知
            if (Constant.API_SUCCESS_CODE.equals(result.getCode())) {
                sendTransferChangeMessages(uid, req.getSymbol());
            }
            return result;
        } catch (BizException e) {
            log.warn("账户划转失败 - {}", e.getMessage());
            return ApiResultVo.fail(lang, e.getMessageCode(), e.getMessage(lang));
        } catch (Exception e) {
            log.error("账户划转失败 - req={}", req, e);
            return ApiResultVo.fail(lang, MessageCode.TRANSFER_FAILED);
        }
    }

    /**
     * 划转成功后发送缓存更新 Kafka 通知
     * 1. 通知现货模块资产变动（SPOT_CHANGE）
     * 2. 通知资金账户模块缓存更新（trading-account-change）
     *
     * @param uid    用户ID
     * @param symbol 币种符号
     */
    private void sendTransferChangeMessages(Long uid, String symbol) {
        try {
            // 现货资产变动通知
            assetChangeMqService.sendSpotAssetChange(uid, symbol);
        } catch (Exception e) {
            log.warn("发送现货资产变动通知失败 - uid: {}, symbol: {}", uid, symbol, e);
        }
        try {
            // 资金账户缓存更新通知
            kafkaTemplate.send(Constant.KAFKA_TOPIC_TRADING_ACCOUNT_CHANGE, String.valueOf(uid), String.valueOf(uid));
            log.info("资金账户缓存更新通知已发送 - uid: {}, topic: {}", uid, Constant.KAFKA_TOPIC_TRADING_ACCOUNT_CHANGE);
        } catch (Exception e) {
            log.warn("发送资金账户缓存更新通知失败 - uid: {}", uid, e);
        }
    }

}
