package com.bizzan.bitrade.controller.member;

import com.alibaba.fastjson.JSONObject;
import com.bizzan.bitrade.annotation.AccessLog;
import com.bizzan.bitrade.constant.AdminModule;
import com.bizzan.bitrade.constant.PageModel;
import com.bizzan.bitrade.constant.SysConstant;
import com.bizzan.bitrade.constant.TransactionType;
import com.bizzan.bitrade.controller.common.BaseAdminController;
import com.bizzan.bitrade.dto.MemberWalletDTO;
import com.bizzan.bitrade.entity.*;
import com.bizzan.bitrade.es.ESUtils;
import com.bizzan.bitrade.vo.TradingAccount;
import com.bizzan.bitrade.model.screen.MemberWalletScreen;
import com.bizzan.bitrade.service.*;
import com.bizzan.bitrade.util.DateUtil;
import com.bizzan.bitrade.util.InnerInvokeUtil;
import com.bizzan.bitrade.util.MessageResult;
import com.querydsl.core.types.Predicate;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestAttribute;

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

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

@RestController
@RequestMapping("member/member-wallet")
@Slf4j
public class MemberWalletController extends BaseAdminController {

    @Autowired
    private MemberWalletService memberWalletService;

    @Autowired
    private MemberService memberService;
    @Autowired
    private CoinService coinService;
    @Autowired
    private KafkaTemplate kafkaTemplate;
    @Autowired
    private MemberTransactionService memberTransactionService;
    @Autowired
    private LocaleMessageSourceService messageSource;
    @Autowired
    private ESUtils esUtils;
    @Autowired
    private JavaMailSender javaMailSender;
    @Autowired
    private InnerInvokeUtil invokeUtil;
    @Autowired
    private UserPurseService userPurseService;
    @Autowired
    private FollowWalletService followWalletService;
    @Autowired
    private MemberContractWalletService memberContractWalletService;

    @Value("${spring.mail.username}")
    private String from;
    @Value("${spark.system.host}")
    private String host;
    @Value("${spark.system.name}")
    private String company;

    @Value("${spark.system.admins}")
    private String admins;
    
    /**
     * 使用反射设置字段（如果字段存在）
     * @return true表示设置成功，false表示字段不存在或设置失败
     */
    private boolean setFieldIfExists(Object obj, String fieldName, Object value) {
        try {
            java.lang.reflect.Field field = obj.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(obj, value);
            log.debug("反射设置字段成功: className={}, fieldName={}, value={}", 
                    obj.getClass().getName(), fieldName, value);
            return true;
        } catch (NoSuchFieldException e) {
            // 字段不存在，记录调试日志
            log.debug("字段不存在: className={}, fieldName={}", obj.getClass().getName(), fieldName);
            return false;
        } catch (Exception e) {
            log.warn("设置字段失败: className={}, fieldName={}, value={}", 
                    obj.getClass().getName(), fieldName, value, e);
            return false;
        }
    }

