package com.yingpai.miniapp.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.yingpai.miniapp.domain.bo.PaymentConfigBo;
import com.yingpai.miniapp.domain.vo.PaymentConfigVo;
import com.yingpai.miniapp.service.IPaymentConfigService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.system.domain.SysConfig;
import org.dromara.system.mapper.SysConfigMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.List;

/**
 * 支付配置服务实现（从sys_config读取）
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PaymentConfigServiceImpl implements IPaymentConfigService {

    private final SysConfigMapper sysConfigMapper;

    /** 证书保存目录（模块resources/cert下） */
    private String getCertDir() {
        try {
            // 获取当前模块的resources目录
            String resourcePath = this.getClass().getClassLoader().getResource("").getPath();
            // Windows路径处理
            if (resourcePath.startsWith("/")) {
                resourcePath = resourcePath.substring(1);
            }
            // 开发环境：target/classes -> src/main/resources
            if (resourcePath.contains("target/classes")) {
                resourcePath = resourcePath.replace("target/classes", "src/main/resources");
            }
            return resourcePath + "cert";
        } catch (Exception e) {
            log.error("获取resources路径失败", e);
            throw new RuntimeException("获取证书目录失败", e);
        }
    }

    // 配置key
    private static final String SHORT_PRICE_KEY = "payment.short.price";
    private static final String STRONG_PRICE_KEY = "payment.strong.price";
    private static final String MCH_ID_KEY = "payment.mch.id";
    private static final String API_V3_KEY = "payment.api.v3.key";
    private static final String NOTIFY_URL_KEY = "payment.notify.url";
    private static final String PRIVATE_KEY_PATH_KEY = "payment.private.key.path";
    private static final String CERT_PATH_KEY = "payment.cert.path";
    private static final String PUBLIC_KEY_ID_KEY = "payment.public.key.id";
    private static final String PUBLIC_KEY_PATH_KEY = "payment.public.key.path";

    @Override
    public PaymentConfigVo getConfig() {
        PaymentConfigVo vo = new PaymentConfigVo();

        vo.setShortPrice(getConfigValue(SHORT_PRICE_KEY, "1"));
        vo.setStrongPrice(getConfigValue(STRONG_PRICE_KEY, "100"));
        vo.setMchId(getConfigString(MCH_ID_KEY));
        vo.setApiV3Key(getConfigString(API_V3_KEY));
        vo.setNotifyUrl(getConfigString(NOTIFY_URL_KEY));
        
        // 微信支付公钥配置
        vo.setPublicKeyId(getConfigString(PUBLIC_KEY_ID_KEY));
        
        // 检查公钥是否已上传
        String publicKeyPath = getConfigString(PUBLIC_KEY_PATH_KEY);
        vo.setPublicKeyUploaded(publicKeyPath != null && !publicKeyPath.isEmpty() && new File(publicKeyPath).exists());

        // 检查私钥是否已上传
        String privateKeyPath = getConfigString(PRIVATE_KEY_PATH_KEY);
        vo.setPrivateKeyUploaded(privateKeyPath != null && !privateKeyPath.isEmpty() && new File(privateKeyPath).exists());

        // 检查证书是否已上传
        String certPath = getConfigString(CERT_PATH_KEY);
        vo.setCertUploaded(certPath != null && !certPath.isEmpty() && new File(certPath).exists());

        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateConfig(PaymentConfigBo bo) {
        if (bo.getShortPrice() != null) {
            updateOrInsertConfig(SHORT_PRICE_KEY, bo.getShortPrice().toString(), "超短池订阅价格");
        }
        if (bo.getStrongPrice() != null) {
            updateOrInsertConfig(STRONG_PRICE_KEY, bo.getStrongPrice().toString(), "强势池订阅价格");
        }
        if (bo.getMchId() != null) {
            updateOrInsertConfig(MCH_ID_KEY, bo.getMchId(), "微信支付商户号");
        }
        if (bo.getApiV3Key() != null) {
            updateOrInsertConfig(API_V3_KEY, bo.getApiV3Key(), "微信支付APIv3密钥");
        }
        if (bo.getNotifyUrl() != null) {
            updateOrInsertConfig(NOTIFY_URL_KEY, bo.getNotifyUrl(), "支付回调地址");
        }
        if (bo.getPublicKeyId() != null) {
            updateOrInsertConfig(PUBLIC_KEY_ID_KEY, bo.getPublicKeyId(), "微信支付公钥ID");
        }
        return true;
    }

    @Override
    public boolean savePrivateKey(MultipartFile file) {
        try {
            // 保存到resources/cert目录
            String certDir = getCertDir();
            File dir = new File(certDir);
            if (!dir.exists()) {
                boolean created = dir.mkdirs();
                log.info("创建目录 {}: {}", certDir, created);
            }

            String filePath = certDir + "/apiclient_key.pem";
            File destFile = new File(filePath);
            
            // 使用 InputStream 写入文件，避免 transferTo 在 Windows 上的问题
            try (InputStream is = file.getInputStream();
                 FileOutputStream fos = new FileOutputStream(destFile)) {
                byte[] buffer = new byte[1024];
                int len;
                while ((len = is.read(buffer)) > 0) {
                    fos.write(buffer, 0, len);
                }
            }

            // 保存路径到配置
            updateOrInsertConfig(PRIVATE_KEY_PATH_KEY, filePath, "商户私钥文件路径");

            log.info("私钥文件保存成功: {}", filePath);
            return true;
        } catch (IOException e) {
            log.error("保存私钥文件失败", e);
            throw new RuntimeException("保存私钥文件失败", e);
        }
    }

    @Override
    public boolean saveCert(MultipartFile file) {
        try {
            // 保存到resources/cert目录
            String certDir = getCertDir();
            File dir = new File(certDir);
            if (!dir.exists()) {
                boolean created = dir.mkdirs();
                log.info("创建目录 {}: {}", certDir, created);
            }

            String filePath = certDir + "/apiclient_cert.pem";
            File destFile = new File(filePath);
            
            // 使用 InputStream 写入文件，避免 transferTo 在 Windows 上的问题
            try (InputStream is = file.getInputStream();
                 FileOutputStream fos = new FileOutputStream(destFile)) {
                byte[] buffer = new byte[1024];
                int len;
                while ((len = is.read(buffer)) > 0) {
                    fos.write(buffer, 0, len);
                }
            }

            // 保存路径到配置
            updateOrInsertConfig(CERT_PATH_KEY, filePath, "支付证书文件路径");

            log.info("证书文件保存成功: {}", filePath);
            return true;
        } catch (IOException e) {
            log.error("保存证书文件失败", e);
            throw new RuntimeException("保存证书文件失败", e);
        }
    }

    @Override
    public boolean savePublicKey(MultipartFile file) {
        try {
            // 保存到resources/cert目录
            String certDir = getCertDir();
            File dir = new File(certDir);
            if (!dir.exists()) {
                boolean created = dir.mkdirs();
                log.info("创建目录 {}: {}", certDir, created);
            }

            String filePath = certDir + "/pub_key.pem";
            File destFile = new File(filePath);
            
            // 使用 InputStream 写入文件
            try (InputStream is = file.getInputStream();
                 FileOutputStream fos = new FileOutputStream(destFile)) {
                byte[] buffer = new byte[1024];
                int len;
                while ((len = is.read(buffer)) > 0) {
                    fos.write(buffer, 0, len);
                }
            }

            // 保存路径到配置
            updateOrInsertConfig(PUBLIC_KEY_PATH_KEY, filePath, "微信支付公钥文件路径");

            log.info("公钥文件保存成功: {}", filePath);
            return true;
        } catch (IOException e) {
            log.error("保存公钥文件失败", e);
            throw new RuntimeException("保存公钥文件失败", e);
        }
    }

    private BigDecimal getConfigValue(String key, String defaultValue) {
        List<SysConfig> list = sysConfigMapper.selectList(
            new LambdaQueryWrapper<SysConfig>().eq(SysConfig::getConfigKey, key).last("LIMIT 1"));
        String value = !list.isEmpty() ? list.get(0).getConfigValue() : defaultValue;
        return new BigDecimal(value);
    }

    private String getConfigString(String key) {
        List<SysConfig> list = sysConfigMapper.selectList(
            new LambdaQueryWrapper<SysConfig>().eq(SysConfig::getConfigKey, key).last("LIMIT 1"));
        return !list.isEmpty() ? list.get(0).getConfigValue() : "";
    }

    private void updateOrInsertConfig(String key, String value, String name) {
        List<SysConfig> list = sysConfigMapper.selectList(
            new LambdaQueryWrapper<SysConfig>().eq(SysConfig::getConfigKey, key).last("LIMIT 1"));

        if (!list.isEmpty()) {
            sysConfigMapper.update(null, new LambdaUpdateWrapper<SysConfig>()
                .eq(SysConfig::getConfigKey, key)
                .set(SysConfig::getConfigValue, value));
        } else {
            SysConfig config = new SysConfig();
            config.setConfigName(name);
            config.setConfigKey(key);
            config.setConfigValue(value);
            config.setConfigType("N");
            sysConfigMapper.insert(config);
        }
    }
}
