package com.bizzan.bitrade.service;

import com.bizzan.bitrade.constant.BooleanEnum;
import com.bizzan.bitrade.constant.CommonStatus;
import com.bizzan.bitrade.dao.CoinDao;
import com.bizzan.bitrade.dao.CoinNetworkConfigDao;
import com.bizzan.bitrade.dao.CoinNetworkDao;
import com.bizzan.bitrade.entity.Coin;
import com.bizzan.bitrade.entity.CoinNetwork;
import com.bizzan.bitrade.entity.CoinNetworkConfig;
import com.bizzan.bitrade.service.Base.BaseService;
import com.bizzan.bitrade.vo.CoinChildWithNetworkVO;
import com.bizzan.bitrade.vo.CoinRechargeConfigVO;
import com.bizzan.bitrade.vo.CoinWithdrawConfigVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 币种主网配置 Service
 *
 * @author auto
 * @date 2026-05-13
 */
@Service
public class CoinNetworkConfigService extends BaseService {

    @Autowired
    private CoinNetworkConfigDao coinNetworkConfigDao;

    @Autowired
    private CoinNetworkDao coinNetworkDao;

    @Autowired
    private CoinDao coinDao;

    /**
     * 某主网下可配置币种（子币且未配置；编辑时可包含当前币种）
     */
    @Transactional(readOnly = true)
    public List<String> findAvailableCoinNames(Long networkId, String includeCoinName) {
        if (StringUtils.hasText(includeCoinName)) {
            return coinDao.findAvailableCoinNamesForNetworkEdit(networkId, includeCoinName.trim());
        }
        return coinDao.findAvailableCoinNamesForNetwork(networkId);
    }

    /**
     * 查询某币种下所有主网配置，按排序升序
     *
     * @param coinName 币种名称
     * @return 配置列表
     */
    @Transactional(readOnly = true)
    public List<CoinNetworkConfig> findByCoinName(String coinName) {
        return coinNetworkConfigDao.findAllByCoinNameOrderBySortAsc(coinName);
    }

    /**
     * 查询某主网下的所有币种配置
     *
     * @param networkId 主网ID
     * @return 配置列表
     */
    @Transactional(readOnly = true)
    public List<CoinNetworkConfig> findByNetworkId(Long networkId) {
        return coinNetworkConfigDao.findAllByNetworkId(networkId);
    }

    /**
     * 充值：某顶级币种下已在 coin_network_config 配置的可选主网
     */
    @Transactional(readOnly = true)
    public List<CoinNetwork> findRechargeNetworksByParent(String parentCoinName) {
        return coinNetworkConfigDao.findRechargeNetworksForParent(
                parentCoinName,
                BooleanEnum.IS_TRUE,
                CommonStatus.NORMAL,
                CommonStatus.NORMAL);
    }

    /**
     * 充值：按 coin_network.id 从 coin_network_config 查询该主网下可充值的子币种
     */
    @Transactional(readOnly = true)
    public List<CoinRechargeConfigVO> findRechargeConfigsByParentAndNetwork(String parentCoinName, Long networkId) {
        List<CoinNetworkConfig> configs = coinNetworkConfigDao.findRechargeConfigsByParentAndNetwork(
                parentCoinName,
                networkId,
                BooleanEnum.IS_TRUE,
                CommonStatus.NORMAL);
        List<CoinRechargeConfigVO> result = new ArrayList<>();
        for (CoinNetworkConfig cfg : configs) {
            CoinNetwork network = cfg.getNetwork();
            if (network == null || network.getStatus() != CommonStatus.NORMAL) {
                continue;
            }
            Coin coin = coinDao.findOne(cfg.getCoinName());
            if (coin == null) {
                continue;
            }
            CoinRechargeConfigVO vo = new CoinRechargeConfigVO();
            vo.setNetworkConfigId(cfg.getId());
            vo.setCoinName(coin.getName());
            vo.setCoinNameCn(coin.getNameCn());
            vo.setNetworkId(network.getId());
            vo.setNetworkName(network.getName());
            vo.setProtocol(network.getProtocol());
            vo.setContractAddress(cfg.getContractAddress());
            vo.setRechargeAddress(cfg.getRechargeAddress());
            vo.setSort(cfg.getSort());
            result.add(vo);
        }
        return result;
    }

    /**
     * 提币：coin_network 表中有可提币种配置的主网列表
     */
    @Transactional(readOnly = true)
    public List<CoinNetwork> findWithdrawNetworks() {
        return coinNetworkConfigDao.findWithdrawNetworks(
                BooleanEnum.IS_TRUE,
                CommonStatus.NORMAL,
                CommonStatus.NORMAL);
    }