    @RequiresPermissions("member:member-wallet:balance")
    @PostMapping("balance")
    @AccessLog(module = AdminModule.MEMBER, operation = "余额管理")
    public MessageResult getBalance(
            PageModel pageModel,
            MemberWalletScreen screen) {
        QMemberWallet qMemberWallet = QMemberWallet.memberWallet;
        QMember qMember = QMember.member;
        List<Predicate> criteria = new ArrayList<>();
        if (StringUtils.hasText(screen.getAccount())) {
            criteria.add(qMember.username.like("%" + screen.getAccount() + "%")
                    .or(qMember.mobilePhone.like(screen.getAccount() + "%"))
                    .or(qMember.email.like(screen.getAccount() + "%"))
                    .or(qMember.realName.like("%" + screen.getAccount() + "%")));
        }
        if (!StringUtils.isEmpty(screen.getWalletAddress())) {
            criteria.add(qMemberWallet.address.eq(screen.getWalletAddress()));
        }

        if (!StringUtils.isEmpty(screen.getUnit())) {
            criteria.add(qMemberWallet.coin.unit.eq(screen.getUnit()));
        }

        if (screen.getMaxAllBalance() != null) {
            criteria.add(qMemberWallet.balance.add(qMemberWallet.frozenBalance).loe(screen.getMaxAllBalance()));
        }

        if (screen.getMinAllBalance() != null) {
            criteria.add(qMemberWallet.balance.add(qMemberWallet.frozenBalance).goe(screen.getMinAllBalance()));
        }

        if (screen.getMaxBalance() != null) {
            criteria.add(qMemberWallet.balance.loe(screen.getMaxBalance()));
        }

        if (screen.getMinBalance() != null) {
            criteria.add(qMemberWallet.balance.goe(screen.getMinBalance()));
        }

        if (screen.getMaxFrozenBalance() != null) {
            criteria.add(qMemberWallet.frozenBalance.loe(screen.getMaxFrozenBalance()));
        }

        if (screen.getMinFrozenBalance() != null) {
            criteria.add(qMemberWallet.frozenBalance.goe(screen.getMinFrozenBalance()));
        }

        Page<MemberWalletDTO> page = memberWalletService.joinFind(criteria, qMember, qMemberWallet, pageModel,screen.getAllBalance());
        
        // 为每个结果添加三个账户类型的数据
        List<MemberWalletDTO> content = page.getContent();
        log.info("开始处理余额数据，共{}条记录", content.size());
        for (MemberWalletDTO dto : content) {
            Long memberId = dto.getMemberId();
            String unit = dto.getUnit();
            log.debug("处理会员余额数据: memberId={}, unit={}, username={}", memberId, unit, dto.getUsername());
            
            // 资产账户（现货账户）- 当前钱包数据
            BigDecimal spotBalance = dto.getBalance() != null ? dto.getBalance() : BigDecimal.ZERO;
            BigDecimal spotFrozenBalance = dto.getFrozenBalance() != null ? dto.getFrozenBalance() : BigDecimal.ZERO;
            BigDecimal spotTotalBalance = spotBalance.add(spotFrozenBalance);
            log.debug("资产账户余额: memberId={}, spotBalance={}, spotFrozenBalance={}, spotTotalBalance={}", 
                    memberId, spotBalance, spotFrozenBalance, spotTotalBalance);
            
            // 合约账户
            BigDecimal contractBalance = BigDecimal.ZERO;
            BigDecimal contractFrozenBalance = BigDecimal.ZERO;
            BigDecimal contractTotalBalance = BigDecimal.ZERO;
            try {
                if ("USDT".equals(unit)) {
                    TradingAccount tradingAccount = userPurseService.findOneVO(memberId);
                    if (tradingAccount != null) {
                        contractBalance = tradingAccount.getCurrentCapital() != null ? tradingAccount.getCurrentCapital() : BigDecimal.ZERO;
                        log.debug("获取合约账户可用余额: memberId={}, contractBalance={}", memberId, contractBalance);
                    }
                    // 获取合约钱包的冻结余额
                    List<MemberContractWallet> contractWallets = memberContractWalletService.findAllByMemberId(memberId);
                    log.debug("获取合约钱包列表: memberId={}, walletCount={}", memberId, contractWallets != null ? contractWallets.size() : 0);
                    for (MemberContractWallet contractWallet : contractWallets) {
                        if (contractWallet != null && contractWallet.getUsdtFrozenBalance() != null) {
                            contractFrozenBalance = contractFrozenBalance.add(contractWallet.getUsdtFrozenBalance());
                            log.debug("累加合约冻结余额: memberId={}, walletId={}, frozenBalance={}, total={}", 
                                    memberId, contractWallet.getId(), contractWallet.getUsdtFrozenBalance(), contractFrozenBalance);
                        }
                    }
                    contractTotalBalance = contractBalance.add(contractFrozenBalance);
                    log.debug("合约账户余额: memberId={}, contractBalance={}, contractFrozenBalance={}, contractTotalBalance={}", 
                            memberId, contractBalance, contractFrozenBalance, contractTotalBalance);
                }
            } catch (Exception e) {
                log.warn("获取合约账户余额失败, memberId={}, unit={}", memberId, unit, e);
            }
            
            // 跟单账户
            BigDecimal followBalance = BigDecimal.ZERO;
            BigDecimal followFrozenBalance = BigDecimal.ZERO;
            BigDecimal followTotalBalance = BigDecimal.ZERO;
            try {
                FollowWallet followWallet = followWalletService.findOne(memberId);
                if (followWallet != null && "USDT".equals(unit)) {
                    followBalance = followWallet.getBalance() != null ? followWallet.getBalance() : BigDecimal.ZERO;
                    followFrozenBalance = followWallet.getFrozenBalance() != null ? followWallet.getFrozenBalance() : BigDecimal.ZERO;
                    followTotalBalance = followBalance.add(followFrozenBalance);
                    log.debug("跟单账户余额: memberId={}, followBalance={}, followFrozenBalance={}, followTotalBalance={}", 
                            memberId, followBalance, followFrozenBalance, followTotalBalance);
                } else {
                    log.debug("跟单账户不存在或币种不匹配: memberId={}, unit={}, followWallet={}", 
                            memberId, unit, followWallet != null ? "存在" : "null");
                }
            } catch (Exception e) {
                log.warn("获取跟单账户余额失败, memberId={}, unit={}", memberId, unit, e);
            }
            
            // 使用反射设置字段（如果字段存在）
            log.debug("开始使用反射设置字段: memberId={}, DTO类型={}", memberId, dto.getClass().getName());
            try {
                boolean spotBalanceSet = setFieldIfExists(dto, "spotBalance", spotBalance);
                boolean spotFrozenBalanceSet = setFieldIfExists(dto, "spotFrozenBalance", spotFrozenBalance);
                boolean spotTotalBalanceSet = setFieldIfExists(dto, "spotTotalBalance", spotTotalBalance);
                boolean contractBalanceSet = setFieldIfExists(dto, "contractBalance", contractBalance);
                boolean contractFrozenBalanceSet = setFieldIfExists(dto, "contractFrozenBalance", contractFrozenBalance);
                boolean contractTotalBalanceSet = setFieldIfExists(dto, "contractTotalBalance", contractTotalBalance);
                boolean followBalanceSet = setFieldIfExists(dto, "followBalance", followBalance);
                boolean followFrozenBalanceSet = setFieldIfExists(dto, "followFrozenBalance", followFrozenBalance);
                boolean followTotalBalanceSet = setFieldIfExists(dto, "followTotalBalance", followTotalBalance);
                
                log.info("反射设置字段结果: memberId={}, spotBalance={}({}), spotFrozenBalance={}({}), spotTotalBalance={}({}), " +
                        "contractBalance={}({}), contractFrozenBalance={}({}), contractTotalBalance={}({}), " +
                        "followBalance={}({}), followFrozenBalance={}({}), followTotalBalance={}({})",
                        memberId,
                        spotBalance, spotBalanceSet ? "成功" : "失败",
                        spotFrozenBalance, spotFrozenBalanceSet ? "成功" : "失败",
                        spotTotalBalance, spotTotalBalanceSet ? "成功" : "失败",
                        contractBalance, contractBalanceSet ? "成功" : "失败",
                        contractFrozenBalance, contractFrozenBalanceSet ? "成功" : "失败",
                        contractTotalBalance, contractTotalBalanceSet ? "成功" : "失败",
                        followBalance, followBalanceSet ? "成功" : "失败",
                        followFrozenBalance, followFrozenBalanceSet ? "成功" : "失败",
                        followTotalBalance, followTotalBalanceSet ? "成功" : "失败");
            } catch (Exception e) {
                log.warn("设置账户余额字段失败, memberId={}, unit={}", memberId, unit, e);
            }
        }
        log.info("完成处理余额数据，共{}条记录", content.size());
        
        return success(messageSource.getMessage("SUCCESS"), page);
    }

