package com.bizzan.bitrade.controller.system;

import com.bizzan.bitrade.annotation.AccessLog;
import com.bizzan.bitrade.constant.AdminModule;
import com.bizzan.bitrade.constant.CommonStatus;
import com.bizzan.bitrade.constant.PageModel;
import com.bizzan.bitrade.controller.common.BaseAdminController;
import com.bizzan.bitrade.dao.CoinDao;
import com.bizzan.bitrade.dao.CoinNetworkDao;
import com.bizzan.bitrade.dao.WithdrawChainConfigDao;
import com.bizzan.bitrade.entity.CoinNetwork;
import com.bizzan.bitrade.entity.WithdrawChainConfig;
import com.bizzan.bitrade.service.WithdrawChainConfigService;
import com.bizzan.bitrade.util.MessageResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
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 java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 提现链配置管理接口
 *
 * @author auto
 * @date 2026-05-18
 */
@RestController
@RequestMapping("/system/withdraw-chain-config")
@Slf4j
public class WithdrawChainConfigController extends BaseAdminController {

    @Autowired
    private WithdrawChainConfigService withdrawChainConfigService;

    @Autowired
    private WithdrawChainConfigDao withdrawChainConfigDao;

    @Autowired
    private CoinNetworkDao coinNetworkDao;

    @Autowired
    private CoinDao coinDao;

    /**
     * 分页查询提现链配置
     *
     * @param pageModel 分页参数
     * @return 分页结果
     */
    @PostMapping("page-query")
    @AccessLog(module = AdminModule.SYSTEM, operation = "分页查询提现链配置")
    public MessageResult pageQuery(PageModel pageModel) {
        PageRequest pageable = new PageRequest(
                pageModel.getPageNo() - 1,
                pageModel.getPageSize(),
                new Sort(Sort.Direction.DESC, "id")
        );
        Page<WithdrawChainConfig> page = withdrawChainConfigDao.findAll(pageable);
        return success(page);
    }

    /**
     * 新增提现链配置
     *
     * @param coinUnit        币种单位，如 USDT
     * @param chainName       链名称，如 ERC20
     * @param rpcUrl          RPC 节点地址
     * @param contractAddress 合约地址（原生币可为空）
     * @param payoutAddress   打款地址（热钱包地址）
     * @param currency        货币类型（默认3）
     * @param keyType         密钥类型：0=私钥，1=助记词BIP44派生
     * @param signKey         签名私钥或助记词
     * @param derivePath      派生路径（keyType=1时使用）
     * @param testMode        测试模式：0=生产，1=测试
     * @param enabled         是否启用：1=启用，0=禁用
     * @param remark          备注
     * @return 操作结果
     */
    @PostMapping("create")
    @AccessLog(module = AdminModule.SYSTEM, operation = "新增提现链配置")
    public MessageResult create(
            @RequestParam("coinUnit") String coinUnit,
            @RequestParam("chainName") String chainName,
            @RequestParam("rpcUrl") String rpcUrl,
            @RequestParam(value = "contractAddress", required = false, defaultValue = "") String contractAddress,
            @RequestParam(value = "payoutAddress", required = false, defaultValue = "") String payoutAddress,
            @RequestParam(value = "currency", defaultValue = "3") Integer currency,
            @RequestParam(value = "keyType", defaultValue = "0") Integer keyType,
            @RequestParam("signKey") String signKey,
            @RequestParam(value = "derivePath", required = false, defaultValue = "") String derivePath,
            @RequestParam(value = "testMode", defaultValue = "0") Integer testMode,
            @RequestParam(value = "enabled", defaultValue = "1") Integer enabled,
            @RequestParam(value = "remark", required = false, defaultValue = "") String remark
    ) {
        // 构建配置实体
        WithdrawChainConfig config = buildConfig(
                coinUnit.trim(), chainName.trim(), rpcUrl.trim(),
                contractAddress, payoutAddress, currency, keyType,
                signKey, derivePath, testMode, enabled, remark
        );
        try {
            withdrawChainConfigService.saveConfig(config);
        } catch (IllegalArgumentException e) {
            return error(e.getMessage());
        }
        return success();
    }