    /**
     * 提币：按 coin_network.id 查询 coin_network_config 下可提子币
     */
    @Transactional(readOnly = true)
    public List<CoinWithdrawConfigVO> findWithdrawConfigsByNetwork(Long networkId) {
        List<CoinNetworkConfig> configs = coinNetworkConfigDao.findWithdrawConfigsByNetwork(
                networkId,
                BooleanEnum.IS_TRUE,
                CommonStatus.NORMAL);
        List<CoinWithdrawConfigVO> result = new ArrayList<>();
        for (CoinNetworkConfig cfg : configs) {
            CoinNetwork network = cfg.getNetwork();
            if (network == null || network.getStatus() != CommonStatus.NORMAL) {
                continue;
            }
            Coin coin = coinDao.findOne(cfg.getCoinName());
            if (coin == null) {
                continue;
            }
            CoinWithdrawConfigVO vo = new CoinWithdrawConfigVO();
            vo.setCoinName(coin.getName());
            vo.setUnit(coin.getUnit());
            vo.setCoinNameCn(coin.getNameCn());
            vo.setNetworkId(network.getId());
            vo.setNetworkName(network.getName());
            vo.setProtocol(network.getProtocol());
            vo.setMinWithdrawAmount(coin.getMinWithdrawAmount());
            vo.setMaxWithdrawAmount(coin.getMaxWithdrawAmount());
            vo.setWithdrawFeeValue(coin.getWithdrawFeeValue());
            vo.setParentCoinName(coin.getParentCoinName());
            vo.setSort(cfg.getSort());
            result.add(vo);
        }
        return result;
    }

    /**
     * 查询某币种在某主网下的配置
     *
     * @param coinName  币种名称
     * @param networkId 主网ID
     * @return 配置信息，不存在返回 null
     */
    @Transactional(readOnly = true)
    public CoinNetworkConfig findByCoinAndNetwork(String coinName, Long networkId) {
        return coinNetworkConfigDao.findByCoinNameAndNetworkId(coinName, networkId);
    }

    /**
     * 按ID查询配置
     *
     * @param id 配置ID
     * @return 配置信息
     */
    @Transactional(readOnly = true)
    public CoinNetworkConfig findById(Long id) {
        return coinNetworkConfigDao.findOne(id);
    }

    /**
     * 新增币种主网配置
     *
     * @param config 配置信息（network 字段须含有效 id）
     * @return 保存后的配置
     * @throws IllegalArgumentException 主网不存在或该配置已存在时抛出
     */
    @Transactional(rollbackFor = Exception.class)
    public CoinNetworkConfig save(CoinNetworkConfig config) {
        CoinNetwork network = coinNetworkDao.findOne(config.getNetwork().getId());
        if (network == null) {
            throw new IllegalArgumentException("主网不存在，networkId=" + config.getNetwork().getId());
        }
        if (coinNetworkConfigDao.existsByCoinNameAndNetworkId(config.getCoinName(), network.getId())) {
            throw new IllegalArgumentException("该币种主网配置已存在：" + config.getCoinName() + " / " + network.getName());
        }
        config.setNetwork(network);
        return coinNetworkConfigDao.save(config);
    }

    /**
     * 更新币种主网配置
     *
     * @param config 配置信息（须含有效 id）
     * @return 更新后的配置
     */
    @Transactional(rollbackFor = Exception.class)
    public CoinNetworkConfig update(CoinNetworkConfig config) {
        return coinNetworkConfigDao.save(config);
    }

    /**
     * 批量查询子币种列表及其主网配置，组合为 VO 返回
     * 适用于充值流程：根据顶级币种查询所有子币种及对应主网信息
     *
     * @param children 子币种列表
     * @return 子币种与主网配置组合列表
     */
    @Transactional(readOnly = true)
    public List<CoinChildWithNetworkVO> buildChildrenWithNetwork(List<Coin> children) {
        // 遍历子币种，逐个查询主网配置并组装 VO
        List<CoinChildWithNetworkVO> result = new ArrayList<>();
        for (Coin child : children) {
            CoinChildWithNetworkVO vo = buildChildVO(child);
            result.add(vo);
        }
        return result;
    }

    /**
     * 构建单个子币种的主网配置 VO
     *
     * @param child 子币种
     * @return 组合 VO
     */
    private CoinChildWithNetworkVO buildChildVO(Coin child) {
        CoinChildWithNetworkVO vo = new CoinChildWithNetworkVO();
        vo.setCoin(child);
        List<CoinNetworkConfig> configs = coinNetworkConfigDao.findAllByCoinNameOrderBySortAsc(child.getName());
        vo.setNetworkConfigs(configs);
        return vo;
    }
}