    @RequiresPermissions("member:member-wallet:recharge")
    @PostMapping("recharge")
    @AccessLog(module = AdminModule.MEMBER, operation = "充币管理")
    public MessageResult recharge(
    		@RequestAttribute(SysConstant.SESSION_ADMIN) Admin admin,
            @RequestParam("unit") String unit,
            @RequestParam("uid") Long uid,
            @RequestParam("amount") BigDecimal amount) {
        Coin coin = coinService.findByUnit(unit);
        if (coin == null) {
            return error("币种不存在");
        }
        MemberWallet memberWallet = memberWalletService.findByCoinAndMemberId(coin, uid);
        //memberWallet.setBalance(memberWallet.getBalance().add(amount));
        //MemberWallet memberWallet = InnerInvokeUtil.fineWallet(uid, unit);
        if (memberWallet.getBalance().add(amount).compareTo(BigDecimal.ZERO) < 0) {
        	return error("余额不能小于0");
        }
        memberWalletService.increaseBalance(memberWallet.getId(), amount);
        Assert.notNull(memberWallet, "wallet null");

        MemberTransaction memberTransaction = new MemberTransaction();
        memberTransaction.setFee(BigDecimal.ZERO);
        memberTransaction.setAmount(amount);
        memberTransaction.setMemberId(memberWallet.getMemberId());
        memberTransaction.setSymbol(unit);
        memberTransaction.setType(TransactionType.ADMIN_RECHARGE);
        memberTransaction.setCreateTime(DateUtil.getCurrentDate());
        memberTransaction.setRealFee("0");
        memberTransaction.setDiscountFee("0");
        memberTransaction= memberTransactionService.save(memberTransaction);
        
        //memberService.updateDisableReward(memberWallet.getMemberId(), 1);
        
        kafkaTemplate.send("trading-account-change", memberWallet.getMemberId()+"");
        
        String[] adminList = admins.split(",");
        for(int i = 0; i < adminList.length; i++) {
			sendEmailMsg(adminList[i], "管理员人工充值(用户ID: " + uid + ", 币种: " + unit + ", 数量: " + amount + "); 操作者：" +admin.getUsername() + "/" + admin.getMobilePhone(), "人工充值通知");
		}
        
        return success(messageSource.getMessage("SUCCESS"));
    }
    