    /**
     * 更新提现链配置
     *
     * @param id              配置ID
     * @param coinUnit        币种单位
     * @param chainName       链名称
     * @param rpcUrl          RPC 节点地址
     * @param contractAddress 合约地址
     * @param payoutAddress   打款地址
     * @param currency        货币类型
     * @param keyType         密钥类型
     * @param signKey         签名私钥或助记词
     * @param derivePath      派生路径
     * @param testMode        测试模式
     * @param enabled         是否启用
     * @param remark          备注
     * @return 操作结果
     */
    @PostMapping("update")
    @AccessLog(module = AdminModule.SYSTEM, operation = "更新提现链配置")
    public MessageResult update(
            @RequestParam("id") Long id,
            @RequestParam("coinUnit") String coinUnit,
            @RequestParam("chainName") String chainName,
            @RequestParam("rpcUrl") String rpcUrl,
            @RequestParam(value = "contractAddress", required = false, defaultValue = "") String contractAddress,
            @RequestParam(value = "payoutAddress", required = false, defaultValue = "") String payoutAddress,
            @RequestParam(value = "currency", defaultValue = "3") Integer currency,
            @RequestParam(value = "keyType", defaultValue = "0") Integer keyType,
            @RequestParam("signKey") String signKey,
            @RequestParam(value = "derivePath", required = false, defaultValue = "") String derivePath,
            @RequestParam(value = "testMode", defaultValue = "0") Integer testMode,
            @RequestParam(value = "enabled", defaultValue = "1") Integer enabled,
            @RequestParam(value = "remark", required = false, defaultValue = "") String remark
    ) {
        WithdrawChainConfig config = withdrawChainConfigService.findOne(id);
        if (config == null) {
            return error("配置不存在");
        }
        // 更新字段
        config.setCoinUnit(coinUnit.trim());
        config.setChainName(chainName.trim());
        config.setRpcUrl(rpcUrl.trim());
        config.setContractAddress(contractAddress);
        config.setPayoutAddress(payoutAddress);
        config.setCurrency(currency);
        config.setKeyType(keyType);
        config.setSignKey(signKey);
        config.setDerivePath(derivePath);
        config.setTestMode(testMode);
        config.setEnabled(enabled);
        config.setRemark(remark);
        try {
            withdrawChainConfigService.updateConfig(config);
        } catch (IllegalArgumentException e) {
            return error(e.getMessage());
        }
        return success();
    }

    /**
     * 删除提现链配置
     *
     * @param id 配置ID
     * @return 操作结果
     */
    @PostMapping("delete")
    @AccessLog(module = AdminModule.SYSTEM, operation = "删除提现链配置")
    public MessageResult delete(@RequestParam("id") Long id) {
        withdrawChainConfigService.deleteConfig(id);
        return success();
    }

    /**
     * 查询所有可用主网列表（从 coin_network 表取，用于新增/编辑时链名称下拉选择）
     *
     * @return 主网列表，每项含 id 和 name
     */
    @PostMapping("all-chain-names")
    @AccessLog(module = AdminModule.SYSTEM, operation = "查询主网列表")
    public MessageResult allChainNames() {
        List<CoinNetwork> networks = coinNetworkDao.findAllByOrderBySortAsc();
        List<Map<String, Object>> result = networks.stream().map(n -> {
            Map<String, Object> item = new HashMap<>();
            item.put("id", n.getId());
            item.put("name", n.getName());
            return item;
        }).collect(Collectors.toList());
        return success(result);
    }

    /**
     * 查询指定主网下可新增的币种单位（用于新增/编辑时联动下拉选择）
     * <p>
     * 返回 coin 表中 parent_coin_name 不为空、且在 withdraw_chain_config 中该链尚未配置的币种。
     * 编辑时可传入 includeCoinUnit，确保当前已配置的币种也出现在列表中。
     *
     * @param chainName       主网名称（如 ERC20、TRC20）
     * @param includeCoinUnit 编辑时当前记录的 coinUnit（可选）
     * @return 可选币种单位列表
     */
    @PostMapping("coin-units-by-chain")
    @AccessLog(module = AdminModule.SYSTEM, operation = "查询主网下可配置币种列表")
    public MessageResult coinUnitsByChain(
            @RequestParam("chainName") String chainName,
            @RequestParam(value = "includeCoinUnit", required = false) String includeCoinUnit
    ) {
        // 1. 查询该链下已配置的 coinUnit 集合
        Set<String> configured = withdrawChainConfigDao.findAll().stream()
                .filter(c -> chainName.equals(c.getChainName()))
                .map(WithdrawChainConfig::getCoinUnit)
                .collect(Collectors.toSet());

        // 2. 从 coin 表取 parent_coin_name 不为空的所有子币种（unit 字段）
        //    过滤掉已配置的，保留未配置的
        List<String> available = coinDao.findAll().stream()
                .filter(c -> c.getParentCoinName() != null && !c.getParentCoinName().isEmpty())
                .map(c -> c.getUnit())
                .filter(unit -> !configured.contains(unit))
                .distinct()
                .sorted()
                .collect(Collectors.toList());

        // 3. 编辑模式：把当前记录的 coinUnit 包含进去（自身已配置但需要出现在下拉中）
        if (includeCoinUnit != null && !includeCoinUnit.isEmpty()
                && !available.contains(includeCoinUnit)) {
            available.add(0, includeCoinUnit);
        }
        return success(available);
    }

    /**
     * 构建提现链配置实体
     */
    private WithdrawChainConfig buildConfig(
            String coinUnit, String chainName, String rpcUrl,
            String contractAddress, String payoutAddress,
            Integer currency, Integer keyType, String signKey,
            String derivePath, Integer testMode, Integer enabled, String remark
    ) {
        WithdrawChainConfig config = new WithdrawChainConfig();
        config.setCoinUnit(coinUnit);
        config.setChainName(chainName);
        config.setRpcUrl(rpcUrl);
        config.setContractAddress(contractAddress);
        config.setPayoutAddress(payoutAddress);
        config.setCurrency(currency);
        config.setKeyType(keyType);
        config.setSignKey(signKey);
        config.setDerivePath(derivePath);
        config.setTestMode(testMode);
        config.setEnabled(enabled);
        config.setRemark(remark);
        return config;
    }
}