    /**
     * 发送邮件
     * @param email
     * @param msg
     * @param subject
     * @throws MessagingException
     * @throws IOException
     * @throws TemplateException
     */
    @Async
    public void sendEmailMsg(String email, String msg, String subject){
    	try {
	        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
	        MimeMessageHelper helper = null;
	        helper = new MimeMessageHelper(mimeMessage, true);
	        helper.setFrom(from);
	        helper.setTo(email);
	        helper.setSubject(company + "-" + subject);
	        Map<String, Object> model = new HashMap<>(16);
	        model.put("msg", msg);
	        Configuration cfg = new Configuration(Configuration.VERSION_2_3_26);
	        cfg.setClassForTemplateLoading(this.getClass(), "/templates");
	        Template template = cfg.getTemplate("simpleMessage.ftl");
	        String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
	        helper.setText(html, true);
	
	        //发送邮件
	        javaMailSender.send(mimeMessage);
	        log.info("send email for {},content:{}", email, html);
    	}catch(Exception e) {
    		e.printStackTrace();
    	}
    }
    
    @RequiresPermissions("member:member-wallet:reset-address")
    @PostMapping("reset-address")
    @AccessLog(module = AdminModule.MEMBER, operation = "重置钱包地址")
    public MessageResult resetAddress(String unit, long uid) {
        Member member = memberService.findOne(uid);
        Assert.notNull(member, "member null");
        try {
            JSONObject json = new JSONObject();
            json.put("uid", member.getId());
            log.info("kafkaTemplate send : topic = {reset-member-address} , unit = {} , uid = {}", unit, json);
            kafkaTemplate.send("reset-member-address", unit, json.toJSONString());
            return MessageResult.success(messageSource.getMessage("SUCCESS"));
        } catch (Exception e) {
            return MessageResult.error(messageSource.getMessage("REQUEST_FAILED"));
        }
    }

    @RequiresPermissions("member:member-wallet:lock-wallet")
    @PostMapping("lock-wallet")
    @AccessLog(module = AdminModule.MEMBER, operation = "锁定钱包")
    public MessageResult lockWallet(Long uid, String unit) {
        if (memberWalletService.lockWallet(uid, unit)) {
            return success(messageSource.getMessage("SUCCESS"));
        } else {
            return error(500, messageSource.getMessage("REQUEST_FAILED"));
        }
    }

    @RequiresPermissions("member:member-wallet:unlock-wallet")
    @PostMapping("unlock-wallet")
    @AccessLog(module = AdminModule.MEMBER, operation = "解锁钱包")
    public MessageResult unlockWallet(Long uid, String unit) {
        if (memberWalletService.unlockWallet(uid, unit)) {
            return success(messageSource.getMessage("SUCCESS"));
        } else {
            return error(500, messageSource.getMessage("REQUEST_FAILED"));
        }
    }
}
